linux-sunxi.lists.linux.dev archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 00/41] drm: Analog TV Improvements
@ 2022-08-29 13:11 Maxime Ripard
  2022-08-29 13:11 ` [PATCH v2 01/41] drm/tests: Order Kunit tests in Makefile Maxime Ripard
                   ` (41 more replies)
  0 siblings, 42 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-08-29 13:11 UTC (permalink / raw)
  To: Maxime Ripard, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec,
	Samuel Holland, Karol Herbst, Noralf Trønnes, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Maxime Ripard, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

Hi,

Here's a series aiming at improving the command line named modes support,
and more importantly how we deal with all the analog TV variants.

The named modes support were initially introduced to allow to specify the
analog TV mode to be used.

However, this was causing multiple issues:

  * The mode name parsed on the command line was passed directly to the
    driver, which had to figure out which mode it was suppose to match;

  * Figuring that out wasn't really easy, since the video= argument or what
    the userspace might not even have a name in the first place, but
    instead could have passed a mode with the same timings;

  * The fallback to matching on the timings was mostly working as long as
    we were supporting one 525 lines (most likely NSTC) and one 625 lines
    (PAL), but couldn't differentiate between two modes with the same
    timings (NTSC vs PAL-M vs NSTC-J for example);

  * There was also some overlap with the tv mode property registered by
    drm_mode_create_tv_properties(), but named modes weren't interacting
    with that property at all.

  * Even though that property was generic, its possible values were
    specific to each drivers, which made some generic support difficult.

Thus, I chose to tackle in multiple steps:

  * A new TV norm property was introduced, with generic values, each driver
    reporting through a bitmask what standard it supports to the userspace;

  * This option was added to the command line parsing code to be able to
    specify it on the kernel command line, and new atomic_check and reset
    helpers were created to integrate properly into atomic KMS;

  * The named mode parsing code is now creating a proper display mode for
    the given named mode, and the TV standard will thus be part of the
    connector state;

  * Two drivers were converted and tested for now (vc4 and sun4i), with
    some backward compatibility code to translate the old TV mode to the
    new TV mode;

Unit tests were created along the way.

One can switch from NTSC to PAL now using (on vc4)

modetest -M vc4  -s 53:720x480i -w 53:'tv norm':0

modetest -M vc4 -s 53:720x480i -w 53:'tv norm':4

Let me know what you think,
Maxime

Changes from v1 (https://lore.kernel.org/dri-devel/20220728-rpi-analog-tv-properties-v1-0-3d53ae722097@cerno.tech/):
  - Kept the older TV mode property as legacy so we can keep the old drivers functional
  - Renamed the tv_norm property to tv_mode
  - Added a function to create PAL and NTSC compatible display modes
  - Added some helpers to instantiate a mock DRM device in Kunit
  - More Kunit tests
  - Removed the HD analog TV modes
  - Renamed some of the tests
  - Renamed some of the named modes
  - Fixed typos in commit logs
  - Added the various tags

Cc: Geert Uytterhoeven <geert@linux-m68k.org>
Cc: Mateusz Kwiatkowski <kfyatek+publicgit@gmail.com>
Cc: "Noralf Trønnes" <noralf@tronnes.org>
Cc: Dave Stevenson <dave.stevenson@raspberrypi.com>
Cc: Dom Cobley <dom@raspberrypi.com>
Cc: Phil Elwell <phil@raspberrypi.com>
Cc: <dri-devel@lists.freedesktop.org>

---
Geert Uytterhoeven (1):
      drm/modes: parse_cmdline: Add support for named modes containing dashes

Mateusz Kwiatkowski (5):
      drm/vc4: vec: Refactor VEC TV mode setting
      drm/vc4: vec: Remove redundant atomic_mode_set
      drm/vc4: vec: Fix timings for VEC modes
      drm/vc4: vec: Fix definition of PAL-M mode
      drm/vc4: vec: Add support for more analog TV standards

Maxime Ripard (35):
      drm/tests: Order Kunit tests in Makefile
      drm/tests: Add Kunit Helpers
      drm/atomic-helper: Rename drm_atomic_helper_connector_tv_reset to avoid ambiguity
      drm/connector: Rename subconnector state variable
      drm/atomic: Add TV subconnector property to get/set_property
      drm/connector: Rename legacy TV property
      drm/connector: Only register TV mode property if present
      drm/connector: Rename drm_mode_create_tv_properties
      drm/connector: Add TV standard property
      drm/modes: Add a function to generate analog display modes
      drm/modes: Only consider bpp and refresh before options
      drm/client: Add some tests for drm_connector_pick_cmdline_mode()
      drm/modes: Move named modes parsing to a separate function
      drm/modes: Switch to named mode descriptors
      drm/modes: Fill drm_cmdline mode from named modes
      drm/connector: Add pixel clock to cmdline mode
      drm/connector: Add a function to lookup a TV mode by its name
      drm/modes: Introduce the tv_mode property as a command-line option
      drm/modes: Properly generate a drm_display_mode from a named mode
      drm/modes: Introduce more named modes
      drm/atomic-helper: Add a TV properties reset helper
      drm/atomic-helper: Add an analog TV atomic_check implementation
      drm/vc4: vec: Remove empty mode_fixup
      drm/vc4: vec: Convert to atomic helpers
      drm/vc4: vec: Switch for common modes
      drm/vc4: vec: Use TV Reset implementation
      drm/vc4: vec: Convert to the new TV mode property
      drm/sun4i: tv: Remove unused mode_valid
      drm/sun4i: tv: Convert to atomic hooks
      drm/sun4i: tv: Merge mode_set into atomic_enable
      drm/sun4i: tv: Remove useless function
      drm/sun4i: tv: Remove useless destroy function
      drm/sun4i: tv: Rename error label
      drm/sun4i: tv: Add missing reset assertion
      drm/sun4i: tv: Convert to the new TV mode property

 drivers/gpu/drm/drm_atomic_state_helper.c       | 115 ++++-
 drivers/gpu/drm/drm_atomic_uapi.c               |   8 +
 drivers/gpu/drm/drm_client_modeset.c            |   4 +
 drivers/gpu/drm/drm_connector.c                 | 119 ++++-
 drivers/gpu/drm/drm_modes.c                     | 638 +++++++++++++++++++++++-
 drivers/gpu/drm/gud/gud_connector.c             |   8 +-
 drivers/gpu/drm/i2c/ch7006_drv.c                |   6 +-
 drivers/gpu/drm/i915/display/intel_tv.c         |   2 +-
 drivers/gpu/drm/nouveau/dispnv04/tvnv17.c       |   6 +-
 drivers/gpu/drm/sun4i/sun4i_tv.c                | 198 +++-----
 drivers/gpu/drm/tests/Makefile                  |  16 +-
 drivers/gpu/drm/tests/drm_client_modeset_test.c | 239 +++++++++
 drivers/gpu/drm/tests/drm_cmdline_parser_test.c | 216 ++++++++
 drivers/gpu/drm/tests/drm_kunit_helpers.c       |  54 ++
 drivers/gpu/drm/tests/drm_kunit_helpers.h       |   9 +
 drivers/gpu/drm/tests/drm_modes_test.c          | 131 +++++
 drivers/gpu/drm/vc4/vc4_hdmi.c                  |   2 +-
 drivers/gpu/drm/vc4/vc4_vec.c                   | 422 ++++++++++------
 include/drm/drm_atomic_state_helper.h           |   4 +
 include/drm/drm_connector.h                     | 165 +++++-
 include/drm/drm_mode_config.h                   |  12 +-
 include/drm/drm_modes.h                         |  17 +
 22 files changed, 2057 insertions(+), 334 deletions(-)
---
base-commit: 8869fa666a9e6782c3c896c1fa57d65adca23249
change-id: 20220728-rpi-analog-tv-properties-0914dfcee460

Best regards,
-- 
Maxime Ripard <maxime@cerno.tech>

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

* [PATCH v2 01/41] drm/tests: Order Kunit tests in Makefile
  2022-08-29 13:11 [PATCH v2 00/41] drm: Analog TV Improvements Maxime Ripard
@ 2022-08-29 13:11 ` Maxime Ripard
  2022-08-29 18:46   ` Noralf Trønnes
  2022-08-29 13:11 ` [PATCH v2 02/41] drm/tests: Add Kunit Helpers Maxime Ripard
                   ` (40 subsequent siblings)
  41 siblings, 1 reply; 128+ messages in thread
From: Maxime Ripard @ 2022-08-29 13:11 UTC (permalink / raw)
  To: Maxime Ripard, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec,
	Samuel Holland, Karol Herbst, Noralf Trønnes, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Maxime Ripard, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

Since we've recently added a ton of tests, the list starts to be a bit
of a mess and creates unneeded conflicts.

Let's order it alphabetically.

Signed-off-by: Maxime Ripard <maxime@cerno.tech>

diff --git a/drivers/gpu/drm/tests/Makefile b/drivers/gpu/drm/tests/Makefile
index 91b70f7d2769..2d9f49b62ecb 100644
--- a/drivers/gpu/drm/tests/Makefile
+++ b/drivers/gpu/drm/tests/Makefile
@@ -1,5 +1,13 @@
 # SPDX-License-Identifier: GPL-2.0
 
-obj-$(CONFIG_DRM_KUNIT_TEST) += drm_format_helper_test.o drm_damage_helper_test.o \
-	drm_cmdline_parser_test.o drm_rect_test.o drm_format_test.o drm_plane_helper_test.o \
-	drm_dp_mst_helper_test.o drm_framebuffer_test.o drm_buddy_test.o drm_mm_test.o
+obj-$(CONFIG_DRM_KUNIT_TEST) += \
+	drm_buddy_test.o \
+	drm_cmdline_parser_test.o \
+	drm_damage_helper_test.o \
+	drm_dp_mst_helper_test.o \
+	drm_format_helper_test.o \
+	drm_format_test.o \
+	drm_framebuffer_test.o \
+	drm_mm_test.o \
+	drm_plane_helper_test.o \
+	drm_rect_test.o

-- 
b4 0.10.0-dev-65ba7

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

* [PATCH v2 02/41] drm/tests: Add Kunit Helpers
  2022-08-29 13:11 [PATCH v2 00/41] drm: Analog TV Improvements Maxime Ripard
  2022-08-29 13:11 ` [PATCH v2 01/41] drm/tests: Order Kunit tests in Makefile Maxime Ripard
@ 2022-08-29 13:11 ` Maxime Ripard
  2022-08-29 13:11 ` [PATCH v2 03/41] drm/atomic-helper: Rename drm_atomic_helper_connector_tv_reset to avoid ambiguity Maxime Ripard
                   ` (39 subsequent siblings)
  41 siblings, 0 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-08-29 13:11 UTC (permalink / raw)
  To: Maxime Ripard, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec,
	Samuel Holland, Karol Herbst, Noralf Trønnes, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Maxime Ripard, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

As the number of kunit tests in KMS grows further, we start to have
multiple test suites that, for example, need to register a mock DRM
driver to interact with the KMS function they are supposed to test.

Let's add a file meant to provide those kind of helpers to avoid
duplication.

Signed-off-by: Maxime Ripard <maxime@cerno.tech>

diff --git a/drivers/gpu/drm/tests/Makefile b/drivers/gpu/drm/tests/Makefile
index 2d9f49b62ecb..b29ef1085cad 100644
--- a/drivers/gpu/drm/tests/Makefile
+++ b/drivers/gpu/drm/tests/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_DRM_KUNIT_TEST) += \
 	drm_format_helper_test.o \
 	drm_format_test.o \
 	drm_framebuffer_test.o \
+	drm_kunit_helpers.o \
 	drm_mm_test.o \
 	drm_plane_helper_test.o \
 	drm_rect_test.o
diff --git a/drivers/gpu/drm/tests/drm_kunit_helpers.c b/drivers/gpu/drm/tests/drm_kunit_helpers.c
new file mode 100644
index 000000000000..7ebd620481c1
--- /dev/null
+++ b/drivers/gpu/drm/tests/drm_kunit_helpers.c
@@ -0,0 +1,54 @@
+#include <drm/drm_drv.h>
+#include <drm/drm_managed.h>
+
+#include <linux/device.h>
+
+static const struct drm_mode_config_funcs drm_mode_config_funcs = {
+};
+
+static const struct drm_driver drm_mode_driver = {
+};
+
+static void drm_kunit_free_device(struct drm_device *drm, void *ptr)
+{
+	struct device *dev = ptr;
+
+	root_device_unregister(dev);
+}
+
+struct drm_device *drm_kunit_device_init(const char *name)
+{
+	struct drm_device *drm;
+	struct device *dev;
+	int ret;
+
+	dev = root_device_register(name);
+	if (IS_ERR(dev))
+		return ERR_CAST(dev);
+
+	drm = drm_dev_alloc(&drm_mode_driver, dev);
+	if (IS_ERR(drm)) {
+		root_device_unregister(dev);
+		return ERR_CAST(drm);
+	}
+	drm->mode_config.funcs = &drm_mode_config_funcs;
+
+	ret = drmm_add_action_or_reset(drm, drm_kunit_free_device, dev);
+	if (ret)
+		goto err_put_device;
+
+	ret = drmm_mode_config_init(drm);
+	if (ret)
+		return ERR_PTR(ret);
+
+	return drm;
+
+err_put_device:
+	drm_dev_put(drm);
+	return ERR_PTR(ret);
+}
+
+void drm_kunit_device_exit(struct drm_device *drm)
+{
+	drm_dev_put(drm);
+}
diff --git a/drivers/gpu/drm/tests/drm_kunit_helpers.h b/drivers/gpu/drm/tests/drm_kunit_helpers.h
new file mode 100644
index 000000000000..5015a327a8c1
--- /dev/null
+++ b/drivers/gpu/drm/tests/drm_kunit_helpers.h
@@ -0,0 +1,9 @@
+#ifndef DRM_KUNIT_HELPERS_H_
+#define DRM_KUNIT_HELPERS_H_
+
+struct drm_device;
+
+struct drm_device *drm_kunit_device_init(const char *name);
+void drm_kunit_device_exit(struct drm_device *drm);
+
+#endif // DRM_KUNIT_HELPERS_H_

-- 
b4 0.10.0-dev-65ba7

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

* [PATCH v2 03/41] drm/atomic-helper: Rename drm_atomic_helper_connector_tv_reset to avoid ambiguity
  2022-08-29 13:11 [PATCH v2 00/41] drm: Analog TV Improvements Maxime Ripard
  2022-08-29 13:11 ` [PATCH v2 01/41] drm/tests: Order Kunit tests in Makefile Maxime Ripard
  2022-08-29 13:11 ` [PATCH v2 02/41] drm/tests: Add Kunit Helpers Maxime Ripard
@ 2022-08-29 13:11 ` Maxime Ripard
  2022-08-29 13:11 ` [PATCH v2 04/41] drm/connector: Rename subconnector state variable Maxime Ripard
                   ` (38 subsequent siblings)
  41 siblings, 0 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-08-29 13:11 UTC (permalink / raw)
  To: Maxime Ripard, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec,
	Samuel Holland, Karol Herbst, Noralf Trønnes, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Maxime Ripard, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

We currently have two sets of TV properties.

The first one is there to deal with analog TV properties, creating
properties such as the TV mode, subconnectors, saturation, hue and so on.
It's created by calling the drm_mode_create_tv_properties() function.

The second one is there to deal with properties that might be useful on a
TV, creating the overscan margins for example. It's created by calling the
drm_mode_create_tv_margin_properties().

However, we also have a drm_atomic_helper_connector_tv_reset() function
that will reset the TV margin properties to their default values, and thus
is supposed to be called for the latter set. This creates an ambiguity due
to the inconsistent naming.

We can thus rename the drm_atomic_helper_connector_tv_reset() function to
drm_atomic_helper_connector_tv_margins_reset() to remove that ambiguity
and hopefully make it more obvious.

Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Reviewed-by: Noralf Trønnes <noralf@tronnes.org>

diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c
index bf31b9d92094..dfb57217253b 100644
--- a/drivers/gpu/drm/drm_atomic_state_helper.c
+++ b/drivers/gpu/drm/drm_atomic_state_helper.c
@@ -464,12 +464,12 @@ 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
+ * drm_atomic_helper_connector_tv_margins_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)
+void drm_atomic_helper_connector_tv_margins_reset(struct drm_connector *connector)
 {
 	struct drm_cmdline_mode *cmdline = &connector->cmdline_mode;
 	struct drm_connector_state *state = connector->state;
@@ -479,7 +479,7 @@ void drm_atomic_helper_connector_tv_reset(struct drm_connector *connector)
 	state->tv.margins.top = cmdline->tv_margins.top;
 	state->tv.margins.bottom = cmdline->tv_margins.bottom;
 }
-EXPORT_SYMBOL(drm_atomic_helper_connector_tv_reset);
+EXPORT_SYMBOL(drm_atomic_helper_connector_tv_margins_reset);
 
 /**
  * __drm_atomic_helper_connector_duplicate_state - copy atomic connector state
diff --git a/drivers/gpu/drm/gud/gud_connector.c b/drivers/gpu/drm/gud/gud_connector.c
index d0addd478815..fa636206f232 100644
--- a/drivers/gpu/drm/gud/gud_connector.c
+++ b/drivers/gpu/drm/gud/gud_connector.c
@@ -355,7 +355,7 @@ static void gud_connector_reset(struct drm_connector *connector)
 	drm_atomic_helper_connector_reset(connector);
 	connector->state->tv = gconn->initial_tv_state;
 	/* Set margins from command line */
-	drm_atomic_helper_connector_tv_reset(connector);
+	drm_atomic_helper_connector_tv_margins_reset(connector);
 	if (gconn->initial_brightness >= 0)
 		connector->state->tv.brightness = gconn->initial_brightness;
 }
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index 84e5a91c2ea7..6877add8e1fa 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -396,7 +396,7 @@ static void vc4_hdmi_connector_reset(struct drm_connector *connector)
 	new_state->base.max_bpc = 8;
 	new_state->base.max_requested_bpc = 8;
 	new_state->output_format = VC4_HDMI_OUTPUT_RGB;
-	drm_atomic_helper_connector_tv_reset(connector);
+	drm_atomic_helper_connector_tv_margins_reset(connector);
 }
 
 static struct drm_connector_state *
diff --git a/include/drm/drm_atomic_state_helper.h b/include/drm/drm_atomic_state_helper.h
index 3f8f1d627f7c..192766656b88 100644
--- a/include/drm/drm_atomic_state_helper.h
+++ b/include/drm/drm_atomic_state_helper.h
@@ -70,7 +70,7 @@ void __drm_atomic_helper_connector_state_reset(struct drm_connector_state *conn_
 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_tv_margins_reset(struct drm_connector *connector);
 void
 __drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector,
 					   struct drm_connector_state *state);
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index 248206bbd975..23112f0c11cf 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -692,7 +692,7 @@ struct drm_connector_tv_margins {
 
 /**
  * struct drm_tv_connector_state - TV connector related states
- * @subconnector: selected subconnector
+ * @select_subconnector: selected subconnector
  * @margins: TV margins
  * @mode: TV mode
  * @brightness: brightness in percent

-- 
b4 0.10.0-dev-65ba7

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

* [PATCH v2 04/41] drm/connector: Rename subconnector state variable
  2022-08-29 13:11 [PATCH v2 00/41] drm: Analog TV Improvements Maxime Ripard
                   ` (2 preceding siblings ...)
  2022-08-29 13:11 ` [PATCH v2 03/41] drm/atomic-helper: Rename drm_atomic_helper_connector_tv_reset to avoid ambiguity Maxime Ripard
@ 2022-08-29 13:11 ` Maxime Ripard
  2022-08-29 13:11 ` [PATCH v2 05/41] drm/atomic: Add TV subconnector property to get/set_property Maxime Ripard
                   ` (37 subsequent siblings)
  41 siblings, 0 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-08-29 13:11 UTC (permalink / raw)
  To: Maxime Ripard, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec,
	Samuel Holland, Karol Herbst, Noralf Trønnes, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Maxime Ripard, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

There is two TV subconnector related properties registered by
drm_mode_create_tv_properties(): subconnector and select subconnector.

While the select subconnector property is stored in the kernel by the
drm_tv_connector_state structure, the subconnector property isn't stored
anywhere.

Worse, the select subconnector property is stored in a field called
subconnector, creating some ambiguity about which property content we're
accessing.

Let's rename that field to one called select_subconnector to make it move
obvious what it's about.

Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Reviewed-by: Noralf Trønnes <noralf@tronnes.org>

diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c
index 79730fa1dd8e..c74c78a28171 100644
--- a/drivers/gpu/drm/drm_atomic_uapi.c
+++ b/drivers/gpu/drm/drm_atomic_uapi.c
@@ -687,7 +687,7 @@ static int drm_atomic_connector_set_property(struct drm_connector *connector,
 		 */
 		return -EINVAL;
 	} else if (property == config->tv_select_subconnector_property) {
-		state->tv.subconnector = val;
+		state->tv.select_subconnector = val;
 	} else if (property == config->tv_left_margin_property) {
 		state->tv.margins.left = val;
 	} else if (property == config->tv_right_margin_property) {
@@ -795,7 +795,7 @@ drm_atomic_connector_get_property(struct drm_connector *connector,
 		else
 			*val = connector->dpms;
 	} else if (property == config->tv_select_subconnector_property) {
-		*val = state->tv.subconnector;
+		*val = state->tv.select_subconnector;
 	} else if (property == config->tv_left_margin_property) {
 		*val = state->tv.margins.left;
 	} else if (property == config->tv_right_margin_property) {
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index 23112f0c11cf..60b5662dec7c 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -703,7 +703,7 @@ struct drm_connector_tv_margins {
  * @hue: hue in percent
  */
 struct drm_tv_connector_state {
-	enum drm_mode_subconnector subconnector;
+	enum drm_mode_subconnector select_subconnector;
 	struct drm_connector_tv_margins margins;
 	unsigned int mode;
 	unsigned int brightness;

-- 
b4 0.10.0-dev-65ba7

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

* [PATCH v2 05/41] drm/atomic: Add TV subconnector property to get/set_property
  2022-08-29 13:11 [PATCH v2 00/41] drm: Analog TV Improvements Maxime Ripard
                   ` (3 preceding siblings ...)
  2022-08-29 13:11 ` [PATCH v2 04/41] drm/connector: Rename subconnector state variable Maxime Ripard
@ 2022-08-29 13:11 ` Maxime Ripard
  2022-08-29 13:11 ` [PATCH v2 06/41] drm/connector: Rename legacy TV property Maxime Ripard
                   ` (36 subsequent siblings)
  41 siblings, 0 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-08-29 13:11 UTC (permalink / raw)
  To: Maxime Ripard, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec,
	Samuel Holland, Karol Herbst, Noralf Trønnes, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Maxime Ripard, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

The subconnector property was created by drm_mode_create_tv_properties(),
but wasn't exposed to the userspace through the generic
atomic_get/set_property implementation, and wasn't stored in any generic
state structure.

Let's solve this.

Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Reviewed-by: Noralf Trønnes <noralf@tronnes.org>

diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c
index c74c78a28171..c06d0639d552 100644
--- a/drivers/gpu/drm/drm_atomic_uapi.c
+++ b/drivers/gpu/drm/drm_atomic_uapi.c
@@ -688,6 +688,8 @@ static int drm_atomic_connector_set_property(struct drm_connector *connector,
 		return -EINVAL;
 	} else if (property == config->tv_select_subconnector_property) {
 		state->tv.select_subconnector = val;
+	} else if (property == config->tv_subconnector_property) {
+		state->tv.subconnector = val;
 	} else if (property == config->tv_left_margin_property) {
 		state->tv.margins.left = val;
 	} else if (property == config->tv_right_margin_property) {
@@ -796,6 +798,8 @@ drm_atomic_connector_get_property(struct drm_connector *connector,
 			*val = connector->dpms;
 	} else if (property == config->tv_select_subconnector_property) {
 		*val = state->tv.select_subconnector;
+	} else if (property == config->tv_subconnector_property) {
+		*val = state->tv.subconnector;
 	} else if (property == config->tv_left_margin_property) {
 		*val = state->tv.margins.left;
 	} else if (property == config->tv_right_margin_property) {
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index 60b5662dec7c..1d5e3cccb9e3 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -693,6 +693,7 @@ struct drm_connector_tv_margins {
 /**
  * struct drm_tv_connector_state - TV connector related states
  * @select_subconnector: selected subconnector
+ * @subconnector: detected subconnector
  * @margins: TV margins
  * @mode: TV mode
  * @brightness: brightness in percent
@@ -704,6 +705,7 @@ struct drm_connector_tv_margins {
  */
 struct drm_tv_connector_state {
 	enum drm_mode_subconnector select_subconnector;
+	enum drm_mode_subconnector subconnector;
 	struct drm_connector_tv_margins margins;
 	unsigned int mode;
 	unsigned int brightness;

-- 
b4 0.10.0-dev-65ba7

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

* [PATCH v2 06/41] drm/connector: Rename legacy TV property
  2022-08-29 13:11 [PATCH v2 00/41] drm: Analog TV Improvements Maxime Ripard
                   ` (4 preceding siblings ...)
  2022-08-29 13:11 ` [PATCH v2 05/41] drm/atomic: Add TV subconnector property to get/set_property Maxime Ripard
@ 2022-08-29 13:11 ` Maxime Ripard
  2022-08-30 19:27   ` Noralf Trønnes
  2022-08-29 13:11 ` [PATCH v2 07/41] drm/connector: Only register TV mode property if present Maxime Ripard
                   ` (35 subsequent siblings)
  41 siblings, 1 reply; 128+ messages in thread
From: Maxime Ripard @ 2022-08-29 13:11 UTC (permalink / raw)
  To: Maxime Ripard, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec,
	Samuel Holland, Karol Herbst, Noralf Trønnes, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Maxime Ripard, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

The current tv_mode has driver-specific values that don't allow to
easily share code using it, either at the userspace or kernel level.

Since we're going to introduce a new, generic, property that fit the
same purpose, let's rename this one to legacy_tv_mode to make it
obvious we should move away from it.

Signed-off-by: Maxime Ripard <maxime@cerno.tech>

diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c
index c06d0639d552..7f2b9a07fbdf 100644
--- a/drivers/gpu/drm/drm_atomic_uapi.c
+++ b/drivers/gpu/drm/drm_atomic_uapi.c
@@ -698,8 +698,8 @@ static int drm_atomic_connector_set_property(struct drm_connector *connector,
 		state->tv.margins.top = val;
 	} else if (property == config->tv_bottom_margin_property) {
 		state->tv.margins.bottom = val;
-	} else if (property == config->tv_mode_property) {
-		state->tv.mode = val;
+	} else if (property == config->legacy_tv_mode_property) {
+		state->tv.legacy_mode = val;
 	} else if (property == config->tv_brightness_property) {
 		state->tv.brightness = val;
 	} else if (property == config->tv_contrast_property) {
@@ -808,8 +808,8 @@ drm_atomic_connector_get_property(struct drm_connector *connector,
 		*val = state->tv.margins.top;
 	} else if (property == config->tv_bottom_margin_property) {
 		*val = state->tv.margins.bottom;
-	} else if (property == config->tv_mode_property) {
-		*val = state->tv.mode;
+	} else if (property == config->legacy_tv_mode_property) {
+		*val = state->tv.legacy_mode;
 	} else if (property == config->tv_brightness_property) {
 		*val = state->tv.brightness;
 	} else if (property == config->tv_contrast_property) {
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index e3142c8142b3..ede6025638d7 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -1686,14 +1686,14 @@ int drm_mode_create_tv_properties(struct drm_device *dev,
 	if (drm_mode_create_tv_margin_properties(dev))
 		goto nomem;
 
-	dev->mode_config.tv_mode_property =
+	dev->mode_config.legacy_tv_mode_property =
 		drm_property_create(dev, DRM_MODE_PROP_ENUM,
 				    "mode", num_modes);
-	if (!dev->mode_config.tv_mode_property)
+	if (!dev->mode_config.legacy_tv_mode_property)
 		goto nomem;
 
 	for (i = 0; i < num_modes; i++)
-		drm_property_add_enum(dev->mode_config.tv_mode_property,
+		drm_property_add_enum(dev->mode_config.legacy_tv_mode_property,
 				      i, modes[i]);
 
 	dev->mode_config.tv_brightness_property =
diff --git a/drivers/gpu/drm/gud/gud_connector.c b/drivers/gpu/drm/gud/gud_connector.c
index fa636206f232..caf82e9095b4 100644
--- a/drivers/gpu/drm/gud/gud_connector.c
+++ b/drivers/gpu/drm/gud/gud_connector.c
@@ -424,7 +424,7 @@ gud_connector_property_lookup(struct drm_connector *connector, u16 prop)
 	case GUD_PROPERTY_TV_BOTTOM_MARGIN:
 		return config->tv_bottom_margin_property;
 	case GUD_PROPERTY_TV_MODE:
-		return config->tv_mode_property;
+		return config->legacy_tv_mode_property;
 	case GUD_PROPERTY_TV_BRIGHTNESS:
 		return config->tv_brightness_property;
 	case GUD_PROPERTY_TV_CONTRAST:
diff --git a/drivers/gpu/drm/i2c/ch7006_drv.c b/drivers/gpu/drm/i2c/ch7006_drv.c
index b91e48d2190d..d29b63fd6178 100644
--- a/drivers/gpu/drm/i2c/ch7006_drv.c
+++ b/drivers/gpu/drm/i2c/ch7006_drv.c
@@ -264,7 +264,7 @@ static int ch7006_encoder_create_resources(struct drm_encoder *encoder,
 				      priv->hmargin);
 	drm_object_attach_property(&connector->base, conf->tv_bottom_margin_property,
 				      priv->vmargin);
-	drm_object_attach_property(&connector->base, conf->tv_mode_property,
+	drm_object_attach_property(&connector->base, conf->legacy_tv_mode_property,
 				      priv->norm);
 	drm_object_attach_property(&connector->base, conf->tv_brightness_property,
 				      priv->brightness);
@@ -315,7 +315,7 @@ static int ch7006_encoder_set_property(struct drm_encoder *encoder,
 		ch7006_load_reg(client, state, CH7006_POV);
 		ch7006_load_reg(client, state, CH7006_VPOS);
 
-	} else if (property == conf->tv_mode_property) {
+	} else if (property == conf->legacy_tv_mode_property) {
 		if (connector->dpms != DRM_MODE_DPMS_OFF)
 			return -EINVAL;
 
diff --git a/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c b/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c
index be28e7bd7490..1a15534adc60 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c
@@ -662,7 +662,7 @@ static int nv17_tv_create_resources(struct drm_encoder *encoder,
 					conf->tv_subconnector_property,
 					tv_enc->subconnector);
 	drm_object_attach_property(&connector->base,
-					conf->tv_mode_property,
+					conf->legacy_tv_mode_property,
 					tv_enc->tv_norm);
 	drm_object_attach_property(&connector->base,
 					conf->tv_flicker_reduction_property,
@@ -722,7 +722,7 @@ static int nv17_tv_set_property(struct drm_encoder *encoder,
 		if (encoder->crtc)
 			nv17_tv_update_rescaler(encoder);
 
-	} else if (property == conf->tv_mode_property) {
+	} else if (property == conf->legacy_tv_mode_property) {
 		if (connector->dpms != DRM_MODE_DPMS_OFF)
 			return -EINVAL;
 
diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c
index 4a788c1c9058..dc33b7b9ce5e 100644
--- a/drivers/gpu/drm/vc4/vc4_vec.c
+++ b/drivers/gpu/drm/vc4/vc4_vec.c
@@ -366,7 +366,7 @@ static int vc4_vec_connector_init(struct drm_device *dev, struct vc4_vec *vec)
 	drm_connector_helper_add(connector, &vc4_vec_connector_helper_funcs);
 
 	drm_object_attach_property(&connector->base,
-				   dev->mode_config.tv_mode_property,
+				   dev->mode_config.legacy_tv_mode_property,
 				   VC4_VEC_TV_MODE_NTSC);
 	vec->tv_mode = &vc4_vec_tv_modes[VC4_VEC_TV_MODE_NTSC];
 
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index 1d5e3cccb9e3..5cfad8b6ad83 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -695,7 +695,7 @@ struct drm_connector_tv_margins {
  * @select_subconnector: selected subconnector
  * @subconnector: detected subconnector
  * @margins: TV margins
- * @mode: TV mode
+ * @legacy_mode: Legacy TV mode, driver specific value
  * @brightness: brightness in percent
  * @contrast: contrast in percent
  * @flicker_reduction: flicker reduction in percent
@@ -707,7 +707,7 @@ struct drm_tv_connector_state {
 	enum drm_mode_subconnector select_subconnector;
 	enum drm_mode_subconnector subconnector;
 	struct drm_connector_tv_margins margins;
-	unsigned int mode;
+	unsigned int legacy_mode;
 	unsigned int brightness;
 	unsigned int contrast;
 	unsigned int flicker_reduction;
diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h
index 6b5e01295348..35a827175c24 100644
--- a/include/drm/drm_mode_config.h
+++ b/include/drm/drm_mode_config.h
@@ -714,11 +714,13 @@ struct drm_mode_config {
 	 * between different TV connector types.
 	 */
 	struct drm_property *tv_select_subconnector_property;
+
 	/**
-	 * @tv_mode_property: Optional TV property to select
+	 * @legacy_tv_mode_property: Optional TV property to select
 	 * the output TV mode.
 	 */
-	struct drm_property *tv_mode_property;
+	struct drm_property *legacy_tv_mode_property;
+
 	/**
 	 * @tv_left_margin_property: Optional TV property to set the left
 	 * margin (expressed in pixels).

-- 
b4 0.10.0-dev-65ba7

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

* [PATCH v2 07/41] drm/connector: Only register TV mode property if present
  2022-08-29 13:11 [PATCH v2 00/41] drm: Analog TV Improvements Maxime Ripard
                   ` (5 preceding siblings ...)
  2022-08-29 13:11 ` [PATCH v2 06/41] drm/connector: Rename legacy TV property Maxime Ripard
@ 2022-08-29 13:11 ` Maxime Ripard
  2022-08-29 13:11 ` [PATCH v2 08/41] drm/connector: Rename drm_mode_create_tv_properties Maxime Ripard
                   ` (34 subsequent siblings)
  41 siblings, 0 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-08-29 13:11 UTC (permalink / raw)
  To: Maxime Ripard, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec,
	Samuel Holland, Karol Herbst, Noralf Trønnes, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Maxime Ripard, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

The drm_create_tv_properties() will create the TV mode property
unconditionally.

However, since we'll gradually phase it out, let's register it only if we
have a list passed as an argument. This will make the transition easier.

Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Acked-by: Noralf Trønnes <noralf@tronnes.org>

diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index ede6025638d7..17a5913cefe3 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -1686,15 +1686,18 @@ int drm_mode_create_tv_properties(struct drm_device *dev,
 	if (drm_mode_create_tv_margin_properties(dev))
 		goto nomem;
 
-	dev->mode_config.legacy_tv_mode_property =
-		drm_property_create(dev, DRM_MODE_PROP_ENUM,
-				    "mode", num_modes);
-	if (!dev->mode_config.legacy_tv_mode_property)
-		goto nomem;
 
-	for (i = 0; i < num_modes; i++)
-		drm_property_add_enum(dev->mode_config.legacy_tv_mode_property,
-				      i, modes[i]);
+	if (num_modes) {
+		dev->mode_config.legacy_tv_mode_property =
+			drm_property_create(dev, DRM_MODE_PROP_ENUM,
+					    "mode", num_modes);
+		if (!dev->mode_config.legacy_tv_mode_property)
+			goto nomem;
+
+		for (i = 0; i < num_modes; i++)
+			drm_property_add_enum(dev->mode_config.legacy_tv_mode_property,
+					      i, modes[i]);
+	}
 
 	dev->mode_config.tv_brightness_property =
 		drm_property_create_range(dev, 0, "brightness", 0, 100);

-- 
b4 0.10.0-dev-65ba7

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

* [PATCH v2 08/41] drm/connector: Rename drm_mode_create_tv_properties
  2022-08-29 13:11 [PATCH v2 00/41] drm: Analog TV Improvements Maxime Ripard
                   ` (6 preceding siblings ...)
  2022-08-29 13:11 ` [PATCH v2 07/41] drm/connector: Only register TV mode property if present Maxime Ripard
@ 2022-08-29 13:11 ` Maxime Ripard
  2022-08-29 13:11 ` [PATCH v2 09/41] drm/connector: Add TV standard property Maxime Ripard
                   ` (33 subsequent siblings)
  41 siblings, 0 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-08-29 13:11 UTC (permalink / raw)
  To: Maxime Ripard, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec,
	Samuel Holland, Karol Herbst, Noralf Trønnes, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Maxime Ripard, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

drm_mode_create_tv_properties(), among other things, will create the
"mode" property that stores the analog TV mode that connector is
supposed to output.

However, that property is getting deprecated, so let's rename that
function to mention it's deprecated. We'll introduce a new variant of
that function creating the property superseeding it in a later patch.

Signed-off-by: Maxime Ripard <maxime@cerno.tech>

diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 17a5913cefe3..4e4fbc9e0049 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -1600,7 +1600,7 @@ EXPORT_SYMBOL(drm_connector_attach_tv_margin_properties);
  * Called by a driver's HDMI connector initialization routine, this function
  * creates the TV margin properties for a given device. No need to call this
  * function for an SDTV connector, it's already called from
- * drm_mode_create_tv_properties().
+ * drm_mode_create_tv_properties_legacy().
  *
  * Returns:
  * 0 on success or a negative error code on failure.
@@ -1635,7 +1635,7 @@ int drm_mode_create_tv_margin_properties(struct drm_device *dev)
 EXPORT_SYMBOL(drm_mode_create_tv_margin_properties);
 
 /**
- * drm_mode_create_tv_properties - create TV specific connector properties
+ * drm_mode_create_tv_properties_legacy - create TV specific connector properties
  * @dev: DRM device
  * @num_modes: number of different TV formats (modes) supported
  * @modes: array of pointers to strings containing name of each format
@@ -1648,9 +1648,9 @@ EXPORT_SYMBOL(drm_mode_create_tv_margin_properties);
  * Returns:
  * 0 on success or a negative error code on failure.
  */
-int drm_mode_create_tv_properties(struct drm_device *dev,
-				  unsigned int num_modes,
-				  const char * const modes[])
+int drm_mode_create_tv_properties_legacy(struct drm_device *dev,
+					 unsigned int num_modes,
+					 const char * const modes[])
 {
 	struct drm_property *tv_selector;
 	struct drm_property *tv_subconnector;
@@ -1733,7 +1733,7 @@ int drm_mode_create_tv_properties(struct drm_device *dev,
 nomem:
 	return -ENOMEM;
 }
-EXPORT_SYMBOL(drm_mode_create_tv_properties);
+EXPORT_SYMBOL(drm_mode_create_tv_properties_legacy);
 
 /**
  * drm_mode_create_scaling_mode_property - create scaling mode property
diff --git a/drivers/gpu/drm/gud/gud_connector.c b/drivers/gpu/drm/gud/gud_connector.c
index caf82e9095b4..4026eb0132bd 100644
--- a/drivers/gpu/drm/gud/gud_connector.c
+++ b/drivers/gpu/drm/gud/gud_connector.c
@@ -400,7 +400,7 @@ static int gud_connector_add_tv_mode(struct gud_device *gdrm, struct drm_connect
 	for (i = 0; i < num_modes; i++)
 		modes[i] = &buf[i * GUD_CONNECTOR_TV_MODE_NAME_LEN];
 
-	ret = drm_mode_create_tv_properties(connector->dev, num_modes, modes);
+	ret = drm_mode_create_tv_properties_legacy(connector->dev, num_modes, modes);
 free:
 	kfree(buf);
 	if (ret < 0)
@@ -539,7 +539,7 @@ static int gud_connector_add_properties(struct gud_device *gdrm, struct gud_conn
 			fallthrough;
 		case GUD_PROPERTY_TV_HUE:
 			/* This is a no-op if already added. */
-			ret = drm_mode_create_tv_properties(drm, 0, NULL);
+			ret = drm_mode_create_tv_properties_legacy(drm, 0, NULL);
 			if (ret)
 				goto out;
 			break;
diff --git a/drivers/gpu/drm/i2c/ch7006_drv.c b/drivers/gpu/drm/i2c/ch7006_drv.c
index d29b63fd6178..506f6f932518 100644
--- a/drivers/gpu/drm/i2c/ch7006_drv.c
+++ b/drivers/gpu/drm/i2c/ch7006_drv.c
@@ -250,7 +250,7 @@ static int ch7006_encoder_create_resources(struct drm_encoder *encoder,
 	struct drm_device *dev = encoder->dev;
 	struct drm_mode_config *conf = &dev->mode_config;
 
-	drm_mode_create_tv_properties(dev, NUM_TV_NORMS, ch7006_tv_norm_names);
+	drm_mode_create_tv_properties_legacy(dev, NUM_TV_NORMS, ch7006_tv_norm_names);
 
 	priv->scale_property = drm_property_create_range(dev, 0, "scale", 0, 2);
 	if (!priv->scale_property)
diff --git a/drivers/gpu/drm/i915/display/intel_tv.c b/drivers/gpu/drm/i915/display/intel_tv.c
index 9379f3463344..7fd2c6f01ad6 100644
--- a/drivers/gpu/drm/i915/display/intel_tv.c
+++ b/drivers/gpu/drm/i915/display/intel_tv.c
@@ -1984,7 +1984,7 @@ intel_tv_init(struct drm_i915_private *dev_priv)
 
 		tv_format_names[i] = tv_modes[i].name;
 	}
-	drm_mode_create_tv_properties(dev, i, tv_format_names);
+	drm_mode_create_tv_properties_legacy(dev, i, tv_format_names);
 
 	drm_object_attach_property(&connector->base, dev->mode_config.tv_mode_property,
 				   state->tv.mode);
diff --git a/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c b/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c
index 1a15534adc60..e5480dab55e3 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c
@@ -653,7 +653,7 @@ static int nv17_tv_create_resources(struct drm_encoder *encoder,
 			tv_enc->tv_norm = i;
 	}
 
-	drm_mode_create_tv_properties(dev, num_tv_norms, nv17_tv_norm_names);
+	drm_mode_create_tv_properties_legacy(dev, num_tv_norms, nv17_tv_norm_names);
 
 	drm_object_attach_property(&connector->base,
 					conf->tv_select_subconnector_property,
diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c
index dc33b7b9ce5e..d5140fe0be4f 100644
--- a/drivers/gpu/drm/vc4/vc4_vec.c
+++ b/drivers/gpu/drm/vc4/vc4_vec.c
@@ -573,8 +573,9 @@ static int vc4_vec_bind(struct device *dev, struct device *master, void *data)
 	struct vc4_vec *vec;
 	int ret;
 
-	ret = drm_mode_create_tv_properties(drm, ARRAY_SIZE(tv_mode_names),
-					    tv_mode_names);
+	ret = drm_mode_create_tv_properties_legacy(drm,
+						   ARRAY_SIZE(tv_mode_names),
+						   tv_mode_names);
 	if (ret)
 		return ret;
 
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index 5cfad8b6ad83..d566b4a4709c 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -1799,9 +1799,9 @@ int drm_mode_create_dvi_i_properties(struct drm_device *dev);
 void drm_connector_attach_dp_subconnector_property(struct drm_connector *connector);
 
 int drm_mode_create_tv_margin_properties(struct drm_device *dev);
-int drm_mode_create_tv_properties(struct drm_device *dev,
-				  unsigned int num_modes,
-				  const char * const modes[]);
+int drm_mode_create_tv_properties_legacy(struct drm_device *dev,
+					 unsigned int num_modes,
+					 const char * const modes[]);
 void drm_connector_attach_tv_margin_properties(struct drm_connector *conn);
 int drm_mode_create_scaling_mode_property(struct drm_device *dev);
 int drm_connector_attach_content_type_property(struct drm_connector *dev);

-- 
b4 0.10.0-dev-65ba7

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

* [PATCH v2 09/41] drm/connector: Add TV standard property
  2022-08-29 13:11 [PATCH v2 00/41] drm: Analog TV Improvements Maxime Ripard
                   ` (7 preceding siblings ...)
  2022-08-29 13:11 ` [PATCH v2 08/41] drm/connector: Rename drm_mode_create_tv_properties Maxime Ripard
@ 2022-08-29 13:11 ` Maxime Ripard
  2022-09-01 22:00   ` Mateusz Kwiatkowski
  2022-09-05 10:18   ` Noralf Trønnes
  2022-08-29 13:11 ` [PATCH v2 10/41] drm/modes: Add a function to generate analog display modes Maxime Ripard
                   ` (32 subsequent siblings)
  41 siblings, 2 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-08-29 13:11 UTC (permalink / raw)
  To: Maxime Ripard, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec,
	Samuel Holland, Karol Herbst, Noralf Trønnes, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Maxime Ripard, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

The TV mode property has been around for a while now to select and get the
current TV mode output on an analog TV connector.

Despite that property name being generic, its content isn't and has been
driver-specific which makes it hard to build any generic behaviour on top
of it, both in kernel and user-space.

Let's create a new bitmask tv norm property, that can contain any of the
analog TV standards currently supported by kernel drivers. Each driver can
then pass in a bitmask of the modes it supports.

We'll then be able to phase out the older tv mode property.

Signed-off-by: Maxime Ripard <maxime@cerno.tech>

diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c
index 7f2b9a07fbdf..d867e7f9f2cd 100644
--- a/drivers/gpu/drm/drm_atomic_uapi.c
+++ b/drivers/gpu/drm/drm_atomic_uapi.c
@@ -700,6 +700,8 @@ static int drm_atomic_connector_set_property(struct drm_connector *connector,
 		state->tv.margins.bottom = val;
 	} else if (property == config->legacy_tv_mode_property) {
 		state->tv.legacy_mode = val;
+	} else if (property == config->tv_mode_property) {
+		state->tv.mode = val;
 	} else if (property == config->tv_brightness_property) {
 		state->tv.brightness = val;
 	} else if (property == config->tv_contrast_property) {
@@ -810,6 +812,8 @@ drm_atomic_connector_get_property(struct drm_connector *connector,
 		*val = state->tv.margins.bottom;
 	} else if (property == config->legacy_tv_mode_property) {
 		*val = state->tv.legacy_mode;
+	} else if (property == config->tv_mode_property) {
+		*val = state->tv.mode;
 	} else if (property == config->tv_brightness_property) {
 		*val = state->tv.brightness;
 	} else if (property == config->tv_contrast_property) {
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 4e4fbc9e0049..b1fcacd150e8 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -980,6 +980,29 @@ static const struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] = {
 DRM_ENUM_NAME_FN(drm_get_dvi_i_subconnector_name,
 		 drm_dvi_i_subconnector_enum_list)
 
+static const struct drm_prop_enum_list drm_tv_mode_enum_list[] = {
+	{ DRM_MODE_TV_MODE_NTSC_443, "NTSC-443" },
+	{ DRM_MODE_TV_MODE_NTSC_J, "NTSC-J" },
+	{ DRM_MODE_TV_MODE_NTSC_M, "NTSC-M" },
+	{ DRM_MODE_TV_MODE_PAL_60, "PAL-60" },
+	{ DRM_MODE_TV_MODE_PAL_B, "PAL-B" },
+	{ DRM_MODE_TV_MODE_PAL_D, "PAL-D" },
+	{ DRM_MODE_TV_MODE_PAL_G, "PAL-G" },
+	{ DRM_MODE_TV_MODE_PAL_H, "PAL-H" },
+	{ DRM_MODE_TV_MODE_PAL_I, "PAL-I" },
+	{ DRM_MODE_TV_MODE_PAL_M, "PAL-M" },
+	{ DRM_MODE_TV_MODE_PAL_N, "PAL-N" },
+	{ DRM_MODE_TV_MODE_PAL_NC, "PAL-Nc" },
+	{ DRM_MODE_TV_MODE_SECAM_60, "SECAM-60" },
+	{ DRM_MODE_TV_MODE_SECAM_B, "SECAM-B" },
+	{ DRM_MODE_TV_MODE_SECAM_D, "SECAM-D" },
+	{ DRM_MODE_TV_MODE_SECAM_G, "SECAM-G" },
+	{ DRM_MODE_TV_MODE_SECAM_K, "SECAM-K" },
+	{ DRM_MODE_TV_MODE_SECAM_K1, "SECAM-K1" },
+	{ DRM_MODE_TV_MODE_SECAM_L, "SECAM-L" },
+};
+DRM_ENUM_NAME_FN(drm_get_tv_mode_name, drm_tv_mode_enum_list)
+
 static const struct drm_prop_enum_list drm_tv_select_enum_list[] = {
 	{ DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */
 	{ DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */
@@ -1645,6 +1668,10 @@ EXPORT_SYMBOL(drm_mode_create_tv_margin_properties);
  * responsible for allocating a list of format names and passing them to
  * this routine.
  *
+ * NOTE: This functions registers the deprecated "mode" connector
+ * property to select the analog TV mode (ie, NTSC, PAL, etc.). New
+ * drivers must use drm_mode_create_tv_properties() instead.
+ *
  * Returns:
  * 0 on success or a negative error code on failure.
  */
@@ -1686,7 +1713,6 @@ int drm_mode_create_tv_properties_legacy(struct drm_device *dev,
 	if (drm_mode_create_tv_margin_properties(dev))
 		goto nomem;
 
-
 	if (num_modes) {
 		dev->mode_config.legacy_tv_mode_property =
 			drm_property_create(dev, DRM_MODE_PROP_ENUM,
@@ -1735,6 +1761,46 @@ int drm_mode_create_tv_properties_legacy(struct drm_device *dev,
 }
 EXPORT_SYMBOL(drm_mode_create_tv_properties_legacy);
 
+/**
+ * drm_mode_create_tv_properties - create TV specific connector properties
+ * @dev: DRM device
+ * @supported_tv_modes: Bitmask of TV modes supported (See DRM_MODE_TV_MODE_*)
+
+ * Called by a driver's TV initialization routine, this function creates
+ * the TV specific connector properties for a given device.  Caller is
+ * responsible for allocating a list of format names and passing them to
+ * this routine.
+ *
+ * Returns:
+ * 0 on success or a negative error code on failure.
+ */
+int drm_mode_create_tv_properties(struct drm_device *dev,
+				  unsigned int supported_tv_modes)
+{
+	struct drm_prop_enum_list tv_mode_list[DRM_MODE_TV_MODE_MAX];
+	struct drm_property *tv_mode;
+	unsigned int i, len = 0;
+
+	for (i = 0; i < DRM_MODE_TV_MODE_MAX; i++) {
+		if (!(supported_tv_modes & BIT(i)))
+			continue;
+
+		tv_mode_list[len].type = i;
+		tv_mode_list[len].name = drm_get_tv_mode_name(i);
+		len++;
+	}
+
+	tv_mode = drm_property_create_enum(dev, 0, "TV mode",
+					   tv_mode_list, len);
+	if (!tv_mode)
+		return -ENOMEM;
+
+	dev->mode_config.tv_mode_property = tv_mode;
+
+	return drm_mode_create_tv_properties_legacy(dev, 0, NULL);
+}
+EXPORT_SYMBOL(drm_mode_create_tv_properties);
+
 /**
  * drm_mode_create_scaling_mode_property - create scaling mode property
  * @dev: DRM device
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index d566b4a4709c..7d3881f35e7c 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -143,6 +143,144 @@ enum subpixel_order {
 
 };
 
+/**
+ * enum drm_connector_tv_mode - Analog TV output mode
+ *
+ * This enum is used to indicate the TV output mode used on an analog TV
+ * connector.
+ *
+ * WARNING: The values of this enum is uABI since they're exposed in the
+ * "TV mode" connector property.
+ */
+enum drm_connector_tv_mode {
+	/**
+	 * @DRM_MODE_TV_MODE_NTSC_443: Variant of
+	 * @DRM_MODE_TV_MODE_NTSC_M. Uses a color subcarrier frequency
+	 * of 4.43 MHz.
+	 */
+	DRM_MODE_TV_MODE_NTSC_443 = 0,
+
+	/**
+	 * @DRM_MODE_TV_MODE_NTSC_J: Variant of @DRM_MODE_TV_MODE_NTSC_M
+	 * used in Japan. Uses a black level equals to the blanking
+	 * level.
+	 */
+	DRM_MODE_TV_MODE_NTSC_J,
+
+	/**
+	 * @DRM_MODE_TV_MODE_NTSC_M: CCIR System M (aka 525-lines)
+	 * together with the NTSC Color Encoding.
+	 */
+	DRM_MODE_TV_MODE_NTSC_M,
+
+	/**
+	 * @DRM_MODE_TV_MODE_PAL_60: CCIR System M (aka 525-lines)
+	 * together with the PAL color encoding and color subcarrier
+	 * frequency.
+	 */
+	DRM_MODE_TV_MODE_PAL_60,
+
+	/**
+	 * @DRM_MODE_TV_MODE_PAL_B: CCIR System B together with the PAL
+	 * color system.
+	 */
+	DRM_MODE_TV_MODE_PAL_B,
+
+	/**
+	 * @DRM_MODE_TV_MODE_PAL_D: CCIR System D together with the PAL
+	 * color system.
+	 */
+	DRM_MODE_TV_MODE_PAL_D,
+
+	/**
+	 * @DRM_MODE_TV_MODE_PAL_G: CCIR System G together with the PAL
+	 * color system. Similar to @DRM_MODE_TV_MODE_PAL_B but uses a
+	 * different channel bandwidth and transmission band.
+	 */
+	DRM_MODE_TV_MODE_PAL_G,
+
+	/**
+	 * @DRM_MODE_TV_MODE_PAL_H: CCIR System H together with the PAL
+	 * color system. Similar to @DRM_MODE_TV_MODE_PAL_G but uses a
+	 * narrower lower side band.
+	 */
+	DRM_MODE_TV_MODE_PAL_H,
+
+	/**
+	 * @DRM_MODE_TV_MODE_PAL_I: CCIR System I together with the PAL
+	 * color system. Similar to @DRM_MODE_TV_MODE_PAL_B, but with a
+	 * different audio encoding.
+	 */
+	DRM_MODE_TV_MODE_PAL_I,
+
+	/**
+	 * @DRM_MODE_TV_MODE_PAL_M: CCIR System M (aka 525-lines)
+	 * together with the PAL color encoding
+	 */
+	DRM_MODE_TV_MODE_PAL_M,
+
+	/**
+	 * @DRM_MODE_TV_MODE_PAL_N: CCIR System N together with the PAL
+	 * color encoding. It uses 625 lines, but has a color subcarrier
+	 * frequency of 3.58MHz, the SECAM color space, and narrower
+	 * channels compared to most of the other PAL variants.
+	 */
+	DRM_MODE_TV_MODE_PAL_N,
+
+	/**
+	 * @DRM_MODE_TV_MODE_PAL_NC: Seems equivalent to
+	 * @DRM_MODE_TV_MODE_PAL_N.
+	 */
+	DRM_MODE_TV_MODE_PAL_NC,
+
+	/**
+	 * @DRM_MODE_TV_MODE_SECAM_60: CCIR System M (aka 525-lines)
+	 * together with the SECAM color system.
+	 */
+	DRM_MODE_TV_MODE_SECAM_60,
+
+	/**
+	 * @DRM_MODE_TV_MODE_SECAM_B: CCIR System B together with the
+	 * SECAM color system.
+	 */
+	DRM_MODE_TV_MODE_SECAM_B,
+
+	/**
+	 * @DRM_MODE_TV_MODE_SECAM_D: CCIR System D together with the
+	 * SECAM color system.
+	 */
+	DRM_MODE_TV_MODE_SECAM_D,
+
+	/**
+	 * @DRM_MODE_TV_MODE_SECAM_G: CCIR System G together with the
+	 * SECAM color system. Similar to @DRM_MODE_TV_MODE_SECAM_B but
+	 * uses a different channel bandwidth and transmission band.
+	 */
+	DRM_MODE_TV_MODE_SECAM_G,
+
+	/**
+	 * @DRM_MODE_TV_MODE_SECAM_K: CCIR System G together with the
+	 * SECAM color system. Similar to @DRM_MODE_TV_MODE_SECAM_G but
+	 * with different channels.
+	 */
+	DRM_MODE_TV_MODE_SECAM_K,
+
+	/**
+	 * @DRM_MODE_TV_MODE_SECAM_K1: CCIR System G together with the
+	 * SECAM color system. Similar to @DRM_MODE_TV_MODE_SECAM_G and
+	 * @DRM_MODE_TV_MODE_SECAM_K but with different channels.
+	 */
+	DRM_MODE_TV_MODE_SECAM_K1,
+
+	/**
+	 * @DRM_MODE_TV_MODE_SECAM_L: CCIR System L together with the
+	 * SECAM color system.
+	 */
+	DRM_MODE_TV_MODE_SECAM_L,
+
+	DRM_MODE_TV_MODE_MAX,
+};
+
 /**
  * struct drm_scrambling: sink's scrambling support.
  */
@@ -696,6 +834,7 @@ struct drm_connector_tv_margins {
  * @subconnector: detected subconnector
  * @margins: TV margins
  * @legacy_mode: Legacy TV mode, driver specific value
+ * @mode: TV mode
  * @brightness: brightness in percent
  * @contrast: contrast in percent
  * @flicker_reduction: flicker reduction in percent
@@ -708,6 +847,7 @@ struct drm_tv_connector_state {
 	enum drm_mode_subconnector subconnector;
 	struct drm_connector_tv_margins margins;
 	unsigned int legacy_mode;
+	unsigned int mode;
 	unsigned int brightness;
 	unsigned int contrast;
 	unsigned int flicker_reduction;
@@ -1789,6 +1929,7 @@ const char *drm_get_subpixel_order_name(enum subpixel_order order);
 const char *drm_get_dpms_name(int val);
 const char *drm_get_dvi_i_subconnector_name(int val);
 const char *drm_get_dvi_i_select_name(int val);
+const char *drm_get_tv_mode_name(int val);
 const char *drm_get_tv_subconnector_name(int val);
 const char *drm_get_tv_select_name(int val);
 const char *drm_get_dp_subconnector_name(int val);
@@ -1802,6 +1943,8 @@ int drm_mode_create_tv_margin_properties(struct drm_device *dev);
 int drm_mode_create_tv_properties_legacy(struct drm_device *dev,
 					 unsigned int num_modes,
 					 const char * const modes[]);
+int drm_mode_create_tv_properties(struct drm_device *dev,
+				  unsigned int supported_tv_modes);
 void drm_connector_attach_tv_margin_properties(struct drm_connector *conn);
 int drm_mode_create_scaling_mode_property(struct drm_device *dev);
 int drm_connector_attach_content_type_property(struct drm_connector *dev);
diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h
index 35a827175c24..10a6f7d1df0d 100644
--- a/include/drm/drm_mode_config.h
+++ b/include/drm/drm_mode_config.h
@@ -718,9 +718,17 @@ struct drm_mode_config {
 	/**
 	 * @legacy_tv_mode_property: Optional TV property to select
 	 * the output TV mode.
+	 *
+	 * Superseeded by @tv_mode_property
 	 */
 	struct drm_property *legacy_tv_mode_property;
 
+	/**
+	 * @tv_mode_property: Optional TV property to select the TV
+	 * standard output on the connector.
+	 */
+	struct drm_property *tv_mode_property;
+
 	/**
 	 * @tv_left_margin_property: Optional TV property to set the left
 	 * margin (expressed in pixels).

-- 
b4 0.10.0-dev-65ba7

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

* [PATCH v2 10/41] drm/modes: Add a function to generate analog display modes
  2022-08-29 13:11 [PATCH v2 00/41] drm: Analog TV Improvements Maxime Ripard
                   ` (8 preceding siblings ...)
  2022-08-29 13:11 ` [PATCH v2 09/41] drm/connector: Add TV standard property Maxime Ripard
@ 2022-08-29 13:11 ` Maxime Ripard
  2022-08-30 13:01   ` Maíra Canal
                     ` (2 more replies)
  2022-08-29 13:11 ` [PATCH v2 11/41] drm/modes: Only consider bpp and refresh before options Maxime Ripard
                   ` (31 subsequent siblings)
  41 siblings, 3 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-08-29 13:11 UTC (permalink / raw)
  To: Maxime Ripard, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec,
	Samuel Holland, Karol Herbst, Noralf Trønnes, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Maxime Ripard, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

Multiple drivers (meson, vc4, sun4i) define analog TV 525-lines and
625-lines modes in their drivers.

Since those modes are fairly standard, and that we'll need to use them
in more places in the future, it makes sense to move their definition
into the core framework.

However, analog display usually have fairly loose timings requirements,
the only discrete parameters being the total number of lines and pixel
clock frequency. Thus, we created a function that will create a display
mode from the standard, the pixel frequency and the active area.

Signed-off-by: Maxime Ripard <maxime@cerno.tech>

diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index 304004fb80aa..ee581ee17171 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -116,6 +116,459 @@ void drm_mode_probed_add(struct drm_connector *connector,
 }
 EXPORT_SYMBOL(drm_mode_probed_add);
 
+enum drm_mode_analog {
+	DRM_MODE_ANALOG_NTSC,
+	DRM_MODE_ANALOG_PAL,
+};
+
+/*
+ * The timings come from:
+ * - https://web.archive.org/web/20220406232708/http://www.kolumbus.fi/pami1/video/pal_ntsc.html
+ * - https://web.archive.org/web/20220406124914/http://martin.hinner.info/vga/pal.html
+ * - https://web.archive.org/web/20220609202433/http://www.batsocks.co.uk/readme/video_timing.htm
+ */
+#define NTSC_LINE_DURATION_NS		63556U
+#define NTSC_LINES_NUMBER		525
+
+#define NTSC_HBLK_DURATION_TYP_NS	10900U
+#define NTSC_HBLK_DURATION_MIN_NS	(NTSC_HBLK_DURATION_TYP_NS - 200)
+#define NTSC_HBLK_DURATION_MAX_NS	(NTSC_HBLK_DURATION_TYP_NS + 200)
+
+#define NTSC_HACT_DURATION_TYP_NS	(NTSC_LINE_DURATION_NS - NTSC_HBLK_DURATION_TYP_NS)
+#define NTSC_HACT_DURATION_MIN_NS	(NTSC_LINE_DURATION_NS - NTSC_HBLK_DURATION_MAX_NS)
+#define NTSC_HACT_DURATION_MAX_NS	(NTSC_LINE_DURATION_NS - NTSC_HBLK_DURATION_MIN_NS)
+
+#define NTSC_HFP_DURATION_TYP_NS	1500
+#define NTSC_HFP_DURATION_MIN_NS	1270
+#define NTSC_HFP_DURATION_MAX_NS	2220
+
+#define NTSC_HSLEN_DURATION_TYP_NS	4700
+#define NTSC_HSLEN_DURATION_MIN_NS	(NTSC_HSLEN_DURATION_TYP_NS - 100)
+#define NTSC_HSLEN_DURATION_MAX_NS	(NTSC_HSLEN_DURATION_TYP_NS + 100)
+
+#define NTSC_HBP_DURATION_TYP_NS	4700
+
+/*
+ * I couldn't find the actual tolerance for the back porch, so let's
+ * just reuse the sync length ones.
+ */
+#define NTSC_HBP_DURATION_MIN_NS	(NTSC_HBP_DURATION_TYP_NS - 100)
+#define NTSC_HBP_DURATION_MAX_NS	(NTSC_HBP_DURATION_TYP_NS + 100)
+
+#define PAL_LINE_DURATION_NS		64000U
+#define PAL_LINES_NUMBER		625
+
+#define PAL_HACT_DURATION_TYP_NS	51950U
+#define PAL_HACT_DURATION_MIN_NS	(PAL_HACT_DURATION_TYP_NS - 100)
+#define PAL_HACT_DURATION_MAX_NS	(PAL_HACT_DURATION_TYP_NS + 400)
+
+#define PAL_HBLK_DURATION_TYP_NS	(PAL_LINE_DURATION_NS - PAL_HACT_DURATION_TYP_NS)
+#define PAL_HBLK_DURATION_MIN_NS	(PAL_LINE_DURATION_NS - PAL_HACT_DURATION_MAX_NS)
+#define PAL_HBLK_DURATION_MAX_NS	(PAL_LINE_DURATION_NS - PAL_HACT_DURATION_MIN_NS)
+
+#define PAL_HFP_DURATION_TYP_NS		1650
+#define PAL_HFP_DURATION_MIN_NS		(PAL_HFP_DURATION_TYP_NS - 100)
+#define PAL_HFP_DURATION_MAX_NS		(PAL_HFP_DURATION_TYP_NS + 400)
+
+#define PAL_HSLEN_DURATION_TYP_NS	4700
+#define PAL_HSLEN_DURATION_MIN_NS	(PAL_HSLEN_DURATION_TYP_NS - 200)
+#define PAL_HSLEN_DURATION_MAX_NS	(PAL_HSLEN_DURATION_TYP_NS + 200)
+
+#define PAL_HBP_DURATION_TYP_NS		5700
+#define PAL_HBP_DURATION_MIN_NS		(PAL_HBP_DURATION_TYP_NS - 200)
+#define PAL_HBP_DURATION_MAX_NS		(PAL_HBP_DURATION_TYP_NS + 200)
+
+#define PAL_VFP_INTERLACE_LINES		5
+#define PAL_VSLEN_INTERLACE_LINES	5
+
+#define PAL_SHORT_SYNC_DURATION_NS	((2 + 30) * NSEC_PER_USEC)
+#define PAL_LONG_SYNC_DURATION_NS	((30 + 2) * NSEC_PER_USEC)
+
+struct analog_param_field {
+	unsigned int even, odd;
+};
+
+#define PARAM_FIELD(_odd, _even)		\
+	{ .even = _even, .odd = _odd }
+
+struct analog_param_range {
+	unsigned int	min, typ, max;
+};
+
+#define PARAM_RANGE(_min, _typ, _max)		\
+	{ .min = _min, .typ = _typ, .max = _max }
+
+struct analog_parameters {
+	unsigned int			num_lines;
+	unsigned int			line_duration_ns;
+
+	struct analog_param_range	hact_ns;
+	struct analog_param_range	hfp_ns;
+	struct analog_param_range	hslen_ns;
+	struct analog_param_range	hbp_ns;
+	struct analog_param_range	hblk_ns;
+
+	struct analog_param_field	vfp_lines;
+	struct analog_param_field	vslen_lines;
+	struct analog_param_field	vbp_lines;
+};
+
+#define TV_MODE_PARAMETER(_mode, _lines, _line_dur, _hact, _hfp, _hslen, _hbp, _hblk, _vfp, _vslen, _vbp) \
+	[_mode] = {							\
+		.num_lines = _lines,					\
+		.line_duration_ns = _line_dur,				\
+		.hact_ns = _hact,					\
+		.hfp_ns = _hfp,						\
+		.hslen_ns = _hslen,					\
+		.hbp_ns = _hbp,						\
+		.hblk_ns = _hblk,					\
+		.vfp_lines = _vfp,					\
+		.vslen_lines = _vslen,					\
+		.vbp_lines = _vbp,					\
+	}
+
+const static struct analog_parameters tv_modes_parameters[] = {
+	TV_MODE_PARAMETER(DRM_MODE_ANALOG_NTSC,
+			  NTSC_LINES_NUMBER,
+			  NTSC_LINE_DURATION_NS,
+			  PARAM_RANGE(NTSC_HACT_DURATION_MIN_NS,
+				      NTSC_HACT_DURATION_TYP_NS,
+				      NTSC_HACT_DURATION_MAX_NS),
+			  PARAM_RANGE(NTSC_HFP_DURATION_MIN_NS,
+				      NTSC_HFP_DURATION_TYP_NS,
+				      NTSC_HFP_DURATION_MAX_NS),
+			  PARAM_RANGE(NTSC_HSLEN_DURATION_MIN_NS,
+				      NTSC_HSLEN_DURATION_TYP_NS,
+				      NTSC_HSLEN_DURATION_MAX_NS),
+			  PARAM_RANGE(NTSC_HBP_DURATION_MIN_NS,
+				      NTSC_HBP_DURATION_TYP_NS,
+				      NTSC_HBP_DURATION_MAX_NS),
+			  PARAM_RANGE(NTSC_HBLK_DURATION_MIN_NS,
+				      NTSC_HBLK_DURATION_TYP_NS,
+				      NTSC_HBLK_DURATION_MAX_NS),
+			  PARAM_FIELD(3, 3),
+			  PARAM_FIELD(3, 3),
+			  PARAM_FIELD(3, 3)),
+	TV_MODE_PARAMETER(DRM_MODE_ANALOG_PAL,
+			  PAL_LINES_NUMBER,
+			  PAL_LINE_DURATION_NS,
+			  PARAM_RANGE(PAL_HACT_DURATION_MIN_NS,
+				      PAL_HACT_DURATION_TYP_NS,
+				      PAL_HACT_DURATION_MAX_NS),
+			  PARAM_RANGE(PAL_HFP_DURATION_MIN_NS,
+				      PAL_HFP_DURATION_TYP_NS,
+				      PAL_HFP_DURATION_MAX_NS),
+			  PARAM_RANGE(PAL_HSLEN_DURATION_MIN_NS,
+				      PAL_HSLEN_DURATION_TYP_NS,
+				      PAL_HSLEN_DURATION_MAX_NS),
+			  PARAM_RANGE(PAL_HBP_DURATION_MIN_NS,
+				      PAL_HBP_DURATION_TYP_NS,
+				      PAL_HBP_DURATION_MAX_NS),
+			  PARAM_RANGE(PAL_HBLK_DURATION_MIN_NS,
+				      PAL_HBLK_DURATION_TYP_NS,
+				      PAL_HBLK_DURATION_MAX_NS),
+
+			  /*
+			   * The front porch is actually 6 short sync
+			   * pulses for the even field, and 5 for the
+			   * odd field. Each sync takes half a life so
+			   * the odd field front porch is shorter by
+			   * half a line.
+			   *
+			   * In progressive, we're supposed to use 6
+			   * pulses, so we're fine there
+			   */
+			  PARAM_FIELD(3, 2),
+
+			  /*
+			   * The vsync length is 5 long sync pulses,
+			   * each field taking half a line. We're
+			   * shorter for both fields by half a line.
+			   *
+			   * In progressive, we're supposed to use 5
+			   * pulses, so we're off by half
+			   * a line.
+			   *
+			   * In interlace, we're now off by half a line
+			   * for the even field and one line for the odd
+			   * field.
+			   */
+			  PARAM_FIELD(3, 3),
+
+			  /*
+			   * The back porch is actually 5 short sync
+			   * pulses for the even field, 4 for the odd
+			   * field. In progressive, it's 5 short syncs.
+			   *
+			   * In progressive, we thus have 2.5 lines,
+			   * plus the 0.5 line we were missing
+			   * previously, so we should use 3 lines.
+			   *
+			   * In interlace, the even field is in the
+			   * exact same case than progressive. For the
+			   * odd field, we should be using 2 lines but
+			   * we're one line short, so we'll make up for
+			   * it here by using 3.
+			   */
+			  PARAM_FIELD(3, 3)),
+};
+
+static int fill_analog_mode(struct drm_display_mode *mode,
+			    const struct analog_parameters *params,
+			    unsigned long pixel_clock_hz,
+			    unsigned int hactive,
+			    unsigned int vactive,
+			    bool interlace)
+{
+	unsigned long pixel_duration_ns = NSEC_PER_SEC / pixel_clock_hz;
+	unsigned long long htotal;
+	unsigned int vtotal;
+	unsigned int max_hact, hact_duration_ns;
+	unsigned int hblk, hblk_duration_ns;
+	unsigned int hfp, hfp_min, hfp_duration_ns;
+	unsigned int hslen, hslen_duration_ns;
+	unsigned int hbp, hbp_min, hbp_duration_ns;
+	unsigned int porches, porches_duration_ns;
+	unsigned int vfp, vfp_min;
+	unsigned int vbp, vbp_min;
+	unsigned int vslen;
+	int porches_rem;
+	bool strict = true;
+
+	max_hact = params->hact_ns.max / pixel_duration_ns;
+	if (pixel_clock_hz == 13500000 && hactive > max_hact && hactive <= 720)
+		strict = false;
+
+	/*
+	 * Our pixel duration is going to be round down by the division,
+	 * so rounding up is probably going to introduce even more
+	 * deviation.
+	 */
+	htotal = params->line_duration_ns * pixel_clock_hz / NSEC_PER_SEC;
+
+	hact_duration_ns = hactive * pixel_duration_ns;
+	if (strict &&
+	    (hact_duration_ns < params->hact_ns.min ||
+	     hact_duration_ns > params->hact_ns.max)) {
+		DRM_ERROR("Invalid horizontal active area duration: %uns (min: %u, max %u)\n",
+			  hact_duration_ns, params->hact_ns.min, params->hact_ns.max);
+		return -EINVAL;
+	}
+
+	hblk = htotal - hactive;
+	hblk_duration_ns = hblk * pixel_duration_ns;
+	if (strict &&
+	    (hblk_duration_ns < params->hblk_ns.min ||
+	     hblk_duration_ns > params->hblk_ns.max)) {
+		DRM_ERROR("Invalid horizontal blanking duration: %uns (min: %u, max %u)\n",
+			  hblk_duration_ns, params->hblk_ns.min, params->hblk_ns.max);
+		return -EINVAL;
+	}
+
+	hslen = DIV_ROUND_UP(params->hslen_ns.typ, pixel_duration_ns);
+	hslen_duration_ns = hslen * pixel_duration_ns;
+	if (strict &&
+	    (hslen_duration_ns < params->hslen_ns.min ||
+	     hslen_duration_ns > params->hslen_ns.max)) {
+		DRM_ERROR("Invalid horizontal sync duration: %uns (min: %u, max %u)\n",
+			  hslen_duration_ns, params->hslen_ns.min, params->hslen_ns.max);
+		return -EINVAL;
+	}
+
+	porches = hblk - hslen;
+	porches_duration_ns = porches * pixel_duration_ns;
+	if (strict &&
+	    (porches_duration_ns > (params->hfp_ns.max + params->hbp_ns.max) ||
+	     porches_duration_ns < (params->hfp_ns.min + params->hbp_ns.min))) {
+		DRM_ERROR("Invalid horizontal porches duration: %uns\n", porches_duration_ns);
+		return -EINVAL;
+	}
+
+	hfp_min = DIV_ROUND_UP(params->hfp_ns.min, pixel_duration_ns);
+	hbp_min = DIV_ROUND_UP(params->hbp_ns.min, pixel_duration_ns);
+	porches_rem = porches - hfp_min - hbp_min;
+
+	hfp = hfp_min + DIV_ROUND_UP(porches_rem, 2);
+	hfp_duration_ns = hfp * pixel_duration_ns;
+	if (strict &&
+	    (hfp_duration_ns < params->hfp_ns.min ||
+	     hfp_duration_ns > params->hfp_ns.max)) {
+		DRM_ERROR("Invalid horizontal front porch duration: %uns (min: %u, max %u)\n",
+			  hfp_duration_ns, params->hfp_ns.min, params->hfp_ns.max);
+		return -EINVAL;
+	}
+
+	hbp = porches - hfp;
+	hbp_duration_ns = hbp * pixel_duration_ns;
+	if (strict &&
+	    (hbp_duration_ns < params->hbp_ns.min ||
+	     hbp_duration_ns > params->hbp_ns.max)) {
+		DRM_ERROR("Invalid horizontal back porch duration: %uns (min: %u, max %u)\n",
+			  hbp_duration_ns, params->hbp_ns.min, params->hbp_ns.max);
+		return -EINVAL;
+	}
+
+	if (htotal != (hactive + hfp + hslen + hbp))
+		return -EINVAL;
+
+	mode->clock = pixel_clock_hz / 1000;
+	mode->hdisplay = hactive;
+	mode->hsync_start = hactive + hfp;
+	mode->hsync_end = hactive + hfp + hslen;
+	mode->htotal = hactive + hfp + hslen + hbp;
+
+	if (interlace) {
+		vfp_min = params->vfp_lines.even + params->vfp_lines.odd;
+		vbp_min = params->vbp_lines.even + params->vbp_lines.odd;
+		vslen = params->vslen_lines.even + params->vslen_lines.odd;
+	} else {
+		/*
+		 * By convention, NSTC (aka 525/60) systems start with
+		 * the even field, but PAL (aka 625/50) systems start
+		 * with the odd one.
+		 *
+		 * PAL systems also have asymetric timings between the
+		 * even and odd field, while NTSC is symetric.
+		 *
+		 * Moreover, if we want to create a progressive mode for
+		 * PAL, we need to use the odd field timings.
+		 *
+		 * Since odd == even for NTSC, we can just use the odd
+		 * one all the time to simplify the code a bit.
+		 */
+		vfp_min = params->vfp_lines.odd;
+		vbp_min = params->vbp_lines.odd;
+		vslen = params->vslen_lines.odd;
+	}
+
+	porches = params->num_lines - vactive - vslen;
+	porches_rem = porches - vfp_min - vbp_min;
+
+	vfp = vfp_min + (porches_rem / 2);
+	vbp = porches - vfp;
+
+	vtotal = vactive + vfp + vslen + vbp;
+	if (params->num_lines != vtotal) {
+		DRM_ERROR("Invalid vertical total: %upx (expected %upx)\n",
+			  vtotal, params->num_lines);
+		return -EINVAL;
+	}
+
+	mode->vdisplay = vactive;
+	mode->vsync_start = vactive + vfp;
+	mode->vsync_end = vactive + vfp + vslen;
+	mode->vtotal = vactive + vfp + vslen + vbp;
+
+	mode->type = DRM_MODE_TYPE_DRIVER;
+	mode->flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC;
+	if (interlace)
+		mode->flags |= DRM_MODE_FLAG_INTERLACE;
+
+	drm_mode_set_name(mode);
+
+	if (mode->vtotal != params->num_lines)
+		return -EINVAL;
+
+	return 0;
+}
+
+/**
+ * drm_analog_tv_mode - create a display mode for an analog TV
+ * @dev: drm device
+ * @tv_mode: TV Mode standard to create a mode for. See DRM_MODE_TV_MODE_*.
+ * @pixel_clock_hz: Pixel Clock Frequency, in Hertz
+ * @hdisplay: hdisplay size
+ * @vdisplay: vdisplay size
+ * @interlace: whether to compute an interlaced mode
+ *
+ * This function creates a struct drm_display_mode instance suited for
+ * an analog TV output, for one of the usual analog TV mode.
+ *
+ * Note that @hdisplay is larger than the usual constraints for the PAL
+ * and NTSC timings, and we'll choose to ignore most timings constraints
+ * to reach those resolutions.
+ *
+ * Returns:
+ *
+ * A pointer to the mode, allocated with drm_mode_create(). Returns NULL
+ * on error.
+ */
+struct drm_display_mode *drm_analog_tv_mode(struct drm_device *dev,
+					    enum drm_connector_tv_mode tv_mode,
+					    unsigned long pixel_clock_hz,
+					    unsigned int hdisplay,
+					    unsigned int vdisplay,
+					    bool interlace)
+{
+	struct drm_display_mode *mode;
+	enum drm_mode_analog analog;
+	int ret;
+
+	switch (tv_mode) {
+	case DRM_MODE_TV_MODE_NTSC_443:
+		fallthrough;
+	case DRM_MODE_TV_MODE_NTSC_J:
+		fallthrough;
+	case DRM_MODE_TV_MODE_NTSC_M:
+		fallthrough;
+	case DRM_MODE_TV_MODE_PAL_60:
+		fallthrough;
+	case DRM_MODE_TV_MODE_PAL_M:
+		fallthrough;
+	case DRM_MODE_TV_MODE_SECAM_60:
+		analog = DRM_MODE_ANALOG_NTSC;
+		break;
+
+	case DRM_MODE_TV_MODE_PAL_B:
+		fallthrough;
+	case DRM_MODE_TV_MODE_PAL_D:
+		fallthrough;
+	case DRM_MODE_TV_MODE_PAL_G:
+		fallthrough;
+	case DRM_MODE_TV_MODE_PAL_H:
+		fallthrough;
+	case DRM_MODE_TV_MODE_PAL_I:
+		fallthrough;
+	case DRM_MODE_TV_MODE_PAL_N:
+		fallthrough;
+	case DRM_MODE_TV_MODE_PAL_NC:
+		fallthrough;
+	case DRM_MODE_TV_MODE_SECAM_B:
+		fallthrough;
+	case DRM_MODE_TV_MODE_SECAM_D:
+		fallthrough;
+	case DRM_MODE_TV_MODE_SECAM_G:
+		fallthrough;
+	case DRM_MODE_TV_MODE_SECAM_K:
+		fallthrough;
+	case DRM_MODE_TV_MODE_SECAM_K1:
+		fallthrough;
+	case DRM_MODE_TV_MODE_SECAM_L:
+		analog = DRM_MODE_ANALOG_PAL;
+		break;
+
+	default:
+		return NULL;
+	}
+
+	mode = drm_mode_create(dev);
+	if (!mode)
+		return NULL;
+
+	ret = fill_analog_mode(mode,
+			       &tv_modes_parameters[analog],
+			       pixel_clock_hz, hdisplay, vdisplay, interlace);
+	if (ret)
+		goto err_free_mode;
+
+	return mode;
+
+err_free_mode:
+	drm_mode_destroy(dev, mode);
+	return NULL;
+}
+EXPORT_SYMBOL(drm_analog_tv_mode);
+
 /**
  * drm_cvt_mode -create a modeline based on the CVT algorithm
  * @dev: drm device
diff --git a/drivers/gpu/drm/tests/Makefile b/drivers/gpu/drm/tests/Makefile
index b29ef1085cad..b22ac96fdd65 100644
--- a/drivers/gpu/drm/tests/Makefile
+++ b/drivers/gpu/drm/tests/Makefile
@@ -10,5 +10,6 @@ obj-$(CONFIG_DRM_KUNIT_TEST) += \
 	drm_framebuffer_test.o \
 	drm_kunit_helpers.o \
 	drm_mm_test.o \
+	drm_modes_test.o \
 	drm_plane_helper_test.o \
 	drm_rect_test.o
diff --git a/drivers/gpu/drm/tests/drm_modes_test.c b/drivers/gpu/drm/tests/drm_modes_test.c
new file mode 100644
index 000000000000..87d398fcb99e
--- /dev/null
+++ b/drivers/gpu/drm/tests/drm_modes_test.c
@@ -0,0 +1,131 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Kunit test for drm_modes functions
+ */
+
+#include <kunit/test.h>
+
+#include <drm/drm_modes.h>
+
+#include "drm_kunit_helpers.h"
+
+struct drm_modes_test_priv {
+	struct drm_device *drm;
+};
+
+static int drm_modes_test_init(struct kunit *test)
+{
+	struct drm_modes_test_priv *priv;
+
+	priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+	test->priv = priv;
+
+	priv->drm = drm_kunit_device_init("drm-modes-test");
+	if (IS_ERR(priv->drm))
+		return PTR_ERR(priv->drm);
+
+	return 0;
+}
+
+static void drm_modes_test_exit(struct kunit *test)
+{
+	struct drm_modes_test_priv *priv = test->priv;
+
+	drm_kunit_device_exit(priv->drm);
+}
+
+static void drm_modes_analog_tv_ntsc_480i(struct kunit *test)
+{
+	struct drm_modes_test_priv *priv = test->priv;
+	struct drm_display_mode *mode;
+
+	mode = drm_analog_tv_mode(priv->drm,
+				  DRM_MODE_TV_MODE_NTSC_M,
+				  13500 * 1000, 720, 480,
+				  true);
+	KUNIT_ASSERT_NOT_NULL(test, mode);
+
+	KUNIT_EXPECT_EQ(test, drm_mode_vrefresh(mode), 60);
+	KUNIT_EXPECT_EQ(test, mode->hdisplay, 720);
+
+	/* 63.556us * 13.5MHz = 858 pixels */
+	KUNIT_EXPECT_EQ(test, mode->htotal, 858);
+	KUNIT_EXPECT_EQ(test, mode->vdisplay, 480);
+	KUNIT_EXPECT_EQ(test, mode->vtotal, 525);
+}
+
+static void drm_modes_analog_tv_ntsc_480i_inlined(struct kunit *test)
+{
+	struct drm_modes_test_priv *priv = test->priv;
+	struct drm_display_mode *expected, *mode;
+
+	expected = drm_analog_tv_mode(priv->drm,
+				      DRM_MODE_TV_MODE_NTSC_M,
+				      13500 * 1000, 720, 480,
+				      true);
+	KUNIT_ASSERT_NOT_NULL(test, expected);
+
+	mode = drm_mode_analog_ntsc_480i(priv->drm);
+	KUNIT_ASSERT_NOT_NULL(test, mode);
+
+	KUNIT_EXPECT_TRUE(test, drm_mode_equal(expected, mode));
+}
+
+static void drm_modes_analog_tv_pal_576i(struct kunit *test)
+{
+	struct drm_modes_test_priv *priv = test->priv;
+	struct drm_display_mode *mode;
+
+	mode = drm_analog_tv_mode(priv->drm,
+				  DRM_MODE_TV_MODE_PAL_B,
+				  13500 * 1000, 720, 576,
+				  true);
+	KUNIT_ASSERT_NOT_NULL(test, mode);
+
+	KUNIT_EXPECT_EQ(test, drm_mode_vrefresh(mode), 50);
+	KUNIT_EXPECT_EQ(test, mode->hdisplay, 720);
+
+	/* 64us * 13.5MHz = 864 pixels */
+	KUNIT_EXPECT_EQ(test, mode->htotal, 864);
+	KUNIT_EXPECT_EQ(test, mode->vdisplay, 576);
+	KUNIT_EXPECT_EQ(test, mode->vtotal, 625);
+}
+
+static void drm_modes_analog_tv_pal_576i_inlined(struct kunit *test)
+{
+	struct drm_modes_test_priv *priv = test->priv;
+	struct drm_display_mode *expected, *mode;
+
+	expected = drm_analog_tv_mode(priv->drm,
+				      DRM_MODE_TV_MODE_PAL_B,
+				      13500 * 1000, 720, 576,
+				      true);
+	KUNIT_ASSERT_NOT_NULL(test, expected);
+
+	mode = drm_mode_analog_pal_576i(priv->drm);
+	KUNIT_ASSERT_NOT_NULL(test, mode);
+
+	KUNIT_EXPECT_TRUE(test, drm_mode_equal(expected, mode));
+}
+
+static struct kunit_case drm_modes_analog_tv_tests[] = {
+	KUNIT_CASE(drm_modes_analog_tv_ntsc_480i),
+	KUNIT_CASE(drm_modes_analog_tv_ntsc_480i_inlined),
+	KUNIT_CASE(drm_modes_analog_tv_pal_576i),
+	KUNIT_CASE(drm_modes_analog_tv_pal_576i_inlined),
+	{ }
+};
+
+static struct kunit_suite drm_modes_analog_tv_test_suite = {
+	.name = "drm_modes_analog_tv",
+	.init = drm_modes_test_init,
+	.exit = drm_modes_test_exit,
+	.test_cases = drm_modes_analog_tv_tests,
+};
+
+kunit_test_suites(
+	&drm_modes_analog_tv_test_suite
+);
+MODULE_LICENSE("GPL v2");
diff --git a/include/drm/drm_modes.h b/include/drm/drm_modes.h
index a80ae9639e96..5ccf3d51d313 100644
--- a/include/drm/drm_modes.h
+++ b/include/drm/drm_modes.h
@@ -443,6 +443,23 @@ bool drm_mode_is_420_also(const struct drm_display_info *display,
 bool drm_mode_is_420(const struct drm_display_info *display,
 		     const struct drm_display_mode *mode);
 
+struct drm_display_mode *drm_analog_tv_mode(struct drm_device *dev,
+					    enum drm_connector_tv_mode mode,
+					    unsigned long pixel_clock_hz,
+					    unsigned int hdisplay,
+					    unsigned int vdisplay,
+					    bool interlace);
+
+static inline struct drm_display_mode *drm_mode_analog_ntsc_480i(struct drm_device *dev)
+{
+	return drm_analog_tv_mode(dev, DRM_MODE_TV_MODE_NTSC_M, 13500000, 720, 480, true);
+}
+
+static inline struct drm_display_mode *drm_mode_analog_pal_576i(struct drm_device *dev)
+{
+	return drm_analog_tv_mode(dev, DRM_MODE_TV_MODE_PAL_B, 13500000, 720, 576, true);
+}
+
 struct drm_display_mode *drm_cvt_mode(struct drm_device *dev,
 				      int hdisplay, int vdisplay, int vrefresh,
 				      bool reduced, bool interlaced,

-- 
b4 0.10.0-dev-65ba7

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

* [PATCH v2 11/41] drm/modes: Only consider bpp and refresh before options
  2022-08-29 13:11 [PATCH v2 00/41] drm: Analog TV Improvements Maxime Ripard
                   ` (9 preceding siblings ...)
  2022-08-29 13:11 ` [PATCH v2 10/41] drm/modes: Add a function to generate analog display modes Maxime Ripard
@ 2022-08-29 13:11 ` Maxime Ripard
  2022-08-29 13:11 ` [PATCH v2 12/41] drm/modes: parse_cmdline: Add support for named modes containing dashes Maxime Ripard
                   ` (30 subsequent siblings)
  41 siblings, 0 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-08-29 13:11 UTC (permalink / raw)
  To: Maxime Ripard, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec,
	Samuel Holland, Karol Herbst, Noralf Trønnes, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Maxime Ripard, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

Some video= options might have a value that contains a dash. However, the
command line parsing mode considers all dashes as the separator between the
mode and the bpp count.

Let's rework the parsing code a bit to only consider a dash as the bpp
separator if it before a comma, the options separator.

A follow-up patch will add a unit-test for this once such an option is
introduced.

Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Reviewed-by: Geert Uytterhoeven <geert@linux-m68k.org>

diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index ee581ee17171..b4e1ff56b4d8 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -2254,20 +2254,22 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
 
 	name = mode_option;
 
+	/* Locate the start of named options */
+	options_ptr = strchr(name, ',');
+	if (options_ptr)
+		options_off = options_ptr - name;
+	else
+		options_off = strlen(name);
+
 	/* Try to locate the bpp and refresh specifiers, if any */
-	bpp_ptr = strchr(name, '-');
+	bpp_ptr = strnchr(name, options_off, '-');
 	if (bpp_ptr)
 		bpp_off = bpp_ptr - name;
 
-	refresh_ptr = strchr(name, '@');
+	refresh_ptr = strnchr(name, options_off, '@');
 	if (refresh_ptr)
 		refresh_off = refresh_ptr - name;
 
-	/* 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) {
 		mode_end = bpp_off;

-- 
b4 0.10.0-dev-65ba7

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

* [PATCH v2 12/41] drm/modes: parse_cmdline: Add support for named modes containing dashes
  2022-08-29 13:11 [PATCH v2 00/41] drm: Analog TV Improvements Maxime Ripard
                   ` (10 preceding siblings ...)
  2022-08-29 13:11 ` [PATCH v2 11/41] drm/modes: Only consider bpp and refresh before options Maxime Ripard
@ 2022-08-29 13:11 ` Maxime Ripard
  2022-08-29 13:11 ` [PATCH v2 13/41] drm/client: Add some tests for drm_connector_pick_cmdline_mode() Maxime Ripard
                   ` (29 subsequent siblings)
  41 siblings, 0 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-08-29 13:11 UTC (permalink / raw)
  To: Maxime Ripard, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec,
	Samuel Holland, Karol Herbst, Noralf Trønnes, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Maxime Ripard, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

From: Geert Uytterhoeven <geert@linux-m68k.org>

It is fairly common for named video modes to contain dashes (e.g.
"tt-mid" on Atari, "dblntsc-ff" on Amiga).  Currently such mode names
are not recognized, as the dash is considered to be a separator between
mode name and bpp.

Fix this by skipping any dashes that are not followed immediately by a
digit when looking for the separator.

Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>

diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index b4e1ff56b4d8..99a21e5cd00d 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -2263,6 +2263,8 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
 
 	/* Try to locate the bpp and refresh specifiers, if any */
 	bpp_ptr = strnchr(name, options_off, '-');
+	while (bpp_ptr && !isdigit(bpp_ptr[1]))
+		bpp_ptr = strnchr(bpp_ptr + 1, options_off, '-');
 	if (bpp_ptr)
 		bpp_off = bpp_ptr - name;
 

-- 
b4 0.10.0-dev-65ba7

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

* [PATCH v2 13/41] drm/client: Add some tests for drm_connector_pick_cmdline_mode()
  2022-08-29 13:11 [PATCH v2 00/41] drm: Analog TV Improvements Maxime Ripard
                   ` (11 preceding siblings ...)
  2022-08-29 13:11 ` [PATCH v2 12/41] drm/modes: parse_cmdline: Add support for named modes containing dashes Maxime Ripard
@ 2022-08-29 13:11 ` Maxime Ripard
  2022-08-29 13:11 ` [PATCH v2 14/41] drm/modes: Move named modes parsing to a separate function Maxime Ripard
                   ` (28 subsequent siblings)
  41 siblings, 0 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-08-29 13:11 UTC (permalink / raw)
  To: Maxime Ripard, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec,
	Samuel Holland, Karol Herbst, Noralf Trønnes, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Maxime Ripard, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

drm_connector_pick_cmdline_mode() is in charge of finding a proper
drm_display_mode from the definition we got in the video= command line
argument.

Let's add some unit tests to make sure we're not getting any regressions
there.

Signed-off-by: Maxime Ripard <maxime@cerno.tech>

diff --git a/drivers/gpu/drm/drm_client_modeset.c b/drivers/gpu/drm/drm_client_modeset.c
index bbc535cc50dd..d553e793e673 100644
--- a/drivers/gpu/drm/drm_client_modeset.c
+++ b/drivers/gpu/drm/drm_client_modeset.c
@@ -1237,3 +1237,7 @@ int drm_client_modeset_dpms(struct drm_client_dev *client, int mode)
 	return ret;
 }
 EXPORT_SYMBOL(drm_client_modeset_dpms);
+
+#ifdef CONFIG_DRM_KUNIT_TEST
+#include "tests/drm_client_modeset_test.c"
+#endif
diff --git a/drivers/gpu/drm/tests/drm_client_modeset_test.c b/drivers/gpu/drm/tests/drm_client_modeset_test.c
new file mode 100644
index 000000000000..46335de7bc6b
--- /dev/null
+++ b/drivers/gpu/drm/tests/drm_client_modeset_test.c
@@ -0,0 +1,114 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2022 Maxime Ripard <mripard@kernel.org>
+ */
+
+#include <kunit/test.h>
+
+#include <drm/drm_connector.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_modes.h>
+#include <drm/drm_modeset_helper_vtables.h>
+#include <drm/drm_probe_helper.h>
+
+#include "drm_kunit_helpers.h"
+
+struct drm_client_modeset_test_priv {
+	struct drm_device *drm;
+	struct drm_connector connector;
+};
+
+static int drm_client_modeset_connector_get_modes(struct drm_connector *connector)
+{
+	struct drm_display_mode *mode;
+	int count;
+
+	count = drm_add_modes_noedid(connector, 1920, 1200);
+
+	return count;
+}
+
+static const struct drm_connector_helper_funcs drm_client_modeset_connector_helper_funcs = {
+	.get_modes = drm_client_modeset_connector_get_modes,
+};
+
+static const struct drm_connector_funcs drm_client_modeset_connector_funcs = {
+};
+
+static int drm_client_modeset_test_init(struct kunit *test)
+{
+	struct drm_client_modeset_test_priv *priv;
+	int ret;
+
+	priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+	test->priv = priv;
+
+	priv->drm = drm_kunit_device_init("drm-client-modeset-test");
+	if (IS_ERR(priv->drm))
+		return PTR_ERR(priv->drm);
+
+	ret = drmm_connector_init(priv->drm, &priv->connector,
+				  &drm_client_modeset_connector_funcs,
+				  DRM_MODE_CONNECTOR_Unknown,
+				  NULL);
+	if (ret)
+		return ret;
+	drm_connector_helper_add(&priv->connector, &drm_client_modeset_connector_helper_funcs);
+
+	return 0;
+}
+
+static void drm_client_modeset_test_exit(struct kunit *test)
+{
+	struct drm_client_modeset_test_priv *priv = test->priv;
+
+	drm_kunit_device_exit(priv->drm);
+}
+
+static void drm_pick_cmdline_res_1920_1080_60(struct kunit *test)
+{
+	struct drm_client_modeset_test_priv *priv = test->priv;
+	struct drm_device *drm = priv->drm;
+	struct drm_connector *connector = &priv->connector;
+	struct drm_cmdline_mode *cmdline_mode = &connector->cmdline_mode;
+	struct drm_display_mode *expected_mode, *mode;
+	const char *cmdline = "1920x1080@60";
+	int ret;
+
+	expected_mode = drm_mode_find_dmt(priv->drm, 1920, 1080, 60, false);
+	KUNIT_ASSERT_PTR_NE(test, expected_mode, NULL);
+
+	KUNIT_ASSERT_TRUE(test,
+			  drm_mode_parse_command_line_for_connector(cmdline,
+								    connector,
+								    cmdline_mode));
+
+	mutex_lock(&drm->mode_config.mutex);
+	ret = drm_helper_probe_single_connector_modes(connector, 1920, 1080);
+	mutex_unlock(&drm->mode_config.mutex);
+	KUNIT_ASSERT_GT(test, ret, 0);
+
+	mode = drm_connector_pick_cmdline_mode(connector);
+	KUNIT_ASSERT_PTR_NE(test, mode, NULL);
+
+	KUNIT_EXPECT_TRUE(test, drm_mode_equal(expected_mode, mode));
+}
+
+static struct kunit_case drm_pick_cmdline_tests[] = {
+	KUNIT_CASE(drm_pick_cmdline_res_1920_1080_60),
+	{}
+};
+
+static struct kunit_suite drm_pick_cmdline_test_suite = {
+	.name = "drm_pick_cmdline",
+	.init = drm_client_modeset_test_init,
+	.exit = drm_client_modeset_test_exit,
+	.test_cases = drm_pick_cmdline_tests
+};
+
+kunit_test_suite(drm_pick_cmdline_test_suite);
+MODULE_AUTHOR("Maxime Ripard <mripard@kernel.org>");
+MODULE_LICENSE("GPL");

-- 
b4 0.10.0-dev-65ba7

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

* [PATCH v2 14/41] drm/modes: Move named modes parsing to a separate function
  2022-08-29 13:11 [PATCH v2 00/41] drm: Analog TV Improvements Maxime Ripard
                   ` (12 preceding siblings ...)
  2022-08-29 13:11 ` [PATCH v2 13/41] drm/client: Add some tests for drm_connector_pick_cmdline_mode() Maxime Ripard
@ 2022-08-29 13:11 ` Maxime Ripard
  2022-08-30 10:06   ` Geert Uytterhoeven
  2022-08-29 13:11 ` [PATCH v2 15/41] drm/modes: Switch to named mode descriptors Maxime Ripard
                   ` (27 subsequent siblings)
  41 siblings, 1 reply; 128+ messages in thread
From: Maxime Ripard @ 2022-08-29 13:11 UTC (permalink / raw)
  To: Maxime Ripard, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec,
	Samuel Holland, Karol Herbst, Noralf Trønnes, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Maxime Ripard, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

The current construction of the named mode parsing doesn't allow to extend
it easily. Let's move it to a separate function so we can add more
parameters and modes.

Signed-off-by: Maxime Ripard <maxime@cerno.tech>

diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index 99a21e5cd00d..0636cb707544 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -1909,6 +1909,9 @@ void drm_connector_list_update(struct drm_connector *connector)
 }
 EXPORT_SYMBOL(drm_connector_list_update);
 
+#define STR_STRICT_EQ(str, len, cmp) \
+	((strlen(cmp) == len) && !strncmp(str, cmp, len))
+
 static int drm_mode_parse_cmdline_bpp(const char *str, char **end_ptr,
 				      struct drm_cmdline_mode *mode)
 {
@@ -2208,6 +2211,52 @@ static const char * const drm_named_modes_whitelist[] = {
 	"PAL",
 };
 
+static int drm_mode_parse_cmdline_named_mode(const char *name,
+					     unsigned int name_end,
+					     struct drm_cmdline_mode *cmdline_mode)
+{
+	unsigned int i;
+
+	if (!name_end)
+		return 0;
+
+	/* If the name starts with a digit, it's not a named mode */
+	if (isdigit(name[0]))
+		return 0;
+
+	/*
+	 * If there's an equal sign in the name, the command-line
+	 * contains only an option and no mode.
+	 */
+	if (strnchr(name, name_end, '='))
+		return 0;
+
+	/* The connection status extras can be set without a mode. */
+	if (STR_STRICT_EQ(name, name_end, "d") ||
+	    STR_STRICT_EQ(name, name_end, "D") ||
+	    STR_STRICT_EQ(name, name_end, "e"))
+		return 0;
+
+	/*
+	 * We're sure we're a named mode at that point, iterate over the
+	 * list of modes we're aware of.
+	 */
+	for (i = 0; i < ARRAY_SIZE(drm_named_modes_whitelist); i++) {
+		int ret;
+
+		ret = str_has_prefix(name, drm_named_modes_whitelist[i]);
+		if (ret != name_end)
+			continue;
+
+		strcpy(cmdline_mode->name, drm_named_modes_whitelist[i]);
+		cmdline_mode->specified = true;
+
+		return 1;
+	}
+
+	return -EINVAL;
+}
+
 /**
  * drm_mode_parse_command_line_for_connector - parse command line modeline for connector
  * @mode_option: optional per connector mode option
@@ -2244,7 +2293,7 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
 	const char *bpp_ptr = NULL, *refresh_ptr = NULL, *extra_ptr = NULL;
 	const char *options_ptr = NULL;
 	char *bpp_end_ptr = NULL, *refresh_end_ptr = NULL;
-	int i, len, ret;
+	int len, ret;
 
 	memset(mode, 0, sizeof(*mode));
 	mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_UNKNOWN;
@@ -2285,17 +2334,19 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
 		parse_extras = true;
 	}
 
-	/* First check for a named mode */
-	for (i = 0; i < ARRAY_SIZE(drm_named_modes_whitelist); i++) {
-		ret = str_has_prefix(name, drm_named_modes_whitelist[i]);
-		if (ret == mode_end) {
-			if (refresh_ptr)
-				return false; /* named + refresh is invalid */
 
-			strcpy(mode->name, drm_named_modes_whitelist[i]);
-			mode->specified = true;
-			break;
-		}
+	if (mode_end) {
+		ret = drm_mode_parse_cmdline_named_mode(name, mode_end, mode);
+		if (ret < 0)
+			return false;
+
+		/*
+		 * Having a mode that starts by a letter (and thus is named)
+		 * and an at-sign (used to specify a refresh rate) is
+		 * disallowed.
+		 */
+		if (ret && refresh_ptr)
+			return false;
 	}
 
 	/* No named mode? Check for a normal mode argument, e.g. 1024x768 */

-- 
b4 0.10.0-dev-65ba7

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

* [PATCH v2 15/41] drm/modes: Switch to named mode descriptors
  2022-08-29 13:11 [PATCH v2 00/41] drm: Analog TV Improvements Maxime Ripard
                   ` (13 preceding siblings ...)
  2022-08-29 13:11 ` [PATCH v2 14/41] drm/modes: Move named modes parsing to a separate function Maxime Ripard
@ 2022-08-29 13:11 ` Maxime Ripard
  2022-08-29 13:11 ` [PATCH v2 16/41] drm/modes: Fill drm_cmdline mode from named modes Maxime Ripard
                   ` (26 subsequent siblings)
  41 siblings, 0 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-08-29 13:11 UTC (permalink / raw)
  To: Maxime Ripard, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec,
	Samuel Holland, Karol Herbst, Noralf Trønnes, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Maxime Ripard, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

The current named mode parsing relies only the mode name, and doesn't allow
to specify any other parameter.

Let's convert that string list to an array of a custom structure that will
hold the name and some additional parameters in the future.

Signed-off-by: Maxime Ripard <maxime@cerno.tech>

diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index 0636cb707544..1fdfa004b139 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -2206,9 +2206,13 @@ static int drm_mode_parse_cmdline_options(const char *str,
 	return 0;
 }
 
-static const char * const drm_named_modes_whitelist[] = {
-	"NTSC",
-	"PAL",
+struct drm_named_mode {
+	const char *name;
+};
+
+static const struct drm_named_mode drm_named_modes[] = {
+	{ "NTSC", },
+	{ "PAL", },
 };
 
 static int drm_mode_parse_cmdline_named_mode(const char *name,
@@ -2241,14 +2245,15 @@ static int drm_mode_parse_cmdline_named_mode(const char *name,
 	 * We're sure we're a named mode at that point, iterate over the
 	 * list of modes we're aware of.
 	 */
-	for (i = 0; i < ARRAY_SIZE(drm_named_modes_whitelist); i++) {
+	for (i = 0; i < ARRAY_SIZE(drm_named_modes); i++) {
+		const struct drm_named_mode *mode = &drm_named_modes[i];
 		int ret;
 
-		ret = str_has_prefix(name, drm_named_modes_whitelist[i]);
+		ret = str_has_prefix(name, mode->name);
 		if (ret != name_end)
 			continue;
 
-		strcpy(cmdline_mode->name, drm_named_modes_whitelist[i]);
+		strcpy(cmdline_mode->name, mode->name);
 		cmdline_mode->specified = true;
 
 		return 1;

-- 
b4 0.10.0-dev-65ba7

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

* [PATCH v2 16/41] drm/modes: Fill drm_cmdline mode from named modes
  2022-08-29 13:11 [PATCH v2 00/41] drm: Analog TV Improvements Maxime Ripard
                   ` (14 preceding siblings ...)
  2022-08-29 13:11 ` [PATCH v2 15/41] drm/modes: Switch to named mode descriptors Maxime Ripard
@ 2022-08-29 13:11 ` Maxime Ripard
  2022-08-29 13:11 ` [PATCH v2 17/41] drm/connector: Add pixel clock to cmdline mode Maxime Ripard
                   ` (25 subsequent siblings)
  41 siblings, 0 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-08-29 13:11 UTC (permalink / raw)
  To: Maxime Ripard, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec,
	Samuel Holland, Karol Herbst, Noralf Trønnes, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Maxime Ripard, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

The current code to deal with named modes will only set the mode name, and
then it's up to drivers to try to match that name to whatever mode or
configuration they see fit.

The plan is to remove that need and move the named mode handling out of
drivers and into the core, and only rely on modes and properties. Let's
start by properly filling drm_cmdline_mode from a named mode.

Signed-off-by: Maxime Ripard <maxime@cerno.tech>

diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index 1fdfa004b139..5e898699b532 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -2208,11 +2208,22 @@ static int drm_mode_parse_cmdline_options(const char *str,
 
 struct drm_named_mode {
 	const char *name;
+	unsigned int xres;
+	unsigned int yres;
+	unsigned int flags;
 };
 
+#define NAMED_MODE(_name, _x, _y, _flags)		\
+	{						\
+		.name = _name,				\
+		.xres = _x,				\
+		.yres = _y,				\
+		.flags = _flags,			\
+	}
+
 static const struct drm_named_mode drm_named_modes[] = {
-	{ "NTSC", },
-	{ "PAL", },
+	NAMED_MODE("NTSC", 720, 480, DRM_MODE_FLAG_INTERLACE),
+	NAMED_MODE("PAL", 720, 576, DRM_MODE_FLAG_INTERLACE),
 };
 
 static int drm_mode_parse_cmdline_named_mode(const char *name,
@@ -2254,6 +2265,9 @@ static int drm_mode_parse_cmdline_named_mode(const char *name,
 			continue;
 
 		strcpy(cmdline_mode->name, mode->name);
+		cmdline_mode->xres = mode->xres;
+		cmdline_mode->yres = mode->yres;
+		cmdline_mode->interlace = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
 		cmdline_mode->specified = true;
 
 		return 1;

-- 
b4 0.10.0-dev-65ba7

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

* [PATCH v2 17/41] drm/connector: Add pixel clock to cmdline mode
  2022-08-29 13:11 [PATCH v2 00/41] drm: Analog TV Improvements Maxime Ripard
                   ` (15 preceding siblings ...)
  2022-08-29 13:11 ` [PATCH v2 16/41] drm/modes: Fill drm_cmdline mode from named modes Maxime Ripard
@ 2022-08-29 13:11 ` Maxime Ripard
  2022-08-29 13:11 ` [PATCH v2 18/41] drm/connector: Add a function to lookup a TV mode by its name Maxime Ripard
                   ` (24 subsequent siblings)
  41 siblings, 0 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-08-29 13:11 UTC (permalink / raw)
  To: Maxime Ripard, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec,
	Samuel Holland, Karol Herbst, Noralf Trønnes, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Maxime Ripard, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

We'll need to get the pixel clock to generate proper display modes for
all the current named modes. Let's add it to struct drm_cmdline_mode and
fill it when parsing the named mode.

Signed-off-by: Maxime Ripard <maxime@cerno.tech>

diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index 5e898699b532..73d01e755496 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -2208,22 +2208,24 @@ static int drm_mode_parse_cmdline_options(const char *str,
 
 struct drm_named_mode {
 	const char *name;
+	unsigned int pixel_clock_khz;
 	unsigned int xres;
 	unsigned int yres;
 	unsigned int flags;
 };
 
-#define NAMED_MODE(_name, _x, _y, _flags)		\
+#define NAMED_MODE(_name, _pclk, _x, _y, _flags)	\
 	{						\
 		.name = _name,				\
+		.pixel_clock_khz = _pclk,		\
 		.xres = _x,				\
 		.yres = _y,				\
 		.flags = _flags,			\
 	}
 
 static const struct drm_named_mode drm_named_modes[] = {
-	NAMED_MODE("NTSC", 720, 480, DRM_MODE_FLAG_INTERLACE),
-	NAMED_MODE("PAL", 720, 576, DRM_MODE_FLAG_INTERLACE),
+	NAMED_MODE("NTSC", 13500, 720, 480, DRM_MODE_FLAG_INTERLACE),
+	NAMED_MODE("PAL", 13500, 720, 576, DRM_MODE_FLAG_INTERLACE),
 };
 
 static int drm_mode_parse_cmdline_named_mode(const char *name,
@@ -2265,6 +2267,7 @@ static int drm_mode_parse_cmdline_named_mode(const char *name,
 			continue;
 
 		strcpy(cmdline_mode->name, mode->name);
+		cmdline_mode->pixel_clock = mode->pixel_clock_khz;
 		cmdline_mode->xres = mode->xres;
 		cmdline_mode->yres = mode->yres;
 		cmdline_mode->interlace = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index 7d3881f35e7c..bb39d2bb806e 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -1352,6 +1352,13 @@ struct drm_cmdline_mode {
 	 */
 	bool bpp_specified;
 
+	/**
+	 * @pixel_clock:
+	 *
+	 * Pixel Clock in kHz. Optional.
+	 */
+	unsigned int pixel_clock;
+
 	/**
 	 * @xres:
 	 *

-- 
b4 0.10.0-dev-65ba7

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

* [PATCH v2 18/41] drm/connector: Add a function to lookup a TV mode by its name
  2022-08-29 13:11 [PATCH v2 00/41] drm: Analog TV Improvements Maxime Ripard
                   ` (16 preceding siblings ...)
  2022-08-29 13:11 ` [PATCH v2 17/41] drm/connector: Add pixel clock to cmdline mode Maxime Ripard
@ 2022-08-29 13:11 ` Maxime Ripard
  2022-08-31 19:14   ` Noralf Trønnes
  2022-08-29 13:11 ` [PATCH v2 19/41] drm/modes: Introduce the tv_mode property as a command-line option Maxime Ripard
                   ` (23 subsequent siblings)
  41 siblings, 1 reply; 128+ messages in thread
From: Maxime Ripard @ 2022-08-29 13:11 UTC (permalink / raw)
  To: Maxime Ripard, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec,
	Samuel Holland, Karol Herbst, Noralf Trønnes, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Maxime Ripard, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

As part of the command line parsing rework coming in the next patches,
we'll need to lookup drm_connector_tv_mode values by their name, already
defined in drm_tv_mode_enum_list.

In order to avoid any code duplication, let's do a function that will
perform a lookup of a TV mode name and return its value.

Signed-off-by: Maxime Ripard <maxime@cerno.tech>

diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index b1fcacd150e8..0fe01a1c20ad 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -1003,6 +1003,30 @@ static const struct drm_prop_enum_list drm_tv_mode_enum_list[] = {
 };
 DRM_ENUM_NAME_FN(drm_get_tv_mode_name, drm_tv_mode_enum_list)
 
+/**
+ * drm_get_tv_mode_from_name - Translates a TV mode name into its enum value
+ * @name: TV Mode name we want to convert
+ * @len: Length of @name
+ *
+ * Translates @name into an enum drm_connector_tv_mode.
+ *
+ * Returns: the enum value on success, a negative errno otherwise.
+ */
+int drm_get_tv_mode_from_name(const char *name, size_t len)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(drm_tv_mode_enum_list); i++) {
+		const struct drm_prop_enum_list *item = &drm_tv_mode_enum_list[i];
+
+		if (strlen(item->name) == len && !strncmp(item->name, name, len))
+			return item->type;
+	}
+
+	return -EINVAL;
+}
+EXPORT_SYMBOL(drm_get_tv_mode_from_name)
+
 static const struct drm_prop_enum_list drm_tv_select_enum_list[] = {
 	{ DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */
 	{ DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index bb39d2bb806e..49d261977d4e 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -1943,6 +1943,8 @@ const char *drm_get_dp_subconnector_name(int val);
 const char *drm_get_content_protection_name(int val);
 const char *drm_get_hdcp_content_type_name(int val);
 
+int drm_get_tv_mode_from_name(const char *name, size_t len);
+
 int drm_mode_create_dvi_i_properties(struct drm_device *dev);
 void drm_connector_attach_dp_subconnector_property(struct drm_connector *connector);
 

-- 
b4 0.10.0-dev-65ba7

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

* [PATCH v2 19/41] drm/modes: Introduce the tv_mode property as a command-line option
  2022-08-29 13:11 [PATCH v2 00/41] drm: Analog TV Improvements Maxime Ripard
                   ` (17 preceding siblings ...)
  2022-08-29 13:11 ` [PATCH v2 18/41] drm/connector: Add a function to lookup a TV mode by its name Maxime Ripard
@ 2022-08-29 13:11 ` Maxime Ripard
  2022-08-30 12:34   ` Maíra Canal
                     ` (2 more replies)
  2022-08-29 13:11 ` [PATCH v2 20/41] drm/modes: Properly generate a drm_display_mode from a named mode Maxime Ripard
                   ` (22 subsequent siblings)
  41 siblings, 3 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-08-29 13:11 UTC (permalink / raw)
  To: Maxime Ripard, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec,
	Samuel Holland, Karol Herbst, Noralf Trønnes, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Maxime Ripard, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

Our new tv mode option allows to specify the TV mode from a property.
However, it can still be useful, for example to avoid any boot time
artifact, to set that property directly from the kernel command line.

Let's add some code to allow it, and some unit tests to exercise that code.

Signed-off-by: Maxime Ripard <maxime@cerno.tech>

diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index 73d01e755496..a759a4ba0036 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -2115,6 +2115,30 @@ static int drm_mode_parse_panel_orientation(const char *delim,
 	return 0;
 }
 
+static int drm_mode_parse_tv_mode(const char *delim,
+				  struct drm_cmdline_mode *mode)
+{
+	const char *value;
+	unsigned int len;
+	int ret;
+
+	if (*delim != '=')
+		return -EINVAL;
+
+	value = delim + 1;
+	delim = strchr(value, ',');
+	if (!delim)
+		delim = value + strlen(value);
+
+	ret = drm_get_tv_mode_from_name(value, delim - value);
+	if (ret < 0)
+		return ret;
+
+	mode->tv_mode = ret;
+
+	return 0;
+}
+
 static int drm_mode_parse_cmdline_options(const char *str,
 					  bool freestanding,
 					  const struct drm_connector *connector,
@@ -2184,6 +2208,9 @@ static int drm_mode_parse_cmdline_options(const char *str,
 		} else if (!strncmp(option, "panel_orientation", delim - option)) {
 			if (drm_mode_parse_panel_orientation(delim, mode))
 				return -EINVAL;
+		} else if (!strncmp(option, "tv_mode", delim - option)) {
+			if (drm_mode_parse_tv_mode(delim, mode))
+				return -EINVAL;
 		} else {
 			return -EINVAL;
 		}
@@ -2212,20 +2239,22 @@ struct drm_named_mode {
 	unsigned int xres;
 	unsigned int yres;
 	unsigned int flags;
+	unsigned int tv_mode;
 };
 
-#define NAMED_MODE(_name, _pclk, _x, _y, _flags)	\
+#define NAMED_MODE(_name, _pclk, _x, _y, _flags, _mode)	\
 	{						\
 		.name = _name,				\
 		.pixel_clock_khz = _pclk,		\
 		.xres = _x,				\
 		.yres = _y,				\
 		.flags = _flags,			\
+		.tv_mode = _mode,			\
 	}
 
 static const struct drm_named_mode drm_named_modes[] = {
-	NAMED_MODE("NTSC", 13500, 720, 480, DRM_MODE_FLAG_INTERLACE),
-	NAMED_MODE("PAL", 13500, 720, 576, DRM_MODE_FLAG_INTERLACE),
+	NAMED_MODE("NTSC", 13500, 720, 480, DRM_MODE_FLAG_INTERLACE, DRM_MODE_TV_MODE_NTSC_M),
+	NAMED_MODE("PAL", 13500, 720, 576, DRM_MODE_FLAG_INTERLACE, DRM_MODE_TV_MODE_PAL_B),
 };
 
 static int drm_mode_parse_cmdline_named_mode(const char *name,
@@ -2271,6 +2300,7 @@ static int drm_mode_parse_cmdline_named_mode(const char *name,
 		cmdline_mode->xres = mode->xres;
 		cmdline_mode->yres = mode->yres;
 		cmdline_mode->interlace = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
+		cmdline_mode->tv_mode = mode->tv_mode;
 		cmdline_mode->specified = true;
 
 		return 1;
diff --git a/drivers/gpu/drm/tests/drm_cmdline_parser_test.c b/drivers/gpu/drm/tests/drm_cmdline_parser_test.c
index 59b29cdfdd35..f1e73ed65be0 100644
--- a/drivers/gpu/drm/tests/drm_cmdline_parser_test.c
+++ b/drivers/gpu/drm/tests/drm_cmdline_parser_test.c
@@ -885,6 +885,201 @@ static void drm_cmdline_test_multiple_options(struct kunit *test)
 	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED);
 }
 
+static void drm_cmdline_test_tv_options(struct kunit *test,
+					const char *cmdline,
+					const struct drm_display_mode *expected_mode,
+					unsigned int expected_tv_mode)
+{
+	struct drm_cmdline_mode mode = { };
+
+	KUNIT_EXPECT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector, &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, expected_mode->hdisplay);
+	KUNIT_EXPECT_EQ(test, mode.yres, expected_mode->vdisplay);
+	KUNIT_EXPECT_EQ(test, mode.tv_mode, expected_tv_mode);
+
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
+
+	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
+
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_EQ(test, mode.interlace, !!(expected_mode->flags & DRM_MODE_FLAG_INTERLACE));
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED);
+}
+
+static void drm_cmdline_test_tv_option_ntsc_443(struct kunit *test)
+{
+	drm_cmdline_test_tv_options(test,
+				    "720x480i,tv_mode=NTSC-443",
+				    drm_mode_analog_ntsc_480i(NULL),
+				    DRM_MODE_TV_MODE_NTSC_443);
+}
+
+static void drm_cmdline_test_tv_option_ntsc_j(struct kunit *test)
+{
+	drm_cmdline_test_tv_options(test,
+				    "720x480i,tv_mode=NTSC-J",
+				    drm_mode_analog_ntsc_480i(NULL),
+				    DRM_MODE_TV_MODE_NTSC_J);
+}
+
+static void drm_cmdline_test_tv_option_ntsc_m(struct kunit *test)
+{
+	drm_cmdline_test_tv_options(test,
+				    "720x480i,tv_mode=NTSC-M",
+				    drm_mode_analog_ntsc_480i(NULL),
+				    DRM_MODE_TV_MODE_NTSC_M);
+}
+
+static void drm_cmdline_test_tv_option_pal_60(struct kunit *test)
+{
+	drm_cmdline_test_tv_options(test,
+				    "720x576i,tv_mode=PAL-60",
+				    drm_mode_analog_pal_576i(NULL),
+				    DRM_MODE_TV_MODE_PAL_60);
+}
+
+static void drm_cmdline_test_tv_option_pal_b(struct kunit *test)
+{
+	drm_cmdline_test_tv_options(test,
+				    "720x576i,tv_mode=PAL-B",
+				    drm_mode_analog_pal_576i(NULL),
+				    DRM_MODE_TV_MODE_PAL_B);
+}
+
+static void drm_cmdline_test_tv_option_pal_d(struct kunit *test)
+{
+	drm_cmdline_test_tv_options(test,
+				    "720x576i,tv_mode=PAL-D",
+				    drm_mode_analog_pal_576i(NULL),
+				    DRM_MODE_TV_MODE_PAL_D);
+}
+
+static void drm_cmdline_test_tv_option_pal_g(struct kunit *test)
+{
+	drm_cmdline_test_tv_options(test,
+				    "720x576i,tv_mode=PAL-G",
+				    drm_mode_analog_pal_576i(NULL),
+				    DRM_MODE_TV_MODE_PAL_G);
+}
+
+static void drm_cmdline_test_tv_option_pal_h(struct kunit *test)
+{
+	drm_cmdline_test_tv_options(test,
+				    "720x576i,tv_mode=PAL-H",
+				    drm_mode_analog_pal_576i(NULL),
+				    DRM_MODE_TV_MODE_PAL_H);
+}
+
+static void drm_cmdline_test_tv_option_pal_i(struct kunit *test)
+{
+	drm_cmdline_test_tv_options(test,
+				    "720x576i,tv_mode=PAL-I",
+				    drm_mode_analog_pal_576i(NULL),
+				    DRM_MODE_TV_MODE_PAL_I);
+}
+
+static void drm_cmdline_test_tv_option_pal_m(struct kunit *test)
+{
+	drm_cmdline_test_tv_options(test,
+				    "720x480i,tv_mode=PAL-M",
+				    drm_mode_analog_ntsc_480i(NULL),
+				    DRM_MODE_TV_MODE_PAL_M);
+}
+
+static void drm_cmdline_test_tv_option_pal_n(struct kunit *test)
+{
+	drm_cmdline_test_tv_options(test,
+				    "720x576i,tv_mode=PAL-N",
+				    drm_mode_analog_pal_576i(NULL),
+				    DRM_MODE_TV_MODE_PAL_N);
+}
+
+static void drm_cmdline_test_tv_option_pal_nc(struct kunit *test)
+{
+	drm_cmdline_test_tv_options(test,
+				    "720x576i,tv_mode=PAL-Nc",
+				    drm_mode_analog_pal_576i(NULL),
+				    DRM_MODE_TV_MODE_PAL_NC);
+}
+
+static void drm_cmdline_test_tv_option_secam_60(struct kunit *test)
+{
+	drm_cmdline_test_tv_options(test,
+				    "720x576i,tv_mode=SECAM-60",
+				    drm_mode_analog_pal_576i(NULL),
+				    DRM_MODE_TV_MODE_SECAM_60);
+}
+
+static void drm_cmdline_test_tv_option_secam_b(struct kunit *test)
+{
+	drm_cmdline_test_tv_options(test,
+				    "720x576i,tv_mode=SECAM-B",
+				    drm_mode_analog_pal_576i(NULL),
+				    DRM_MODE_TV_MODE_SECAM_B);
+}
+
+static void drm_cmdline_test_tv_option_secam_d(struct kunit *test)
+{
+	drm_cmdline_test_tv_options(test,
+				    "720x576i,tv_mode=SECAM-D",
+				    drm_mode_analog_pal_576i(NULL),
+				    DRM_MODE_TV_MODE_SECAM_D);
+}
+
+static void drm_cmdline_test_tv_option_secam_g(struct kunit *test)
+{
+	drm_cmdline_test_tv_options(test,
+				    "720x576i,tv_mode=SECAM-G",
+				    drm_mode_analog_pal_576i(NULL),
+				    DRM_MODE_TV_MODE_SECAM_G);
+}
+
+static void drm_cmdline_test_tv_option_secam_k(struct kunit *test)
+{
+	drm_cmdline_test_tv_options(test,
+				    "720x576i,tv_mode=SECAM-K",
+				    drm_mode_analog_pal_576i(NULL),
+				    DRM_MODE_TV_MODE_SECAM_K);
+}
+
+static void drm_cmdline_test_tv_option_secam_k1(struct kunit *test)
+{
+	drm_cmdline_test_tv_options(test,
+				    "720x576i,tv_mode=SECAM-K1",
+				    drm_mode_analog_pal_576i(NULL),
+				    DRM_MODE_TV_MODE_SECAM_K1);
+}
+
+static void drm_cmdline_test_tv_option_secam_l(struct kunit *test)
+{
+	drm_cmdline_test_tv_options(test,
+				    "720x576i,tv_mode=SECAM-L",
+				    drm_mode_analog_pal_576i(NULL),
+				    DRM_MODE_TV_MODE_SECAM_L);
+}
+
+static void drm_cmdline_test_tv_option_invalid(struct kunit *test)
+{
+	struct drm_cmdline_mode mode = { };
+	const char *cmdline = "720x480i,tv_mode=invalid";
+
+	KUNIT_EXPECT_FALSE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									   &no_connector, &mode));
+}
+
+static void drm_cmdline_test_tv_option_truncated(struct kunit *test)
+{
+	struct drm_cmdline_mode mode = { };
+	const char *cmdline = "720x480i,tv_mode=NTSC";
+
+	KUNIT_EXPECT_FALSE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									   &no_connector, &mode));
+}
+
 static void drm_cmdline_test_invalid_option(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
@@ -1047,6 +1242,27 @@ static struct kunit_case drm_cmdline_parser_tests[] = {
 	KUNIT_CASE(drm_cmdline_test_name_refresh_invalid_mode),
 	KUNIT_CASE(drm_cmdline_test_name_option),
 	KUNIT_CASE(drm_cmdline_test_name_bpp_option),
+	KUNIT_CASE(drm_cmdline_test_tv_option_ntsc_443),
+	KUNIT_CASE(drm_cmdline_test_tv_option_ntsc_j),
+	KUNIT_CASE(drm_cmdline_test_tv_option_ntsc_m),
+	KUNIT_CASE(drm_cmdline_test_tv_option_pal_60),
+	KUNIT_CASE(drm_cmdline_test_tv_option_pal_b),
+	KUNIT_CASE(drm_cmdline_test_tv_option_pal_d),
+	KUNIT_CASE(drm_cmdline_test_tv_option_pal_g),
+	KUNIT_CASE(drm_cmdline_test_tv_option_pal_h),
+	KUNIT_CASE(drm_cmdline_test_tv_option_pal_i),
+	KUNIT_CASE(drm_cmdline_test_tv_option_pal_m),
+	KUNIT_CASE(drm_cmdline_test_tv_option_pal_n),
+	KUNIT_CASE(drm_cmdline_test_tv_option_pal_nc),
+	KUNIT_CASE(drm_cmdline_test_tv_option_secam_60),
+	KUNIT_CASE(drm_cmdline_test_tv_option_secam_b),
+	KUNIT_CASE(drm_cmdline_test_tv_option_secam_d),
+	KUNIT_CASE(drm_cmdline_test_tv_option_secam_g),
+	KUNIT_CASE(drm_cmdline_test_tv_option_secam_k),
+	KUNIT_CASE(drm_cmdline_test_tv_option_secam_k1),
+	KUNIT_CASE(drm_cmdline_test_tv_option_secam_l),
+	KUNIT_CASE(drm_cmdline_test_tv_option_invalid),
+	KUNIT_CASE(drm_cmdline_test_tv_option_truncated),
 	KUNIT_CASE(drm_cmdline_test_rotate_0),
 	KUNIT_CASE(drm_cmdline_test_rotate_90),
 	KUNIT_CASE(drm_cmdline_test_rotate_180),
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index 49d261977d4e..9589108ba202 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -1447,6 +1447,11 @@ struct drm_cmdline_mode {
 	 * @tv_margins: TV margins to apply to the mode.
 	 */
 	struct drm_connector_tv_margins tv_margins;
+
+	/**
+	 * @tv_mode: TV mode standard. See DRM_MODE_TV_MODE_*.
+	 */
+	enum drm_connector_tv_mode tv_mode;
 };
 
 /**

-- 
b4 0.10.0-dev-65ba7

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

* [PATCH v2 20/41] drm/modes: Properly generate a drm_display_mode from a named mode
  2022-08-29 13:11 [PATCH v2 00/41] drm: Analog TV Improvements Maxime Ripard
                   ` (18 preceding siblings ...)
  2022-08-29 13:11 ` [PATCH v2 19/41] drm/modes: Introduce the tv_mode property as a command-line option Maxime Ripard
@ 2022-08-29 13:11 ` Maxime Ripard
  2022-09-01 22:52   ` Mateusz Kwiatkowski
  2022-08-29 13:11 ` [PATCH v2 21/41] drm/modes: Introduce more named modes Maxime Ripard
                   ` (21 subsequent siblings)
  41 siblings, 1 reply; 128+ messages in thread
From: Maxime Ripard @ 2022-08-29 13:11 UTC (permalink / raw)
  To: Maxime Ripard, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec,
	Samuel Holland, Karol Herbst, Noralf Trønnes, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Maxime Ripard, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

The framework will get the drm_display_mode from the drm_cmdline_mode it
got by parsing the video command line argument by calling
drm_connector_pick_cmdline_mode().

The heavy lifting will then be done by the drm_mode_create_from_cmdline_mode()
function.

In the case of the named modes though, there's no real code to make that
translation and we rely on the drivers to guess which actual display mode
we meant.

Let's modify drm_mode_create_from_cmdline_mode() to properly generate the
drm_display_mode we mean when passing a named mode.

Signed-off-by: Maxime Ripard <maxime@cerno.tech>

diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index a759a4ba0036..065dbfbd815e 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -2480,6 +2480,36 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
 }
 EXPORT_SYMBOL(drm_mode_parse_command_line_for_connector);
 
+static struct drm_display_mode *drm_named_mode(struct drm_device *dev,
+					       struct drm_cmdline_mode *cmd)
+{
+	struct drm_display_mode *mode;
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(drm_named_modes); i++) {
+		const struct drm_named_mode *named_mode = &drm_named_modes[i];
+
+		if (strcmp(cmd->name, named_mode->name))
+			continue;
+
+		if (!named_mode->tv_mode)
+			continue;
+
+		mode = drm_analog_tv_mode(dev,
+					  named_mode->tv_mode,
+					  named_mode->pixel_clock_khz * 1000,
+					  named_mode->xres,
+					  named_mode->yres,
+					  named_mode->flags & DRM_MODE_FLAG_INTERLACE);
+		if (!mode)
+			return NULL;
+
+		return mode;
+	}
+
+	return NULL;
+}
+
 /**
  * drm_mode_create_from_cmdline_mode - convert a command line modeline into a DRM display mode
  * @dev: DRM device to create the new mode for
@@ -2497,7 +2527,9 @@ drm_mode_create_from_cmdline_mode(struct drm_device *dev,
 	if (cmd->xres == 0 || cmd->yres == 0)
 		return NULL;
 
-	if (cmd->cvt)
+	if (strlen(cmd->name))
+		mode = drm_named_mode(dev, cmd);
+	else if (cmd->cvt)
 		mode = drm_cvt_mode(dev,
 				    cmd->xres, cmd->yres,
 				    cmd->refresh_specified ? cmd->refresh : 60,
diff --git a/drivers/gpu/drm/tests/drm_client_modeset_test.c b/drivers/gpu/drm/tests/drm_client_modeset_test.c
index 46335de7bc6b..4380cf670fb4 100644
--- a/drivers/gpu/drm/tests/drm_client_modeset_test.c
+++ b/drivers/gpu/drm/tests/drm_client_modeset_test.c
@@ -26,6 +26,20 @@ static int drm_client_modeset_connector_get_modes(struct drm_connector *connecto
 
 	count = drm_add_modes_noedid(connector, 1920, 1200);
 
+	mode = drm_mode_analog_ntsc_480i(connector->dev);
+	if (!mode)
+		return -ENOMEM;
+
+	drm_mode_probed_add(connector, mode);
+	count += 1;
+
+	mode = drm_mode_analog_pal_576i(connector->dev);
+	if (!mode)
+		return -ENOMEM;
+
+	drm_mode_probed_add(connector, mode);
+	count += 1;
+
 	return count;
 }
 
@@ -58,6 +72,9 @@ static int drm_client_modeset_test_init(struct kunit *test)
 		return ret;
 	drm_connector_helper_add(&priv->connector, &drm_client_modeset_connector_helper_funcs);
 
+	priv->connector.interlace_allowed = true;
+	priv->connector.doublescan_allowed = true;
+
 	return 0;
 }
 
@@ -97,8 +114,62 @@ static void drm_pick_cmdline_res_1920_1080_60(struct kunit *test)
 	KUNIT_EXPECT_TRUE(test, drm_mode_equal(expected_mode, mode));
 }
 
+static void drm_pick_cmdline_named_ntsc(struct kunit *test)
+{
+	struct drm_client_modeset_test_priv *priv = test->priv;
+	struct drm_device *drm = priv->drm;
+	struct drm_connector *connector = &priv->connector;
+	struct drm_cmdline_mode *cmdline_mode = &connector->cmdline_mode;
+	struct drm_display_mode *mode;
+	const char *cmdline = "NTSC";
+	int ret;
+
+	KUNIT_ASSERT_TRUE(test,
+			  drm_mode_parse_command_line_for_connector(cmdline,
+								    connector,
+								    cmdline_mode));
+
+	mutex_lock(&drm->mode_config.mutex);
+	ret = drm_helper_probe_single_connector_modes(connector, 1920, 1080);
+	mutex_unlock(&drm->mode_config.mutex);
+	KUNIT_ASSERT_GT(test, ret, 0);
+
+	mode = drm_connector_pick_cmdline_mode(connector);
+	KUNIT_ASSERT_PTR_NE(test, mode, NULL);
+
+	KUNIT_EXPECT_TRUE(test, drm_mode_equal(drm_mode_analog_ntsc_480i(drm), mode));
+}
+
+static void drm_pick_cmdline_named_pal(struct kunit *test)
+{
+	struct drm_client_modeset_test_priv *priv = test->priv;
+	struct drm_device *drm = priv->drm;
+	struct drm_connector *connector = &priv->connector;
+	struct drm_cmdline_mode *cmdline_mode = &connector->cmdline_mode;
+	struct drm_display_mode *mode;
+	const char *cmdline = "PAL";
+	int ret;
+
+	KUNIT_ASSERT_TRUE(test,
+			  drm_mode_parse_command_line_for_connector(cmdline,
+								    connector,
+								    cmdline_mode));
+
+	mutex_lock(&drm->mode_config.mutex);
+	ret = drm_helper_probe_single_connector_modes(connector, 1920, 1080);
+	mutex_unlock(&drm->mode_config.mutex);
+	KUNIT_ASSERT_GT(test, ret, 0);
+
+	mode = drm_connector_pick_cmdline_mode(connector);
+	KUNIT_ASSERT_PTR_NE(test, mode, NULL);
+
+	KUNIT_EXPECT_TRUE(test, drm_mode_equal(drm_mode_analog_pal_576i(drm), mode));
+}
+
 static struct kunit_case drm_pick_cmdline_tests[] = {
 	KUNIT_CASE(drm_pick_cmdline_res_1920_1080_60),
+	KUNIT_CASE(drm_pick_cmdline_named_ntsc),
+	KUNIT_CASE(drm_pick_cmdline_named_pal),
 	{}
 };
 

-- 
b4 0.10.0-dev-65ba7

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

* [PATCH v2 21/41] drm/modes: Introduce more named modes
  2022-08-29 13:11 [PATCH v2 00/41] drm: Analog TV Improvements Maxime Ripard
                   ` (19 preceding siblings ...)
  2022-08-29 13:11 ` [PATCH v2 20/41] drm/modes: Properly generate a drm_display_mode from a named mode Maxime Ripard
@ 2022-08-29 13:11 ` Maxime Ripard
  2022-08-29 13:11 ` [PATCH v2 22/41] drm/atomic-helper: Add a TV properties reset helper Maxime Ripard
                   ` (20 subsequent siblings)
  41 siblings, 0 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-08-29 13:11 UTC (permalink / raw)
  To: Maxime Ripard, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec,
	Samuel Holland, Karol Herbst, Noralf Trønnes, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Maxime Ripard, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

Now that we can easily extend the named modes list, let's add a few more
analog TV modes that were used in the wild, and some unit tests to make
sure it works as intended.

Signed-off-by: Maxime Ripard <maxime@cerno.tech>

diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index 065dbfbd815e..7d769de4d31b 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -2254,7 +2254,9 @@ struct drm_named_mode {
 
 static const struct drm_named_mode drm_named_modes[] = {
 	NAMED_MODE("NTSC", 13500, 720, 480, DRM_MODE_FLAG_INTERLACE, DRM_MODE_TV_MODE_NTSC_M),
+	NAMED_MODE("NTSC_J", 13500, 720, 480, DRM_MODE_FLAG_INTERLACE, DRM_MODE_TV_MODE_NTSC_J),
 	NAMED_MODE("PAL", 13500, 720, 576, DRM_MODE_FLAG_INTERLACE, DRM_MODE_TV_MODE_PAL_B),
+	NAMED_MODE("PAL_M", 13500, 720, 480, DRM_MODE_FLAG_INTERLACE, DRM_MODE_TV_MODE_PAL_M),
 };
 
 static int drm_mode_parse_cmdline_named_mode(const char *name,
diff --git a/drivers/gpu/drm/tests/drm_client_modeset_test.c b/drivers/gpu/drm/tests/drm_client_modeset_test.c
index 4380cf670fb4..d6ecb5fbe159 100644
--- a/drivers/gpu/drm/tests/drm_client_modeset_test.c
+++ b/drivers/gpu/drm/tests/drm_client_modeset_test.c
@@ -140,6 +140,32 @@ static void drm_pick_cmdline_named_ntsc(struct kunit *test)
 	KUNIT_EXPECT_TRUE(test, drm_mode_equal(drm_mode_analog_ntsc_480i(drm), mode));
 }
 
+static void drm_pick_cmdline_named_ntsc_j(struct kunit *test)
+{
+	struct drm_client_modeset_test_priv *priv = test->priv;
+	struct drm_device *drm = priv->drm;
+	struct drm_connector *connector = &priv->connector;
+	struct drm_cmdline_mode *cmdline_mode = &connector->cmdline_mode;
+	struct drm_display_mode *mode;
+	const char *cmdline = "NTSC_J";
+	int ret;
+
+	KUNIT_ASSERT_TRUE(test,
+			  drm_mode_parse_command_line_for_connector(cmdline,
+								    connector,
+								    cmdline_mode));
+
+	mutex_lock(&drm->mode_config.mutex);
+	ret = drm_helper_probe_single_connector_modes(connector, 1920, 1080);
+	mutex_unlock(&drm->mode_config.mutex);
+	KUNIT_ASSERT_GT(test, ret, 0);
+
+	mode = drm_connector_pick_cmdline_mode(connector);
+	KUNIT_ASSERT_PTR_NE(test, mode, NULL);
+
+	KUNIT_EXPECT_TRUE(test, drm_mode_equal(drm_mode_analog_ntsc_480i(drm), mode));
+}
+
 static void drm_pick_cmdline_named_pal(struct kunit *test)
 {
 	struct drm_client_modeset_test_priv *priv = test->priv;
@@ -166,10 +192,38 @@ static void drm_pick_cmdline_named_pal(struct kunit *test)
 	KUNIT_EXPECT_TRUE(test, drm_mode_equal(drm_mode_analog_pal_576i(drm), mode));
 }
 
+static void drm_pick_cmdline_named_pal_m(struct kunit *test)
+{
+	struct drm_client_modeset_test_priv *priv = test->priv;
+	struct drm_device *drm = priv->drm;
+	struct drm_connector *connector = &priv->connector;
+	struct drm_cmdline_mode *cmdline_mode = &connector->cmdline_mode;
+	struct drm_display_mode *mode;
+	const char *cmdline = "PAL_M";
+	int ret;
+
+	KUNIT_ASSERT_TRUE(test,
+			  drm_mode_parse_command_line_for_connector(cmdline,
+								    connector,
+								    cmdline_mode));
+
+	mutex_lock(&drm->mode_config.mutex);
+	ret = drm_helper_probe_single_connector_modes(connector, 1920, 1080);
+	mutex_unlock(&drm->mode_config.mutex);
+	KUNIT_ASSERT_GT(test, ret, 0);
+
+	mode = drm_connector_pick_cmdline_mode(connector);
+	KUNIT_ASSERT_PTR_NE(test, mode, NULL);
+
+	KUNIT_EXPECT_TRUE(test, drm_mode_equal(drm_mode_analog_ntsc_480i(drm), mode));
+}
+
 static struct kunit_case drm_pick_cmdline_tests[] = {
 	KUNIT_CASE(drm_pick_cmdline_res_1920_1080_60),
 	KUNIT_CASE(drm_pick_cmdline_named_ntsc),
+	KUNIT_CASE(drm_pick_cmdline_named_ntsc_j),
 	KUNIT_CASE(drm_pick_cmdline_named_pal),
+	KUNIT_CASE(drm_pick_cmdline_named_pal_m),
 	{}
 };
 

-- 
b4 0.10.0-dev-65ba7

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

* [PATCH v2 22/41] drm/atomic-helper: Add a TV properties reset helper
  2022-08-29 13:11 [PATCH v2 00/41] drm: Analog TV Improvements Maxime Ripard
                   ` (20 preceding siblings ...)
  2022-08-29 13:11 ` [PATCH v2 21/41] drm/modes: Introduce more named modes Maxime Ripard
@ 2022-08-29 13:11 ` Maxime Ripard
  2022-08-30 18:40   ` Noralf Trønnes
  2022-08-29 13:11 ` [PATCH v2 23/41] drm/atomic-helper: Add an analog TV atomic_check implementation Maxime Ripard
                   ` (19 subsequent siblings)
  41 siblings, 1 reply; 128+ messages in thread
From: Maxime Ripard @ 2022-08-29 13:11 UTC (permalink / raw)
  To: Maxime Ripard, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec,
	Samuel Holland, Karol Herbst, Noralf Trønnes, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Maxime Ripard, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

The drm_tv_create_properties() function will create a bunch of properties,
but it's up to each and every driver using that function to properly reset
the state of these properties leading to inconsistent behaviours.

Let's create a helper that will take care of it.

Signed-off-by: Maxime Ripard <maxime@cerno.tech>

diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c
index dfb57217253b..0373c3dc824b 100644
--- a/drivers/gpu/drm/drm_atomic_state_helper.c
+++ b/drivers/gpu/drm/drm_atomic_state_helper.c
@@ -481,6 +481,81 @@ void drm_atomic_helper_connector_tv_margins_reset(struct drm_connector *connecto
 }
 EXPORT_SYMBOL(drm_atomic_helper_connector_tv_margins_reset);
 
+/**
+ * drm_atomic_helper_connector_tv_reset - Resets Analog TV connector properties
+ * @connector: DRM connector
+ *
+ * Resets the analog TV properties attached to a connector
+ */
+void drm_atomic_helper_connector_tv_reset(struct drm_connector *connector)
+{
+	struct drm_device *dev = connector->dev;
+	struct drm_cmdline_mode *cmdline = &connector->cmdline_mode;
+	struct drm_connector_state *state = connector->state;
+	struct drm_property *prop;
+	uint64_t val;
+
+	prop = dev->mode_config.tv_mode_property;
+	if (prop)
+		if (!drm_object_property_get_default_value(&connector->base,
+							   prop, &val))
+			state->tv.mode = val;
+
+	if (cmdline->tv_mode)
+		state->tv.mode = cmdline->tv_mode;
+
+	prop = dev->mode_config.tv_select_subconnector_property;
+	if (prop)
+		if (!drm_object_property_get_default_value(&connector->base,
+							   prop, &val))
+			state->tv.select_subconnector = val;
+
+	prop = dev->mode_config.tv_subconnector_property;
+	if (prop)
+		if (!drm_object_property_get_default_value(&connector->base,
+							   prop, &val))
+			state->tv.subconnector = val;
+
+	prop = dev->mode_config.tv_brightness_property;
+	if (prop)
+		if (!drm_object_property_get_default_value(&connector->base,
+							   prop, &val))
+			state->tv.brightness = val;
+
+	prop = dev->mode_config.tv_contrast_property;
+	if (prop)
+		if (!drm_object_property_get_default_value(&connector->base,
+							   prop, &val))
+			state->tv.contrast = val;
+
+	prop = dev->mode_config.tv_flicker_reduction_property;
+	if (prop)
+		if (!drm_object_property_get_default_value(&connector->base,
+							   prop, &val))
+			state->tv.flicker_reduction = val;
+
+	prop = dev->mode_config.tv_overscan_property;
+	if (prop)
+		if (!drm_object_property_get_default_value(&connector->base,
+							   prop, &val))
+			state->tv.overscan = val;
+
+	prop = dev->mode_config.tv_saturation_property;
+	if (prop)
+		if (!drm_object_property_get_default_value(&connector->base,
+							   prop, &val))
+			state->tv.saturation = val;
+
+	prop = dev->mode_config.tv_hue_property;
+	if (prop)
+		if (!drm_object_property_get_default_value(&connector->base,
+							   prop, &val))
+			state->tv.hue = val;
+
+	drm_atomic_helper_connector_tv_margins_reset(connector);
+}
+EXPORT_SYMBOL(drm_atomic_helper_connector_tv_reset);
+
 /**
  * __drm_atomic_helper_connector_duplicate_state - copy atomic connector state
  * @connector: connector object
diff --git a/include/drm/drm_atomic_state_helper.h b/include/drm/drm_atomic_state_helper.h
index 192766656b88..c8fbce795ee7 100644
--- a/include/drm/drm_atomic_state_helper.h
+++ b/include/drm/drm_atomic_state_helper.h
@@ -70,6 +70,7 @@ void __drm_atomic_helper_connector_state_reset(struct drm_connector_state *conn_
 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_tv_margins_reset(struct drm_connector *connector);
 void
 __drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector,

-- 
b4 0.10.0-dev-65ba7

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

* [PATCH v2 23/41] drm/atomic-helper: Add an analog TV atomic_check implementation
  2022-08-29 13:11 [PATCH v2 00/41] drm: Analog TV Improvements Maxime Ripard
                   ` (21 preceding siblings ...)
  2022-08-29 13:11 ` [PATCH v2 22/41] drm/atomic-helper: Add a TV properties reset helper Maxime Ripard
@ 2022-08-29 13:11 ` Maxime Ripard
  2022-08-30 18:49   ` Noralf Trønnes
  2022-08-29 13:11 ` [PATCH v2 24/41] drm/vc4: vec: Remove empty mode_fixup Maxime Ripard
                   ` (18 subsequent siblings)
  41 siblings, 1 reply; 128+ messages in thread
From: Maxime Ripard @ 2022-08-29 13:11 UTC (permalink / raw)
  To: Maxime Ripard, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec,
	Samuel Holland, Karol Herbst, Noralf Trønnes, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Maxime Ripard, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

The analog TV connector drivers share some atomic_check logic, and the new
TV standard property have created a bunch of new constraints that needs to
be shared across drivers too.

Let's create an atomic_check helper for those use cases.

Signed-off-by: Maxime Ripard <maxime@cerno.tech>

diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c
index 0373c3dc824b..d64733c6aae3 100644
--- a/drivers/gpu/drm/drm_atomic_state_helper.c
+++ b/drivers/gpu/drm/drm_atomic_state_helper.c
@@ -556,6 +556,42 @@ void drm_atomic_helper_connector_tv_reset(struct drm_connector *connector)
 }
 EXPORT_SYMBOL(drm_atomic_helper_connector_tv_reset);
 
+/**
+ * @drm_atomic_helper_connector_tv_check: Validate an analog TV connector state
+ * @connector: DRM Connector
+ * @state: the DRM State object
+ *
+ * Checks the state object to see if the requested state is valid for an
+ * analog TV connector.
+ *
+ * Returns:
+ * Zero for success, a negative error code on error.
+ */
+int drm_atomic_helper_connector_tv_check(struct drm_connector *connector,
+					 struct drm_atomic_state *state)
+{
+	struct drm_connector_state *old_conn_state =
+		drm_atomic_get_old_connector_state(state, connector);
+	struct drm_connector_state *new_conn_state =
+		drm_atomic_get_new_connector_state(state, connector);
+	struct drm_crtc_state *crtc_state;
+	struct drm_crtc *crtc;
+
+	crtc = new_conn_state->crtc;
+	if (!crtc)
+		return 0;
+
+	crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
+	if (!crtc_state)
+		return -EINVAL;
+
+	if (old_conn_state->tv.mode != new_conn_state->tv.mode)
+		crtc_state->mode_changed = true;
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_atomic_helper_connector_tv_check);
+
 /**
  * __drm_atomic_helper_connector_duplicate_state - copy atomic connector state
  * @connector: connector object
diff --git a/include/drm/drm_atomic_state_helper.h b/include/drm/drm_atomic_state_helper.h
index c8fbce795ee7..b9740edb2658 100644
--- a/include/drm/drm_atomic_state_helper.h
+++ b/include/drm/drm_atomic_state_helper.h
@@ -26,6 +26,7 @@
 
 #include <linux/types.h>
 
+struct drm_atomic_state;
 struct drm_bridge;
 struct drm_bridge_state;
 struct drm_crtc;
@@ -71,6 +72,8 @@ 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);
+int drm_atomic_helper_connector_tv_check(struct drm_connector *connector,
+					 struct drm_atomic_state *state);
 void drm_atomic_helper_connector_tv_margins_reset(struct drm_connector *connector);
 void
 __drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector,

-- 
b4 0.10.0-dev-65ba7

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

* [PATCH v2 24/41] drm/vc4: vec: Remove empty mode_fixup
  2022-08-29 13:11 [PATCH v2 00/41] drm: Analog TV Improvements Maxime Ripard
                   ` (22 preceding siblings ...)
  2022-08-29 13:11 ` [PATCH v2 23/41] drm/atomic-helper: Add an analog TV atomic_check implementation Maxime Ripard
@ 2022-08-29 13:11 ` Maxime Ripard
  2022-08-30 15:23   ` Noralf Trønnes
  2022-09-07  8:34   ` (subset) " Maxime Ripard
  2022-08-29 13:11 ` [PATCH v2 25/41] drm/vc4: vec: Convert to atomic helpers Maxime Ripard
                   ` (17 subsequent siblings)
  41 siblings, 2 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-08-29 13:11 UTC (permalink / raw)
  To: Maxime Ripard, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec,
	Samuel Holland, Karol Herbst, Noralf Trønnes, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Maxime Ripard, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

The mode_fixup hooks are deprecated, and the behaviour we implement is the
default one anyway. Let's remove it.

Signed-off-by: Maxime Ripard <maxime@cerno.tech>

diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c
index d5140fe0be4f..d521ffd8d75c 100644
--- a/drivers/gpu/drm/vc4/vc4_vec.c
+++ b/drivers/gpu/drm/vc4/vc4_vec.c
@@ -483,14 +483,6 @@ static void vc4_vec_encoder_enable(struct drm_encoder *encoder)
 	drm_dev_exit(idx);
 }
 
-
-static bool vc4_vec_encoder_mode_fixup(struct drm_encoder *encoder,
-				       const struct drm_display_mode *mode,
-				       struct drm_display_mode *adjusted_mode)
-{
-	return true;
-}
-
 static void vc4_vec_encoder_atomic_mode_set(struct drm_encoder *encoder,
 					struct drm_crtc_state *crtc_state,
 					struct drm_connector_state *conn_state)
@@ -518,7 +510,6 @@ static int vc4_vec_encoder_atomic_check(struct drm_encoder *encoder,
 static const struct drm_encoder_helper_funcs vc4_vec_encoder_helper_funcs = {
 	.disable = vc4_vec_encoder_disable,
 	.enable = vc4_vec_encoder_enable,
-	.mode_fixup = vc4_vec_encoder_mode_fixup,
 	.atomic_check = vc4_vec_encoder_atomic_check,
 	.atomic_mode_set = vc4_vec_encoder_atomic_mode_set,
 };

-- 
b4 0.10.0-dev-65ba7

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

* [PATCH v2 25/41] drm/vc4: vec: Convert to atomic helpers
  2022-08-29 13:11 [PATCH v2 00/41] drm: Analog TV Improvements Maxime Ripard
                   ` (23 preceding siblings ...)
  2022-08-29 13:11 ` [PATCH v2 24/41] drm/vc4: vec: Remove empty mode_fixup Maxime Ripard
@ 2022-08-29 13:11 ` Maxime Ripard
  2022-08-30 15:24   ` Noralf Trønnes
  2022-09-07  8:35   ` (subset) " Maxime Ripard
  2022-08-29 13:11 ` [PATCH v2 26/41] drm/vc4: vec: Refactor VEC TV mode setting Maxime Ripard
                   ` (16 subsequent siblings)
  41 siblings, 2 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-08-29 13:11 UTC (permalink / raw)
  To: Maxime Ripard, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec,
	Samuel Holland, Karol Herbst, Noralf Trønnes, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Maxime Ripard, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

The VC4 VEC driver still uses legacy enable and disable hook
implementation. Let's convert to the atomic variants.

Signed-off-by: Maxime Ripard <maxime@cerno.tech>

diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c
index d521ffd8d75c..72eee0cbb615 100644
--- a/drivers/gpu/drm/vc4/vc4_vec.c
+++ b/drivers/gpu/drm/vc4/vc4_vec.c
@@ -375,7 +375,8 @@ static int vc4_vec_connector_init(struct drm_device *dev, struct vc4_vec *vec)
 	return 0;
 }
 
-static void vc4_vec_encoder_disable(struct drm_encoder *encoder)
+static void vc4_vec_encoder_disable(struct drm_encoder *encoder,
+				    struct drm_atomic_state *state)
 {
 	struct drm_device *drm = encoder->dev;
 	struct vc4_vec *vec = encoder_to_vc4_vec(encoder);
@@ -406,7 +407,8 @@ static void vc4_vec_encoder_disable(struct drm_encoder *encoder)
 	drm_dev_exit(idx);
 }
 
-static void vc4_vec_encoder_enable(struct drm_encoder *encoder)
+static void vc4_vec_encoder_enable(struct drm_encoder *encoder,
+				   struct drm_atomic_state *state)
 {
 	struct drm_device *drm = encoder->dev;
 	struct vc4_vec *vec = encoder_to_vc4_vec(encoder);
@@ -508,9 +510,9 @@ static int vc4_vec_encoder_atomic_check(struct drm_encoder *encoder,
 }
 
 static const struct drm_encoder_helper_funcs vc4_vec_encoder_helper_funcs = {
-	.disable = vc4_vec_encoder_disable,
-	.enable = vc4_vec_encoder_enable,
 	.atomic_check = vc4_vec_encoder_atomic_check,
+	.atomic_disable = vc4_vec_encoder_disable,
+	.atomic_enable = vc4_vec_encoder_enable,
 	.atomic_mode_set = vc4_vec_encoder_atomic_mode_set,
 };
 

-- 
b4 0.10.0-dev-65ba7

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

* [PATCH v2 26/41] drm/vc4: vec: Refactor VEC TV mode setting
  2022-08-29 13:11 [PATCH v2 00/41] drm: Analog TV Improvements Maxime Ripard
                   ` (24 preceding siblings ...)
  2022-08-29 13:11 ` [PATCH v2 25/41] drm/vc4: vec: Convert to atomic helpers Maxime Ripard
@ 2022-08-29 13:11 ` Maxime Ripard
  2022-08-30 15:29   ` Noralf Trønnes
  2022-09-07  8:35   ` (subset) " Maxime Ripard
  2022-08-29 13:11 ` [PATCH v2 27/41] drm/vc4: vec: Remove redundant atomic_mode_set Maxime Ripard
                   ` (15 subsequent siblings)
  41 siblings, 2 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-08-29 13:11 UTC (permalink / raw)
  To: Maxime Ripard, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec,
	Samuel Holland, Karol Herbst, Noralf Trønnes, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Maxime Ripard, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

From: Mateusz Kwiatkowski <kfyatek+publicgit@gmail.com>

Change the mode_set function pointer logic to declarative config0,
config1 and custom_freq fields, to make TV mode setting logic more
concise and uniform.

Signed-off-by: Mateusz Kwiatkowski <kfyatek+publicgit@gmail.com>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>

diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c
index 72eee0cbb615..9a37c3fcc295 100644
--- a/drivers/gpu/drm/vc4/vc4_vec.c
+++ b/drivers/gpu/drm/vc4/vc4_vec.c
@@ -194,7 +194,9 @@ enum vc4_vec_tv_mode_id {
 
 struct vc4_vec_tv_mode {
 	const struct drm_display_mode *mode;
-	void (*mode_set)(struct vc4_vec *vec);
+	u32 config0;
+	u32 config1;
+	u32 custom_freq;
 };
 
 static const struct debugfs_reg32 vec_regs[] = {
@@ -224,34 +226,6 @@ static const struct debugfs_reg32 vec_regs[] = {
 	VC4_REG32(VEC_DAC_MISC),
 };
 
-static void vc4_vec_ntsc_mode_set(struct vc4_vec *vec)
-{
-	struct drm_device *drm = vec->connector.dev;
-	int idx;
-
-	if (!drm_dev_enter(drm, &idx))
-		return;
-
-	VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_NTSC_STD | VEC_CONFIG0_PDEN);
-	VEC_WRITE(VEC_CONFIG1, VEC_CONFIG1_C_CVBS_CVBS);
-
-	drm_dev_exit(idx);
-}
-
-static void vc4_vec_ntsc_j_mode_set(struct vc4_vec *vec)
-{
-	struct drm_device *drm = vec->connector.dev;
-	int idx;
-
-	if (!drm_dev_enter(drm, &idx))
-		return;
-
-	VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_NTSC_STD);
-	VEC_WRITE(VEC_CONFIG1, VEC_CONFIG1_C_CVBS_CVBS);
-
-	drm_dev_exit(idx);
-}
-
 static const struct drm_display_mode ntsc_mode = {
 	DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 13500,
 		 720, 720 + 14, 720 + 14 + 64, 720 + 14 + 64 + 60, 0,
@@ -259,37 +233,6 @@ static const struct drm_display_mode ntsc_mode = {
 		 DRM_MODE_FLAG_INTERLACE)
 };
 
-static void vc4_vec_pal_mode_set(struct vc4_vec *vec)
-{
-	struct drm_device *drm = vec->connector.dev;
-	int idx;
-
-	if (!drm_dev_enter(drm, &idx))
-		return;
-
-	VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_PAL_BDGHI_STD);
-	VEC_WRITE(VEC_CONFIG1, VEC_CONFIG1_C_CVBS_CVBS);
-
-	drm_dev_exit(idx);
-}
-
-static void vc4_vec_pal_m_mode_set(struct vc4_vec *vec)
-{
-	struct drm_device *drm = vec->connector.dev;
-	int idx;
-
-	if (!drm_dev_enter(drm, &idx))
-		return;
-
-	VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_PAL_BDGHI_STD);
-	VEC_WRITE(VEC_CONFIG1,
-		  VEC_CONFIG1_C_CVBS_CVBS | VEC_CONFIG1_CUSTOM_FREQ);
-	VEC_WRITE(VEC_FREQ3_2, 0x223b);
-	VEC_WRITE(VEC_FREQ1_0, 0x61d1);
-
-	drm_dev_exit(idx);
-}
-
 static const struct drm_display_mode pal_mode = {
 	DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 13500,
 		 720, 720 + 20, 720 + 20 + 64, 720 + 20 + 64 + 60, 0,
@@ -300,19 +243,24 @@ static const struct drm_display_mode pal_mode = {
 static const struct vc4_vec_tv_mode vc4_vec_tv_modes[] = {
 	[VC4_VEC_TV_MODE_NTSC] = {
 		.mode = &ntsc_mode,
-		.mode_set = vc4_vec_ntsc_mode_set,
+		.config0 = VEC_CONFIG0_NTSC_STD | VEC_CONFIG0_PDEN,
+		.config1 = VEC_CONFIG1_C_CVBS_CVBS,
 	},
 	[VC4_VEC_TV_MODE_NTSC_J] = {
 		.mode = &ntsc_mode,
-		.mode_set = vc4_vec_ntsc_j_mode_set,
+		.config0 = VEC_CONFIG0_NTSC_STD,
+		.config1 = VEC_CONFIG1_C_CVBS_CVBS,
 	},
 	[VC4_VEC_TV_MODE_PAL] = {
 		.mode = &pal_mode,
-		.mode_set = vc4_vec_pal_mode_set,
+		.config0 = VEC_CONFIG0_PAL_BDGHI_STD,
+		.config1 = VEC_CONFIG1_C_CVBS_CVBS,
 	},
 	[VC4_VEC_TV_MODE_PAL_M] = {
 		.mode = &pal_mode,
-		.mode_set = vc4_vec_pal_m_mode_set,
+		.config0 = VEC_CONFIG0_PAL_BDGHI_STD,
+		.config1 = VEC_CONFIG1_C_CVBS_CVBS | VEC_CONFIG1_CUSTOM_FREQ,
+		.custom_freq = 0x223b61d1,
 	},
 };
 
@@ -470,7 +418,16 @@ static void vc4_vec_encoder_enable(struct drm_encoder *encoder,
 	/* Mask all interrupts. */
 	VEC_WRITE(VEC_MASK0, 0);
 
-	vec->tv_mode->mode_set(vec);
+	VEC_WRITE(VEC_CONFIG0, vec->tv_mode->config0);
+	VEC_WRITE(VEC_CONFIG1, vec->tv_mode->config1);
+
+	if (vec->tv_mode->custom_freq != 0) {
+		VEC_WRITE(VEC_FREQ3_2,
+			  (vec->tv_mode->custom_freq >> 16) &
+			  0xffff);
+		VEC_WRITE(VEC_FREQ1_0,
+			  vec->tv_mode->custom_freq & 0xffff);
+	}
 
 	VEC_WRITE(VEC_DAC_MISC,
 		  VEC_DAC_MISC_VID_ACT | VEC_DAC_MISC_DAC_RST_N);

-- 
b4 0.10.0-dev-65ba7

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

* [PATCH v2 27/41] drm/vc4: vec: Remove redundant atomic_mode_set
  2022-08-29 13:11 [PATCH v2 00/41] drm: Analog TV Improvements Maxime Ripard
                   ` (25 preceding siblings ...)
  2022-08-29 13:11 ` [PATCH v2 26/41] drm/vc4: vec: Refactor VEC TV mode setting Maxime Ripard
@ 2022-08-29 13:11 ` Maxime Ripard
  2022-08-30 15:45   ` Noralf Trønnes
  2022-09-07  8:35   ` (subset) " Maxime Ripard
  2022-08-29 13:11 ` [PATCH v2 28/41] drm/vc4: vec: Fix timings for VEC modes Maxime Ripard
                   ` (14 subsequent siblings)
  41 siblings, 2 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-08-29 13:11 UTC (permalink / raw)
  To: Maxime Ripard, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec,
	Samuel Holland, Karol Herbst, Noralf Trønnes, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Maxime Ripard, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

From: Mateusz Kwiatkowski <kfyatek+publicgit@gmail.com>

Let's remove the superfluous tv_mode field, which was redundant with the
mode field in struct drm_tv_connector_state.

Signed-off-by: Mateusz Kwiatkowski <kfyatek+publicgit@gmail.com>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>

diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c
index 9a37c3fcc295..4d7bc7c20704 100644
--- a/drivers/gpu/drm/vc4/vc4_vec.c
+++ b/drivers/gpu/drm/vc4/vc4_vec.c
@@ -171,8 +171,6 @@ struct vc4_vec {
 
 	struct clk *clock;
 
-	const struct vc4_vec_tv_mode *tv_mode;
-
 	struct debugfs_regset32 regset;
 };
 
@@ -316,7 +314,6 @@ static int vc4_vec_connector_init(struct drm_device *dev, struct vc4_vec *vec)
 	drm_object_attach_property(&connector->base,
 				   dev->mode_config.legacy_tv_mode_property,
 				   VC4_VEC_TV_MODE_NTSC);
-	vec->tv_mode = &vc4_vec_tv_modes[VC4_VEC_TV_MODE_NTSC];
 
 	drm_connector_attach_encoder(connector, &vec->encoder.base);
 
@@ -360,6 +357,11 @@ static void vc4_vec_encoder_enable(struct drm_encoder *encoder,
 {
 	struct drm_device *drm = encoder->dev;
 	struct vc4_vec *vec = encoder_to_vc4_vec(encoder);
+	struct drm_connector *connector = &vec->connector;
+	struct drm_connector_state *conn_state =
+		drm_atomic_get_new_connector_state(state, connector);
+	const struct vc4_vec_tv_mode *tv_mode =
+		&vc4_vec_tv_modes[conn_state->tv.mode];
 	int idx, ret;
 
 	if (!drm_dev_enter(drm, &idx))
@@ -418,15 +420,14 @@ static void vc4_vec_encoder_enable(struct drm_encoder *encoder,
 	/* Mask all interrupts. */
 	VEC_WRITE(VEC_MASK0, 0);
 
-	VEC_WRITE(VEC_CONFIG0, vec->tv_mode->config0);
-	VEC_WRITE(VEC_CONFIG1, vec->tv_mode->config1);
+	VEC_WRITE(VEC_CONFIG0, tv_mode->config0);
+	VEC_WRITE(VEC_CONFIG1, tv_mode->config1);
 
-	if (vec->tv_mode->custom_freq != 0) {
+	if (tv_mode->custom_freq != 0) {
 		VEC_WRITE(VEC_FREQ3_2,
-			  (vec->tv_mode->custom_freq >> 16) &
-			  0xffff);
+			  (tv_mode->custom_freq >> 16) & 0xffff);
 		VEC_WRITE(VEC_FREQ1_0,
-			  vec->tv_mode->custom_freq & 0xffff);
+			  tv_mode->custom_freq & 0xffff);
 	}
 
 	VEC_WRITE(VEC_DAC_MISC,
@@ -442,15 +443,6 @@ static void vc4_vec_encoder_enable(struct drm_encoder *encoder,
 	drm_dev_exit(idx);
 }
 
-static void vc4_vec_encoder_atomic_mode_set(struct drm_encoder *encoder,
-					struct drm_crtc_state *crtc_state,
-					struct drm_connector_state *conn_state)
-{
-	struct vc4_vec *vec = encoder_to_vc4_vec(encoder);
-
-	vec->tv_mode = &vc4_vec_tv_modes[conn_state->tv.mode];
-}
-
 static int vc4_vec_encoder_atomic_check(struct drm_encoder *encoder,
 					struct drm_crtc_state *crtc_state,
 					struct drm_connector_state *conn_state)
@@ -470,7 +462,6 @@ static const struct drm_encoder_helper_funcs vc4_vec_encoder_helper_funcs = {
 	.atomic_check = vc4_vec_encoder_atomic_check,
 	.atomic_disable = vc4_vec_encoder_disable,
 	.atomic_enable = vc4_vec_encoder_enable,
-	.atomic_mode_set = vc4_vec_encoder_atomic_mode_set,
 };
 
 static int vc4_vec_late_register(struct drm_encoder *encoder)

-- 
b4 0.10.0-dev-65ba7

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

* [PATCH v2 28/41] drm/vc4: vec: Fix timings for VEC modes
  2022-08-29 13:11 [PATCH v2 00/41] drm: Analog TV Improvements Maxime Ripard
                   ` (26 preceding siblings ...)
  2022-08-29 13:11 ` [PATCH v2 27/41] drm/vc4: vec: Remove redundant atomic_mode_set Maxime Ripard
@ 2022-08-29 13:11 ` Maxime Ripard
  2022-08-30 18:20   ` Noralf Trønnes
  2022-09-07  8:35   ` (subset) " Maxime Ripard
  2022-08-29 13:11 ` [PATCH v2 29/41] drm/vc4: vec: Switch for common modes Maxime Ripard
                   ` (13 subsequent siblings)
  41 siblings, 2 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-08-29 13:11 UTC (permalink / raw)
  To: Maxime Ripard, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec,
	Samuel Holland, Karol Herbst, Noralf Trønnes, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Maxime Ripard, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

From: Mateusz Kwiatkowski <kfyatek+publicgit@gmail.com>

This commit fixes vertical timings of the VEC (composite output) modes
to accurately represent the 525-line ("NTSC") and 625-line ("PAL") ITU-R
standards.

Previous timings were actually defined as 502 and 601 lines, resulting
in non-standard 62.69 Hz and 52 Hz signals being generated,
respectively.

Signed-off-by: Mateusz Kwiatkowski <kfyatek+publicgit@gmail.com>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>

diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c
index 4d7bc7c20704..d1d40b69279e 100644
--- a/drivers/gpu/drm/vc4/vc4_vec.c
+++ b/drivers/gpu/drm/vc4/vc4_vec.c
@@ -227,14 +227,14 @@ static const struct debugfs_reg32 vec_regs[] = {
 static const struct drm_display_mode ntsc_mode = {
 	DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 13500,
 		 720, 720 + 14, 720 + 14 + 64, 720 + 14 + 64 + 60, 0,
-		 480, 480 + 3, 480 + 3 + 3, 480 + 3 + 3 + 16, 0,
+		 480, 480 + 7, 480 + 7 + 6, 525, 0,
 		 DRM_MODE_FLAG_INTERLACE)
 };
 
 static const struct drm_display_mode pal_mode = {
 	DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 13500,
 		 720, 720 + 20, 720 + 20 + 64, 720 + 20 + 64 + 60, 0,
-		 576, 576 + 2, 576 + 2 + 3, 576 + 2 + 3 + 20, 0,
+		 576, 576 + 4, 576 + 4 + 6, 625, 0,
 		 DRM_MODE_FLAG_INTERLACE)
 };
 

-- 
b4 0.10.0-dev-65ba7

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

* [PATCH v2 29/41] drm/vc4: vec: Switch for common modes
  2022-08-29 13:11 [PATCH v2 00/41] drm: Analog TV Improvements Maxime Ripard
                   ` (27 preceding siblings ...)
  2022-08-29 13:11 ` [PATCH v2 28/41] drm/vc4: vec: Fix timings for VEC modes Maxime Ripard
@ 2022-08-29 13:11 ` Maxime Ripard
  2022-08-30 18:36   ` Noralf Trønnes
  2022-08-29 13:11 ` [PATCH v2 30/41] drm/vc4: vec: Fix definition of PAL-M mode Maxime Ripard
                   ` (12 subsequent siblings)
  41 siblings, 1 reply; 128+ messages in thread
From: Maxime Ripard @ 2022-08-29 13:11 UTC (permalink / raw)
  To: Maxime Ripard, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec,
	Samuel Holland, Karol Herbst, Noralf Trønnes, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Maxime Ripard, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

Now that the core has a definition for the 525 and 625 lines analog TV
modes, let's switch to it for vc4.

Signed-off-by: Maxime Ripard <maxime@cerno.tech>

diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c
index d1d40b69279e..63e4e617e321 100644
--- a/drivers/gpu/drm/vc4/vc4_vec.c
+++ b/drivers/gpu/drm/vc4/vc4_vec.c
@@ -224,38 +224,24 @@ static const struct debugfs_reg32 vec_regs[] = {
 	VC4_REG32(VEC_DAC_MISC),
 };
 
-static const struct drm_display_mode ntsc_mode = {
-	DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 13500,
-		 720, 720 + 14, 720 + 14 + 64, 720 + 14 + 64 + 60, 0,
-		 480, 480 + 7, 480 + 7 + 6, 525, 0,
-		 DRM_MODE_FLAG_INTERLACE)
-};
-
-static const struct drm_display_mode pal_mode = {
-	DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 13500,
-		 720, 720 + 20, 720 + 20 + 64, 720 + 20 + 64 + 60, 0,
-		 576, 576 + 4, 576 + 4 + 6, 625, 0,
-		 DRM_MODE_FLAG_INTERLACE)
-};
-
 static const struct vc4_vec_tv_mode vc4_vec_tv_modes[] = {
 	[VC4_VEC_TV_MODE_NTSC] = {
-		.mode = &ntsc_mode,
+		.mode = &drm_mode_480i,
 		.config0 = VEC_CONFIG0_NTSC_STD | VEC_CONFIG0_PDEN,
 		.config1 = VEC_CONFIG1_C_CVBS_CVBS,
 	},
 	[VC4_VEC_TV_MODE_NTSC_J] = {
-		.mode = &ntsc_mode,
+		.mode = &drm_mode_480i,
 		.config0 = VEC_CONFIG0_NTSC_STD,
 		.config1 = VEC_CONFIG1_C_CVBS_CVBS,
 	},
 	[VC4_VEC_TV_MODE_PAL] = {
-		.mode = &pal_mode,
+		.mode = &drm_mode_576i,
 		.config0 = VEC_CONFIG0_PAL_BDGHI_STD,
 		.config1 = VEC_CONFIG1_C_CVBS_CVBS,
 	},
 	[VC4_VEC_TV_MODE_PAL_M] = {
-		.mode = &pal_mode,
+		.mode = &drm_mode_576i,
 		.config0 = VEC_CONFIG0_PAL_BDGHI_STD,
 		.config1 = VEC_CONFIG1_C_CVBS_CVBS | VEC_CONFIG1_CUSTOM_FREQ,
 		.custom_freq = 0x223b61d1,

-- 
b4 0.10.0-dev-65ba7

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

* [PATCH v2 30/41] drm/vc4: vec: Fix definition of PAL-M mode
  2022-08-29 13:11 [PATCH v2 00/41] drm: Analog TV Improvements Maxime Ripard
                   ` (28 preceding siblings ...)
  2022-08-29 13:11 ` [PATCH v2 29/41] drm/vc4: vec: Switch for common modes Maxime Ripard
@ 2022-08-29 13:11 ` Maxime Ripard
  2022-08-29 13:11 ` [PATCH v2 31/41] drm/vc4: vec: Use TV Reset implementation Maxime Ripard
                   ` (11 subsequent siblings)
  41 siblings, 0 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-08-29 13:11 UTC (permalink / raw)
  To: Maxime Ripard, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec,
	Samuel Holland, Karol Herbst, Noralf Trønnes, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Maxime Ripard, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

From: Mateusz Kwiatkowski <kfyatek+publicgit@gmail.com>

PAL-M is a Brazilian analog TV standard that uses a PAL-style chroma
subcarrier at 3.575611[888111] MHz on top of 525-line (480i60) timings.
This commit makes the driver actually use the proper VEC preset for this
mode instead of just changing PAL subcarrier frequency.

Signed-off-by: Mateusz Kwiatkowski <kfyatek+publicgit@gmail.com>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>

diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c
index 63e4e617e321..fa85dd260742 100644
--- a/drivers/gpu/drm/vc4/vc4_vec.c
+++ b/drivers/gpu/drm/vc4/vc4_vec.c
@@ -69,6 +69,7 @@
 #define VEC_CONFIG0_STD_MASK		GENMASK(1, 0)
 #define VEC_CONFIG0_NTSC_STD		0
 #define VEC_CONFIG0_PAL_BDGHI_STD	1
+#define VEC_CONFIG0_PAL_M_STD		2
 #define VEC_CONFIG0_PAL_N_STD		3
 
 #define VEC_SCHPH			0x108
@@ -241,10 +242,9 @@ static const struct vc4_vec_tv_mode vc4_vec_tv_modes[] = {
 		.config1 = VEC_CONFIG1_C_CVBS_CVBS,
 	},
 	[VC4_VEC_TV_MODE_PAL_M] = {
-		.mode = &drm_mode_576i,
-		.config0 = VEC_CONFIG0_PAL_BDGHI_STD,
-		.config1 = VEC_CONFIG1_C_CVBS_CVBS | VEC_CONFIG1_CUSTOM_FREQ,
-		.custom_freq = 0x223b61d1,
+		.mode = &drm_mode_480i,
+		.config0 = VEC_CONFIG0_PAL_M_STD,
+		.config1 = VEC_CONFIG1_C_CVBS_CVBS,
 	},
 };
 

-- 
b4 0.10.0-dev-65ba7

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

* [PATCH v2 31/41] drm/vc4: vec: Use TV Reset implementation
  2022-08-29 13:11 [PATCH v2 00/41] drm: Analog TV Improvements Maxime Ripard
                   ` (29 preceding siblings ...)
  2022-08-29 13:11 ` [PATCH v2 30/41] drm/vc4: vec: Fix definition of PAL-M mode Maxime Ripard
@ 2022-08-29 13:11 ` Maxime Ripard
  2022-08-30 18:51   ` Noralf Trønnes
  2022-08-29 13:11 ` [PATCH v2 32/41] drm/vc4: vec: Convert to the new TV mode property Maxime Ripard
                   ` (10 subsequent siblings)
  41 siblings, 1 reply; 128+ messages in thread
From: Maxime Ripard @ 2022-08-29 13:11 UTC (permalink / raw)
  To: Maxime Ripard, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec,
	Samuel Holland, Karol Herbst, Noralf Trønnes, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Maxime Ripard, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

The analog TV properties created by the drm_mode_create_tv_properties() are
not properly initialised at reset. Let's switch our implementation to call
drm_atomic_helper_connector_tv_reset().

Signed-off-by: Maxime Ripard <maxime@cerno.tech>

diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c
index fa85dd260742..ba6f81908923 100644
--- a/drivers/gpu/drm/vc4/vc4_vec.c
+++ b/drivers/gpu/drm/vc4/vc4_vec.c
@@ -254,6 +254,12 @@ vc4_vec_connector_detect(struct drm_connector *connector, bool force)
 	return connector_status_unknown;
 }
 
+static void vc4_vec_connector_reset(struct drm_connector *connector)
+{
+	drm_atomic_helper_connector_reset(connector);
+	drm_atomic_helper_connector_tv_reset(connector);
+}
+
 static int vc4_vec_connector_get_modes(struct drm_connector *connector)
 {
 	struct drm_connector_state *state = connector->state;
@@ -274,7 +280,7 @@ static int vc4_vec_connector_get_modes(struct drm_connector *connector)
 static const struct drm_connector_funcs vc4_vec_connector_funcs = {
 	.detect = vc4_vec_connector_detect,
 	.fill_modes = drm_helper_probe_single_connector_modes,
-	.reset = drm_atomic_helper_connector_reset,
+	.reset = vc4_vec_connector_reset,
 	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
 	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 };

-- 
b4 0.10.0-dev-65ba7

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

* [PATCH v2 32/41] drm/vc4: vec: Convert to the new TV mode property
  2022-08-29 13:11 [PATCH v2 00/41] drm: Analog TV Improvements Maxime Ripard
                   ` (30 preceding siblings ...)
  2022-08-29 13:11 ` [PATCH v2 31/41] drm/vc4: vec: Use TV Reset implementation Maxime Ripard
@ 2022-08-29 13:11 ` Maxime Ripard
  2022-08-30 19:01   ` Noralf Trønnes
  2022-08-31  2:23   ` Mateusz Kwiatkowski
  2022-08-29 13:11 ` [PATCH v2 33/41] drm/vc4: vec: Add support for more analog TV standards Maxime Ripard
                   ` (9 subsequent siblings)
  41 siblings, 2 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-08-29 13:11 UTC (permalink / raw)
  To: Maxime Ripard, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec,
	Samuel Holland, Karol Herbst, Noralf Trønnes, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Maxime Ripard, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

Now that the core can deal fine with analog TV modes, let's convert the vc4
VEC driver to leverage those new features.

We've added some backward compatibility to support the old TV mode property
and translate it into the new TV norm property.

Signed-off-by: Maxime Ripard <maxime@cerno.tech>

diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c
index ba6f81908923..58286acf4b9e 100644
--- a/drivers/gpu/drm/vc4/vc4_vec.c
+++ b/drivers/gpu/drm/vc4/vc4_vec.c
@@ -172,6 +172,8 @@ struct vc4_vec {
 
 	struct clk *clock;
 
+	struct drm_property *legacy_tv_mode_property;
+
 	struct debugfs_regset32 regset;
 };
 
@@ -184,6 +186,12 @@ encoder_to_vc4_vec(struct drm_encoder *encoder)
 	return container_of(encoder, struct vc4_vec, encoder.base);
 }
 
+static inline struct vc4_vec *
+connector_to_vc4_vec(struct drm_connector *connector)
+{
+	return container_of(connector, struct vc4_vec, connector);
+}
+
 enum vc4_vec_tv_mode_id {
 	VC4_VEC_TV_MODE_NTSC,
 	VC4_VEC_TV_MODE_NTSC_J,
@@ -192,7 +200,7 @@ enum vc4_vec_tv_mode_id {
 };
 
 struct vc4_vec_tv_mode {
-	const struct drm_display_mode *mode;
+	unsigned int mode;
 	u32 config0;
 	u32 config1;
 	u32 custom_freq;
@@ -226,28 +234,50 @@ static const struct debugfs_reg32 vec_regs[] = {
 };
 
 static const struct vc4_vec_tv_mode vc4_vec_tv_modes[] = {
-	[VC4_VEC_TV_MODE_NTSC] = {
-		.mode = &drm_mode_480i,
+	{
+		.mode = DRM_MODE_TV_MODE_NTSC_M,
 		.config0 = VEC_CONFIG0_NTSC_STD | VEC_CONFIG0_PDEN,
 		.config1 = VEC_CONFIG1_C_CVBS_CVBS,
 	},
-	[VC4_VEC_TV_MODE_NTSC_J] = {
-		.mode = &drm_mode_480i,
+	{
+		.mode = DRM_MODE_TV_MODE_NTSC_J,
 		.config0 = VEC_CONFIG0_NTSC_STD,
 		.config1 = VEC_CONFIG1_C_CVBS_CVBS,
 	},
-	[VC4_VEC_TV_MODE_PAL] = {
-		.mode = &drm_mode_576i,
+	{
+		.mode = DRM_MODE_TV_MODE_PAL_B,
 		.config0 = VEC_CONFIG0_PAL_BDGHI_STD,
 		.config1 = VEC_CONFIG1_C_CVBS_CVBS,
 	},
-	[VC4_VEC_TV_MODE_PAL_M] = {
-		.mode = &drm_mode_480i,
+	{
+		.mode = DRM_MODE_TV_MODE_PAL_M,
 		.config0 = VEC_CONFIG0_PAL_M_STD,
 		.config1 = VEC_CONFIG1_C_CVBS_CVBS,
 	},
 };
 
+static inline const struct vc4_vec_tv_mode *
+vc4_vec_tv_mode_lookup(unsigned int mode)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(vc4_vec_tv_modes); i++) {
+		const struct vc4_vec_tv_mode *tv_mode = &vc4_vec_tv_modes[i];
+
+		if (tv_mode->mode == mode)
+			return tv_mode;
+	}
+
+	return NULL;
+}
+
+static const struct drm_prop_enum_list tv_mode_names[] = {
+	{ VC4_VEC_TV_MODE_NTSC, "NTSC", },
+	{ VC4_VEC_TV_MODE_NTSC_J, "NTSC-J", },
+	{ VC4_VEC_TV_MODE_PAL, "PAL", },
+	{ VC4_VEC_TV_MODE_PAL_M, "PAL-M", },
+};
+
 static enum drm_connector_status
 vc4_vec_connector_detect(struct drm_connector *connector, bool force)
 {
@@ -262,19 +292,98 @@ static void vc4_vec_connector_reset(struct drm_connector *connector)
 
 static int vc4_vec_connector_get_modes(struct drm_connector *connector)
 {
-	struct drm_connector_state *state = connector->state;
 	struct drm_display_mode *mode;
+	int count = 0;
 
-	mode = drm_mode_duplicate(connector->dev,
-				  vc4_vec_tv_modes[state->tv.mode].mode);
+	mode = drm_mode_analog_ntsc_480i(connector->dev);
 	if (!mode) {
 		DRM_ERROR("Failed to create a new display mode\n");
 		return -ENOMEM;
 	}
 
 	drm_mode_probed_add(connector, mode);
+	count += 1;
 
-	return 1;
+	mode = drm_mode_analog_pal_576i(connector->dev);
+	if (!mode) {
+		DRM_ERROR("Failed to create a new display mode\n");
+		return -ENOMEM;
+	}
+
+	drm_mode_probed_add(connector, mode);
+	count += 1;
+
+	return count;
+}
+
+static int
+vc4_vec_connector_set_property(struct drm_connector *connector,
+			       struct drm_connector_state *state,
+			       struct drm_property *property,
+			       uint64_t val)
+{
+	struct vc4_vec *vec = connector_to_vc4_vec(connector);
+
+	if (property != vec->legacy_tv_mode_property)
+		return -EINVAL;
+
+	switch (val) {
+	case VC4_VEC_TV_MODE_NTSC:
+		state->tv.mode = DRM_MODE_TV_MODE_NTSC_M;
+		break;
+
+	case VC4_VEC_TV_MODE_NTSC_J:
+		state->tv.mode = DRM_MODE_TV_MODE_NTSC_J;
+		break;
+
+	case VC4_VEC_TV_MODE_PAL:
+		state->tv.mode = DRM_MODE_TV_MODE_PAL_B;
+		break;
+
+	case VC4_VEC_TV_MODE_PAL_M:
+		state->tv.mode = DRM_MODE_TV_MODE_PAL_M;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int
+vc4_vec_connector_get_property(struct drm_connector *connector,
+			       const struct drm_connector_state *state,
+			       struct drm_property *property,
+			       uint64_t *val)
+{
+	struct vc4_vec *vec = connector_to_vc4_vec(connector);
+
+	if (property != vec->legacy_tv_mode_property)
+		return -EINVAL;
+
+	switch (state->tv.mode) {
+	case DRM_MODE_TV_MODE_NTSC_J:
+		*val = VC4_VEC_TV_MODE_NTSC_J;
+		break;
+
+	case DRM_MODE_TV_MODE_NTSC_M:
+		*val = VC4_VEC_TV_MODE_NTSC;
+		break;
+
+	case DRM_MODE_TV_MODE_PAL_B:
+		*val = VC4_VEC_TV_MODE_PAL;
+		break;
+
+	case DRM_MODE_TV_MODE_PAL_M:
+		*val = VC4_VEC_TV_MODE_PAL_M;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
 }
 
 static const struct drm_connector_funcs vc4_vec_connector_funcs = {
@@ -283,15 +392,19 @@ static const struct drm_connector_funcs vc4_vec_connector_funcs = {
 	.reset = vc4_vec_connector_reset,
 	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
 	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+	.atomic_get_property = vc4_vec_connector_get_property,
+	.atomic_set_property = vc4_vec_connector_set_property,
 };
 
 static const struct drm_connector_helper_funcs vc4_vec_connector_helper_funcs = {
+	.atomic_check = drm_atomic_helper_connector_tv_check,
 	.get_modes = vc4_vec_connector_get_modes,
 };
 
 static int vc4_vec_connector_init(struct drm_device *dev, struct vc4_vec *vec)
 {
 	struct drm_connector *connector = &vec->connector;
+	struct drm_property *prop;
 	int ret;
 
 	connector->interlace_allowed = true;
@@ -304,8 +417,16 @@ static int vc4_vec_connector_init(struct drm_device *dev, struct vc4_vec *vec)
 	drm_connector_helper_add(connector, &vc4_vec_connector_helper_funcs);
 
 	drm_object_attach_property(&connector->base,
-				   dev->mode_config.legacy_tv_mode_property,
-				   VC4_VEC_TV_MODE_NTSC);
+				   dev->mode_config.tv_mode_property,
+				   DRM_MODE_TV_MODE_NTSC_M);
+
+	prop = drm_property_create_enum(dev, 0, "mode",
+					tv_mode_names, ARRAY_SIZE(tv_mode_names));
+	if (!prop)
+		return -ENOMEM;
+	vec->legacy_tv_mode_property = prop;
+
+	drm_object_attach_property(&connector->base, prop, VC4_VEC_TV_MODE_NTSC);
 
 	drm_connector_attach_encoder(connector, &vec->encoder.base);
 
@@ -352,13 +473,16 @@ static void vc4_vec_encoder_enable(struct drm_encoder *encoder,
 	struct drm_connector *connector = &vec->connector;
 	struct drm_connector_state *conn_state =
 		drm_atomic_get_new_connector_state(state, connector);
-	const struct vc4_vec_tv_mode *tv_mode =
-		&vc4_vec_tv_modes[conn_state->tv.mode];
+	const struct vc4_vec_tv_mode *tv_mode;
 	int idx, ret;
 
 	if (!drm_dev_enter(drm, &idx))
 		return;
 
+	tv_mode = vc4_vec_tv_mode_lookup(conn_state->tv.mode);
+	if (!tv_mode)
+		goto err_dev_exit;
+
 	ret = pm_runtime_get_sync(&vec->pdev->dev);
 	if (ret < 0) {
 		DRM_ERROR("Failed to retain power domain: %d\n", ret);
@@ -435,23 +559,7 @@ static void vc4_vec_encoder_enable(struct drm_encoder *encoder,
 	drm_dev_exit(idx);
 }
 
-static int vc4_vec_encoder_atomic_check(struct drm_encoder *encoder,
-					struct drm_crtc_state *crtc_state,
-					struct drm_connector_state *conn_state)
-{
-	const struct vc4_vec_tv_mode *vec_mode;
-
-	vec_mode = &vc4_vec_tv_modes[conn_state->tv.mode];
-
-	if (conn_state->crtc &&
-	    !drm_mode_equal(vec_mode->mode, &crtc_state->adjusted_mode))
-		return -EINVAL;
-
-	return 0;
-}
-
 static const struct drm_encoder_helper_funcs vc4_vec_encoder_helper_funcs = {
-	.atomic_check = vc4_vec_encoder_atomic_check,
 	.atomic_disable = vc4_vec_encoder_disable,
 	.atomic_enable = vc4_vec_encoder_enable,
 };
@@ -492,13 +600,6 @@ static const struct of_device_id vc4_vec_dt_match[] = {
 	{ /* sentinel */ },
 };
 
-static const char * const tv_mode_names[] = {
-	[VC4_VEC_TV_MODE_NTSC] = "NTSC",
-	[VC4_VEC_TV_MODE_NTSC_J] = "NTSC-J",
-	[VC4_VEC_TV_MODE_PAL] = "PAL",
-	[VC4_VEC_TV_MODE_PAL_M] = "PAL-M",
-};
-
 static int vc4_vec_bind(struct device *dev, struct device *master, void *data)
 {
 	struct platform_device *pdev = to_platform_device(dev);
@@ -506,9 +607,11 @@ static int vc4_vec_bind(struct device *dev, struct device *master, void *data)
 	struct vc4_vec *vec;
 	int ret;
 
-	ret = drm_mode_create_tv_properties_legacy(drm,
-						   ARRAY_SIZE(tv_mode_names),
-						   tv_mode_names);
+	ret = drm_mode_create_tv_properties(drm,
+					    BIT(DRM_MODE_TV_MODE_NTSC_J) |
+					    BIT(DRM_MODE_TV_MODE_NTSC_M) |
+					    BIT(DRM_MODE_TV_MODE_PAL_B) |
+					    BIT(DRM_MODE_TV_MODE_PAL_M));
 	if (ret)
 		return ret;
 

-- 
b4 0.10.0-dev-65ba7

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

* [PATCH v2 33/41] drm/vc4: vec: Add support for more analog TV standards
  2022-08-29 13:11 [PATCH v2 00/41] drm: Analog TV Improvements Maxime Ripard
                   ` (31 preceding siblings ...)
  2022-08-29 13:11 ` [PATCH v2 32/41] drm/vc4: vec: Convert to the new TV mode property Maxime Ripard
@ 2022-08-29 13:11 ` Maxime Ripard
  2022-08-29 13:11 ` [PATCH v2 34/41] drm/sun4i: tv: Remove unused mode_valid Maxime Ripard
                   ` (8 subsequent siblings)
  41 siblings, 0 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-08-29 13:11 UTC (permalink / raw)
  To: Maxime Ripard, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec,
	Samuel Holland, Karol Herbst, Noralf Trønnes, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Maxime Ripard, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

From: Mateusz Kwiatkowski <kfyatek+publicgit@gmail.com>

Add support for the following composite output modes (all of them are
somewhat more obscure than the previously defined ones):

- NTSC_443 - NTSC-style signal with the chroma subcarrier shifted to
  4.43361875 MHz (the PAL subcarrier frequency). Never used for
  broadcasting, but sometimes used as a hack to play NTSC content in PAL
  regions (e.g. on VCRs).
- PAL_N - PAL with alternative chroma subcarrier frequency,
  3.58205625 MHz. Used as a broadcast standard in Argentina, Paraguay
  and Uruguay to fit 576i50 with colour in 6 MHz channel raster.
- PAL60 - 480i60 signal with PAL-style color at normal European PAL
  frequency. Another non-standard, non-broadcast mode, used in similar
  contexts as NTSC_443. Some displays support one but not the other.
- SECAM - French frequency-modulated analog color standard; also have
  been broadcast in Eastern Europe and various parts of Africa and Asia.
  Uses the same 576i50 timings as PAL.

Also added some comments explaining color subcarrier frequency
registers.

Signed-off-by: Mateusz Kwiatkowski <kfyatek+publicgit@gmail.com>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>

diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c
index 58286acf4b9e..55f6f490877c 100644
--- a/drivers/gpu/drm/vc4/vc4_vec.c
+++ b/drivers/gpu/drm/vc4/vc4_vec.c
@@ -46,6 +46,7 @@
 #define VEC_CONFIG0_YDEL(x)		((x) << 26)
 #define VEC_CONFIG0_CDEL_MASK		GENMASK(25, 24)
 #define VEC_CONFIG0_CDEL(x)		((x) << 24)
+#define VEC_CONFIG0_SECAM_STD		BIT(21)
 #define VEC_CONFIG0_PBPR_FIL		BIT(18)
 #define VEC_CONFIG0_CHROMA_GAIN_MASK	GENMASK(17, 16)
 #define VEC_CONFIG0_CHROMA_GAIN_UNITY	(0 << 16)
@@ -76,6 +77,27 @@
 #define VEC_SOFT_RESET			0x10c
 #define VEC_CLMP0_START			0x144
 #define VEC_CLMP0_END			0x148
+
+/*
+ * These set the color subcarrier frequency
+ * if VEC_CONFIG1_CUSTOM_FREQ is enabled.
+ *
+ * VEC_FREQ1_0 contains the most significant 16-bit half-word,
+ * VEC_FREQ3_2 contains the least significant 16-bit half-word.
+ * 0x80000000 seems to be equivalent to the pixel clock
+ * (which itself is the VEC clock divided by 8).
+ *
+ * Reference values (with the default pixel clock of 13.5 MHz):
+ *
+ * NTSC  (3579545.[45] Hz)     - 0x21F07C1F
+ * PAL   (4433618.75 Hz)       - 0x2A098ACB
+ * PAL-M (3575611.[888111] Hz) - 0x21E6EFE3
+ * PAL-N (3582056.25 Hz)       - 0x21F69446
+ *
+ * NOTE: For SECAM, it is used as the Dr center frequency,
+ * regardless of whether VEC_CONFIG1_CUSTOM_FREQ is enabled or not;
+ * that is specified as 4406250 Hz, which corresponds to 0x29C71C72.
+ */
 #define VEC_FREQ3_2			0x180
 #define VEC_FREQ1_0			0x184
 
@@ -118,6 +140,14 @@
 
 #define VEC_INTERRUPT_CONTROL		0x190
 #define VEC_INTERRUPT_STATUS		0x194
+
+/*
+ * Db center frequency for SECAM; the clock for this is the same as for
+ * VEC_FREQ3_2/VEC_FREQ1_0, which is used for Dr center frequency.
+ *
+ * This is specified as 4250000 Hz, which corresponds to 0x284BDA13.
+ * That is also the default value, so no need to set it explicitly.
+ */
 #define VEC_FCW_SECAM_B			0x198
 #define VEC_SECAM_GAIN_VAL		0x19c
 
@@ -194,9 +224,13 @@ connector_to_vc4_vec(struct drm_connector *connector)
 
 enum vc4_vec_tv_mode_id {
 	VC4_VEC_TV_MODE_NTSC,
+	VC4_VEC_TV_MODE_NTSC_443,
 	VC4_VEC_TV_MODE_NTSC_J,
 	VC4_VEC_TV_MODE_PAL,
+	VC4_VEC_TV_MODE_PAL_60,
 	VC4_VEC_TV_MODE_PAL_M,
+	VC4_VEC_TV_MODE_PAL_N,
+	VC4_VEC_TV_MODE_SECAM,
 };
 
 struct vc4_vec_tv_mode {
@@ -234,6 +268,12 @@ static const struct debugfs_reg32 vec_regs[] = {
 };
 
 static const struct vc4_vec_tv_mode vc4_vec_tv_modes[] = {
+	{
+		.mode = DRM_MODE_TV_MODE_NTSC_443,
+		.config0 = VEC_CONFIG0_NTSC_STD,
+		.config1 = VEC_CONFIG1_C_CVBS_CVBS | VEC_CONFIG1_CUSTOM_FREQ,
+		.custom_freq = 0x2a098acb,
+	},
 	{
 		.mode = DRM_MODE_TV_MODE_NTSC_M,
 		.config0 = VEC_CONFIG0_NTSC_STD | VEC_CONFIG0_PDEN,
@@ -244,6 +284,12 @@ static const struct vc4_vec_tv_mode vc4_vec_tv_modes[] = {
 		.config0 = VEC_CONFIG0_NTSC_STD,
 		.config1 = VEC_CONFIG1_C_CVBS_CVBS,
 	},
+	{
+		.mode = DRM_MODE_TV_MODE_PAL_60,
+		.config0 = VEC_CONFIG0_PAL_M_STD,
+		.config1 = VEC_CONFIG1_C_CVBS_CVBS | VEC_CONFIG1_CUSTOM_FREQ,
+		.custom_freq = 0x2a098acb,
+	},
 	{
 		.mode = DRM_MODE_TV_MODE_PAL_B,
 		.config0 = VEC_CONFIG0_PAL_BDGHI_STD,
@@ -254,6 +300,17 @@ static const struct vc4_vec_tv_mode vc4_vec_tv_modes[] = {
 		.config0 = VEC_CONFIG0_PAL_M_STD,
 		.config1 = VEC_CONFIG1_C_CVBS_CVBS,
 	},
+	{
+		.mode = DRM_MODE_TV_MODE_PAL_N,
+		.config0 = VEC_CONFIG0_PAL_N_STD,
+		.config1 = VEC_CONFIG1_C_CVBS_CVBS,
+	},
+	{
+		.mode = DRM_MODE_TV_MODE_SECAM_B,
+		.config0 = VEC_CONFIG0_SECAM_STD,
+		.config1 = VEC_CONFIG1_C_CVBS_CVBS,
+		.custom_freq = 0x29c71c72,
+	},
 };
 
 static inline const struct vc4_vec_tv_mode *
@@ -273,9 +330,13 @@ vc4_vec_tv_mode_lookup(unsigned int mode)
 
 static const struct drm_prop_enum_list tv_mode_names[] = {
 	{ VC4_VEC_TV_MODE_NTSC, "NTSC", },
+	{ VC4_VEC_TV_MODE_NTSC_443, "NTSC-443", },
 	{ VC4_VEC_TV_MODE_NTSC_J, "NTSC-J", },
 	{ VC4_VEC_TV_MODE_PAL, "PAL", },
+	{ VC4_VEC_TV_MODE_PAL_60, "PAL-60", },
 	{ VC4_VEC_TV_MODE_PAL_M, "PAL-M", },
+	{ VC4_VEC_TV_MODE_PAL_N, "PAL-N", },
+	{ VC4_VEC_TV_MODE_SECAM, "SECAM", },
 };
 
 static enum drm_connector_status
@@ -332,6 +393,10 @@ vc4_vec_connector_set_property(struct drm_connector *connector,
 		state->tv.mode = DRM_MODE_TV_MODE_NTSC_M;
 		break;
 
+	case VC4_VEC_TV_MODE_NTSC_443:
+		state->tv.mode = DRM_MODE_TV_MODE_NTSC_443;
+		break;
+
 	case VC4_VEC_TV_MODE_NTSC_J:
 		state->tv.mode = DRM_MODE_TV_MODE_NTSC_J;
 		break;
@@ -340,10 +405,22 @@ vc4_vec_connector_set_property(struct drm_connector *connector,
 		state->tv.mode = DRM_MODE_TV_MODE_PAL_B;
 		break;
 
+	case VC4_VEC_TV_MODE_PAL_60:
+		state->tv.mode = DRM_MODE_TV_MODE_PAL_60;
+		break;
+
 	case VC4_VEC_TV_MODE_PAL_M:
 		state->tv.mode = DRM_MODE_TV_MODE_PAL_M;
 		break;
 
+	case VC4_VEC_TV_MODE_PAL_N:
+		state->tv.mode = DRM_MODE_TV_MODE_PAL_N;
+		break;
+
+	case VC4_VEC_TV_MODE_SECAM:
+		state->tv.mode = DRM_MODE_TV_MODE_SECAM_B;
+		break;
+
 	default:
 		return -EINVAL;
 	}
@@ -363,6 +440,10 @@ vc4_vec_connector_get_property(struct drm_connector *connector,
 		return -EINVAL;
 
 	switch (state->tv.mode) {
+	case DRM_MODE_TV_MODE_NTSC_443:
+		*val = VC4_VEC_TV_MODE_NTSC_443;
+		break;
+
 	case DRM_MODE_TV_MODE_NTSC_J:
 		*val = VC4_VEC_TV_MODE_NTSC_J;
 		break;
@@ -371,6 +452,10 @@ vc4_vec_connector_get_property(struct drm_connector *connector,
 		*val = VC4_VEC_TV_MODE_NTSC;
 		break;
 
+	case DRM_MODE_TV_MODE_PAL_60:
+		*val = VC4_VEC_TV_MODE_PAL_60;
+		break;
+
 	case DRM_MODE_TV_MODE_PAL_B:
 		*val = VC4_VEC_TV_MODE_PAL;
 		break;
@@ -379,6 +464,14 @@ vc4_vec_connector_get_property(struct drm_connector *connector,
 		*val = VC4_VEC_TV_MODE_PAL_M;
 		break;
 
+	case DRM_MODE_TV_MODE_PAL_N:
+		*val = VC4_VEC_TV_MODE_PAL_N;
+		break;
+
+	case DRM_MODE_TV_MODE_SECAM_B:
+		*val = VC4_VEC_TV_MODE_SECAM;
+		break;
+
 	default:
 		return -EINVAL;
 	}
@@ -608,10 +701,14 @@ static int vc4_vec_bind(struct device *dev, struct device *master, void *data)
 	int ret;
 
 	ret = drm_mode_create_tv_properties(drm,
+					    BIT(DRM_MODE_TV_MODE_NTSC_443) |
 					    BIT(DRM_MODE_TV_MODE_NTSC_J) |
 					    BIT(DRM_MODE_TV_MODE_NTSC_M) |
+					    BIT(DRM_MODE_TV_MODE_PAL_60) |
 					    BIT(DRM_MODE_TV_MODE_PAL_B) |
-					    BIT(DRM_MODE_TV_MODE_PAL_M));
+					    BIT(DRM_MODE_TV_MODE_PAL_M) |
+					    BIT(DRM_MODE_TV_MODE_PAL_N) |
+					    BIT(DRM_MODE_TV_MODE_SECAM_B));
 	if (ret)
 		return ret;
 

-- 
b4 0.10.0-dev-65ba7

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

* [PATCH v2 34/41] drm/sun4i: tv: Remove unused mode_valid
  2022-08-29 13:11 [PATCH v2 00/41] drm: Analog TV Improvements Maxime Ripard
                   ` (32 preceding siblings ...)
  2022-08-29 13:11 ` [PATCH v2 33/41] drm/vc4: vec: Add support for more analog TV standards Maxime Ripard
@ 2022-08-29 13:11 ` Maxime Ripard
  2022-09-07  8:35   ` (subset) " Maxime Ripard
  2022-08-29 13:11 ` [PATCH v2 35/41] drm/sun4i: tv: Convert to atomic hooks Maxime Ripard
                   ` (7 subsequent siblings)
  41 siblings, 1 reply; 128+ messages in thread
From: Maxime Ripard @ 2022-08-29 13:11 UTC (permalink / raw)
  To: Maxime Ripard, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec,
	Samuel Holland, Karol Herbst, Noralf Trønnes, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Maxime Ripard, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

The mode_valid implementation is pretty much a nop, let's remove it.

Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Reviewed-by: Jernej Skrabec <jernej.skrabec@gmail.com>

diff --git a/drivers/gpu/drm/sun4i/sun4i_tv.c b/drivers/gpu/drm/sun4i/sun4i_tv.c
index 94883abe0dfd..53152d77c392 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tv.c
@@ -497,16 +497,8 @@ static int sun4i_tv_comp_get_modes(struct drm_connector *connector)
 	return i;
 }
 
-static int sun4i_tv_comp_mode_valid(struct drm_connector *connector,
-				    struct drm_display_mode *mode)
-{
-	/* TODO */
-	return MODE_OK;
-}
-
 static const struct drm_connector_helper_funcs sun4i_tv_comp_connector_helper_funcs = {
 	.get_modes	= sun4i_tv_comp_get_modes,
-	.mode_valid	= sun4i_tv_comp_mode_valid,
 };
 
 static void

-- 
b4 0.10.0-dev-65ba7

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

* [PATCH v2 35/41] drm/sun4i: tv: Convert to atomic hooks
  2022-08-29 13:11 [PATCH v2 00/41] drm: Analog TV Improvements Maxime Ripard
                   ` (33 preceding siblings ...)
  2022-08-29 13:11 ` [PATCH v2 34/41] drm/sun4i: tv: Remove unused mode_valid Maxime Ripard
@ 2022-08-29 13:11 ` Maxime Ripard
  2022-09-06 20:02   ` Jernej Škrabec
  2022-09-07  8:35   ` (subset) " Maxime Ripard
  2022-08-29 13:11 ` [PATCH v2 36/41] drm/sun4i: tv: Merge mode_set into atomic_enable Maxime Ripard
                   ` (6 subsequent siblings)
  41 siblings, 2 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-08-29 13:11 UTC (permalink / raw)
  To: Maxime Ripard, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec,
	Samuel Holland, Karol Herbst, Noralf Trønnes, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Maxime Ripard, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

The sun4i TV driver still uses legacy enable and disable hook
implementation. Let's convert to the atomic variants.

Signed-off-by: Maxime Ripard <maxime@cerno.tech>

diff --git a/drivers/gpu/drm/sun4i/sun4i_tv.c b/drivers/gpu/drm/sun4i/sun4i_tv.c
index 53152d77c392..f7aad995ab5b 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tv.c
@@ -339,7 +339,8 @@ static void sun4i_tv_mode_to_drm_mode(const struct tv_mode *tv_mode,
 	mode->vtotal = mode->vsync_end  + tv_mode->vback_porch;
 }
 
-static void sun4i_tv_disable(struct drm_encoder *encoder)
+static void sun4i_tv_disable(struct drm_encoder *encoder,
+			    struct drm_atomic_state *state)
 {
 	struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder);
 	struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc);
@@ -353,7 +354,8 @@ static void sun4i_tv_disable(struct drm_encoder *encoder)
 	sunxi_engine_disable_color_correction(crtc->engine);
 }
 
-static void sun4i_tv_enable(struct drm_encoder *encoder)
+static void sun4i_tv_enable(struct drm_encoder *encoder,
+			    struct drm_atomic_state *state)
 {
 	struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder);
 	struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc);
@@ -469,8 +471,8 @@ static void sun4i_tv_mode_set(struct drm_encoder *encoder,
 }
 
 static const struct drm_encoder_helper_funcs sun4i_tv_helper_funcs = {
-	.disable	= sun4i_tv_disable,
-	.enable		= sun4i_tv_enable,
+	.atomic_disable	= sun4i_tv_disable,
+	.atomic_enable	= sun4i_tv_enable,
 	.mode_set	= sun4i_tv_mode_set,
 };
 

-- 
b4 0.10.0-dev-65ba7

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

* [PATCH v2 36/41] drm/sun4i: tv: Merge mode_set into atomic_enable
  2022-08-29 13:11 [PATCH v2 00/41] drm: Analog TV Improvements Maxime Ripard
                   ` (34 preceding siblings ...)
  2022-08-29 13:11 ` [PATCH v2 35/41] drm/sun4i: tv: Convert to atomic hooks Maxime Ripard
@ 2022-08-29 13:11 ` Maxime Ripard
  2022-09-06 20:04   ` Jernej Škrabec
  2022-09-08 14:02   ` (subset) " Maxime Ripard
  2022-08-29 13:11 ` [PATCH v2 37/41] drm/sun4i: tv: Remove useless function Maxime Ripard
                   ` (5 subsequent siblings)
  41 siblings, 2 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-08-29 13:11 UTC (permalink / raw)
  To: Maxime Ripard, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec,
	Samuel Holland, Karol Herbst, Noralf Trønnes, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Maxime Ripard, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

Our mode_set implementation can be merged into our atomic_enable
implementation to simplify things, so let's do this.

Signed-off-by: Maxime Ripard <maxime@cerno.tech>

diff --git a/drivers/gpu/drm/sun4i/sun4i_tv.c b/drivers/gpu/drm/sun4i/sun4i_tv.c
index f7aad995ab5b..3944da9a3c34 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tv.c
@@ -359,23 +359,13 @@ static void sun4i_tv_enable(struct drm_encoder *encoder,
 {
 	struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder);
 	struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc);
-
-	DRM_DEBUG_DRIVER("Enabling the TV Output\n");
-
-	sunxi_engine_apply_color_correction(crtc->engine);
-
-	regmap_update_bits(tv->regs, SUN4I_TVE_EN_REG,
-			   SUN4I_TVE_EN_ENABLE,
-			   SUN4I_TVE_EN_ENABLE);
-}
-
-static void sun4i_tv_mode_set(struct drm_encoder *encoder,
-			      struct drm_display_mode *mode,
-			      struct drm_display_mode *adjusted_mode)
-{
-	struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder);
+	struct drm_crtc_state *crtc_state =
+		drm_atomic_get_new_crtc_state(state, encoder->crtc);
+	struct drm_display_mode *mode = &crtc_state->mode;
 	const struct tv_mode *tv_mode = sun4i_tv_find_tv_by_mode(mode);
 
+	DRM_DEBUG_DRIVER("Enabling the TV Output\n");
+
 	/* Enable and map the DAC to the output */
 	regmap_update_bits(tv->regs, SUN4I_TVE_EN_REG,
 			   SUN4I_TVE_EN_DAC_MAP_MASK,
@@ -468,12 +458,17 @@ static void sun4i_tv_mode_set(struct drm_encoder *encoder,
 		      SUN4I_TVE_RESYNC_FIELD : 0));
 
 	regmap_write(tv->regs, SUN4I_TVE_SLAVE_REG, 0);
+
+	sunxi_engine_apply_color_correction(crtc->engine);
+
+	regmap_update_bits(tv->regs, SUN4I_TVE_EN_REG,
+			   SUN4I_TVE_EN_ENABLE,
+			   SUN4I_TVE_EN_ENABLE);
 }
 
 static const struct drm_encoder_helper_funcs sun4i_tv_helper_funcs = {
 	.atomic_disable	= sun4i_tv_disable,
 	.atomic_enable	= sun4i_tv_enable,
-	.mode_set	= sun4i_tv_mode_set,
 };
 
 static int sun4i_tv_comp_get_modes(struct drm_connector *connector)

-- 
b4 0.10.0-dev-65ba7

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

* [PATCH v2 37/41] drm/sun4i: tv: Remove useless function
  2022-08-29 13:11 [PATCH v2 00/41] drm: Analog TV Improvements Maxime Ripard
                   ` (35 preceding siblings ...)
  2022-08-29 13:11 ` [PATCH v2 36/41] drm/sun4i: tv: Merge mode_set into atomic_enable Maxime Ripard
@ 2022-08-29 13:11 ` Maxime Ripard
  2022-09-06 20:06   ` Jernej Škrabec
  2022-09-07  8:35   ` (subset) " Maxime Ripard
  2022-08-29 13:11 ` [PATCH v2 38/41] drm/sun4i: tv: Remove useless destroy function Maxime Ripard
                   ` (4 subsequent siblings)
  41 siblings, 2 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-08-29 13:11 UTC (permalink / raw)
  To: Maxime Ripard, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec,
	Samuel Holland, Karol Herbst, Noralf Trønnes, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Maxime Ripard, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

The drm_connector_to_sun4i_tv() function isn't used anywhere in the driver,
so let's remove it.

Signed-off-by: Maxime Ripard <maxime@cerno.tech>

diff --git a/drivers/gpu/drm/sun4i/sun4i_tv.c b/drivers/gpu/drm/sun4i/sun4i_tv.c
index 3944da9a3c34..52bbba8f19dc 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tv.c
@@ -275,13 +275,6 @@ drm_encoder_to_sun4i_tv(struct drm_encoder *encoder)
 			    encoder);
 }
 
-static inline struct sun4i_tv *
-drm_connector_to_sun4i_tv(struct drm_connector *connector)
-{
-	return container_of(connector, struct sun4i_tv,
-			    connector);
-}
-
 /*
  * FIXME: If only the drm_display_mode private field was usable, this
  * could go away...

-- 
b4 0.10.0-dev-65ba7

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

* [PATCH v2 38/41] drm/sun4i: tv: Remove useless destroy function
  2022-08-29 13:11 [PATCH v2 00/41] drm: Analog TV Improvements Maxime Ripard
                   ` (36 preceding siblings ...)
  2022-08-29 13:11 ` [PATCH v2 37/41] drm/sun4i: tv: Remove useless function Maxime Ripard
@ 2022-08-29 13:11 ` Maxime Ripard
  2022-09-07  8:35   ` (subset) " Maxime Ripard
  2022-08-29 13:11 ` [PATCH v2 39/41] drm/sun4i: tv: Rename error label Maxime Ripard
                   ` (3 subsequent siblings)
  41 siblings, 1 reply; 128+ messages in thread
From: Maxime Ripard @ 2022-08-29 13:11 UTC (permalink / raw)
  To: Maxime Ripard, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec,
	Samuel Holland, Karol Herbst, Noralf Trønnes, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Maxime Ripard, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

Our destroy implementation is just calling the generic helper, so let's
just remove our function and directly use the helper.

Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Reviewed-by: Jernej Skrabec <jernej.skrabec@gmail.com>

diff --git a/drivers/gpu/drm/sun4i/sun4i_tv.c b/drivers/gpu/drm/sun4i/sun4i_tv.c
index 52bbba8f19dc..6d7e1d51569a 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tv.c
@@ -491,15 +491,9 @@ static const struct drm_connector_helper_funcs sun4i_tv_comp_connector_helper_fu
 	.get_modes	= sun4i_tv_comp_get_modes,
 };
 
-static void
-sun4i_tv_comp_connector_destroy(struct drm_connector *connector)
-{
-	drm_connector_cleanup(connector);
-}
-
 static const struct drm_connector_funcs sun4i_tv_comp_connector_funcs = {
 	.fill_modes		= drm_helper_probe_single_connector_modes,
-	.destroy		= sun4i_tv_comp_connector_destroy,
+	.destroy		= drm_connector_cleanup,
 	.reset			= drm_atomic_helper_connector_reset,
 	.atomic_duplicate_state	= drm_atomic_helper_connector_duplicate_state,
 	.atomic_destroy_state	= drm_atomic_helper_connector_destroy_state,

-- 
b4 0.10.0-dev-65ba7

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

* [PATCH v2 39/41] drm/sun4i: tv: Rename error label
  2022-08-29 13:11 [PATCH v2 00/41] drm: Analog TV Improvements Maxime Ripard
                   ` (37 preceding siblings ...)
  2022-08-29 13:11 ` [PATCH v2 38/41] drm/sun4i: tv: Remove useless destroy function Maxime Ripard
@ 2022-08-29 13:11 ` Maxime Ripard
  2022-09-07  8:35   ` (subset) " Maxime Ripard
  2022-08-29 13:11 ` [PATCH v2 40/41] drm/sun4i: tv: Add missing reset assertion Maxime Ripard
                   ` (2 subsequent siblings)
  41 siblings, 1 reply; 128+ messages in thread
From: Maxime Ripard @ 2022-08-29 13:11 UTC (permalink / raw)
  To: Maxime Ripard, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec,
	Samuel Holland, Karol Herbst, Noralf Trønnes, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Maxime Ripard, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

The other error labels in sun4i_tv_bind() are named after the task they
perform (err_disable_clk to call clk_disable_unprepare for example).

However, the err_cleanup_connector is named after the calling site
(drm_connector_init failing) and will actually cleanup the encoder. Let's
rename it to err_cleanup_encoder to be consistent.

Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Reviewed-by: Jernej Skrabec <jernej.skrabec@gmail.com>

diff --git a/drivers/gpu/drm/sun4i/sun4i_tv.c b/drivers/gpu/drm/sun4i/sun4i_tv.c
index 6d7e1d51569a..ad6a3739bfa9 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tv.c
@@ -580,7 +580,7 @@ static int sun4i_tv_bind(struct device *dev, struct device *master,
 	if (ret) {
 		dev_err(dev,
 			"Couldn't initialise the Composite connector\n");
-		goto err_cleanup_connector;
+		goto err_cleanup_encoder;
 	}
 	tv->connector.interlace_allowed = true;
 
@@ -588,7 +588,7 @@ static int sun4i_tv_bind(struct device *dev, struct device *master,
 
 	return 0;
 
-err_cleanup_connector:
+err_cleanup_encoder:
 	drm_encoder_cleanup(&tv->encoder);
 err_disable_clk:
 	clk_disable_unprepare(tv->clk);

-- 
b4 0.10.0-dev-65ba7

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

* [PATCH v2 40/41] drm/sun4i: tv: Add missing reset assertion
  2022-08-29 13:11 [PATCH v2 00/41] drm: Analog TV Improvements Maxime Ripard
                   ` (38 preceding siblings ...)
  2022-08-29 13:11 ` [PATCH v2 39/41] drm/sun4i: tv: Rename error label Maxime Ripard
@ 2022-08-29 13:11 ` Maxime Ripard
  2022-09-07  8:35   ` (subset) " Maxime Ripard
  2022-08-29 13:11 ` [PATCH v2 41/41] drm/sun4i: tv: Convert to the new TV mode property Maxime Ripard
  2022-09-01 19:35 ` [PATCH v2 00/41] drm: Analog TV Improvements Noralf Trønnes
  41 siblings, 1 reply; 128+ messages in thread
From: Maxime Ripard @ 2022-08-29 13:11 UTC (permalink / raw)
  To: Maxime Ripard, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec,
	Samuel Holland, Karol Herbst, Noralf Trønnes, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Maxime Ripard, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

The reset line is deasserted at bind, and asserted if we ever encounter an
error there. However, it's never asserted in unbind which will lead to a
resource unbalance.

Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Reviewed-by: Jernej Skrabec <jernej.skrabec@gmail.com>

diff --git a/drivers/gpu/drm/sun4i/sun4i_tv.c b/drivers/gpu/drm/sun4i/sun4i_tv.c
index ad6a3739bfa9..74ff5ad6a8b9 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tv.c
@@ -605,6 +605,7 @@ static void sun4i_tv_unbind(struct device *dev, struct device *master,
 	drm_connector_cleanup(&tv->connector);
 	drm_encoder_cleanup(&tv->encoder);
 	clk_disable_unprepare(tv->clk);
+	reset_control_assert(tv->reset);
 }
 
 static const struct component_ops sun4i_tv_ops = {

-- 
b4 0.10.0-dev-65ba7

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

* [PATCH v2 41/41] drm/sun4i: tv: Convert to the new TV mode property
  2022-08-29 13:11 [PATCH v2 00/41] drm: Analog TV Improvements Maxime Ripard
                   ` (39 preceding siblings ...)
  2022-08-29 13:11 ` [PATCH v2 40/41] drm/sun4i: tv: Add missing reset assertion Maxime Ripard
@ 2022-08-29 13:11 ` Maxime Ripard
  2022-09-01 19:35 ` [PATCH v2 00/41] drm: Analog TV Improvements Noralf Trønnes
  41 siblings, 0 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-08-29 13:11 UTC (permalink / raw)
  To: Maxime Ripard, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec,
	Samuel Holland, Karol Herbst, Noralf Trønnes, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Maxime Ripard, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

Now that the core can deal fine with analog TV modes, let's convert the
sun4i TV driver to leverage those new features.

Signed-off-by: Maxime Ripard <maxime@cerno.tech>

diff --git a/drivers/gpu/drm/sun4i/sun4i_tv.c b/drivers/gpu/drm/sun4i/sun4i_tv.c
index 74ff5ad6a8b9..10c0d727d700 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tv.c
@@ -140,23 +140,14 @@ struct resync_parameters {
 struct tv_mode {
 	char		*name;
 
+	unsigned int	tv_mode;
+
 	u32		mode;
 	u32		chroma_freq;
 	u16		back_porch;
 	u16		front_porch;
-	u16		line_number;
 	u16		vblank_level;
 
-	u32		hdisplay;
-	u16		hfront_porch;
-	u16		hsync_len;
-	u16		hback_porch;
-
-	u32		vdisplay;
-	u16		vfront_porch;
-	u16		vsync_len;
-	u16		vback_porch;
-
 	bool		yc_en;
 	bool		dac3_en;
 	bool		dac_bit25_en;
@@ -212,7 +203,7 @@ static const struct resync_parameters pal_resync_parameters = {
 
 static const struct tv_mode tv_modes[] = {
 	{
-		.name		= "NTSC",
+		.tv_mode	= DRM_MODE_TV_MODE_NTSC_M,
 		.mode		= SUN4I_TVE_CFG0_RES_480i,
 		.chroma_freq	= 0x21f07c1f,
 		.yc_en		= true,
@@ -221,17 +212,6 @@ static const struct tv_mode tv_modes[] = {
 
 		.back_porch	= 118,
 		.front_porch	= 32,
-		.line_number	= 525,
-
-		.hdisplay	= 720,
-		.hfront_porch	= 18,
-		.hsync_len	= 2,
-		.hback_porch	= 118,
-
-		.vdisplay	= 480,
-		.vfront_porch	= 26,
-		.vsync_len	= 2,
-		.vback_porch	= 17,
 
 		.vblank_level	= 240,
 
@@ -241,23 +221,12 @@ static const struct tv_mode tv_modes[] = {
 		.resync_params	= &ntsc_resync_parameters,
 	},
 	{
-		.name		= "PAL",
+		.tv_mode	= DRM_MODE_TV_MODE_PAL_B,
 		.mode		= SUN4I_TVE_CFG0_RES_576i,
 		.chroma_freq	= 0x2a098acb,
 
 		.back_porch	= 138,
 		.front_porch	= 24,
-		.line_number	= 625,
-
-		.hdisplay	= 720,
-		.hfront_porch	= 3,
-		.hsync_len	= 2,
-		.hback_porch	= 139,
-
-		.vdisplay	= 576,
-		.vfront_porch	= 28,
-		.vsync_len	= 2,
-		.vback_porch	= 19,
 
 		.vblank_level	= 252,
 
@@ -275,63 +244,21 @@ drm_encoder_to_sun4i_tv(struct drm_encoder *encoder)
 			    encoder);
 }
 
-/*
- * FIXME: If only the drm_display_mode private field was usable, this
- * could go away...
- *
- * So far, it doesn't seem to be preserved when the mode is passed by
- * to mode_set for some reason.
- */
-static const struct tv_mode *sun4i_tv_find_tv_by_mode(const struct drm_display_mode *mode)
+static const struct tv_mode *
+sun4i_tv_find_tv_by_mode(unsigned int mode)
 {
 	int i;
 
-	/* First try to identify the mode by name */
 	for (i = 0; i < ARRAY_SIZE(tv_modes); i++) {
 		const struct tv_mode *tv_mode = &tv_modes[i];
 
-		DRM_DEBUG_DRIVER("Comparing mode %s vs %s",
-				 mode->name, tv_mode->name);
-
-		if (!strcmp(mode->name, tv_mode->name))
-			return tv_mode;
-	}
-
-	/* Then by number of lines */
-	for (i = 0; i < ARRAY_SIZE(tv_modes); i++) {
-		const struct tv_mode *tv_mode = &tv_modes[i];
-
-		DRM_DEBUG_DRIVER("Comparing mode %s vs %s (X: %d vs %d)",
-				 mode->name, tv_mode->name,
-				 mode->vdisplay, tv_mode->vdisplay);
-
-		if (mode->vdisplay == tv_mode->vdisplay)
+		if (tv_mode->tv_mode == mode)
 			return tv_mode;
 	}
 
 	return NULL;
 }
 
-static void sun4i_tv_mode_to_drm_mode(const struct tv_mode *tv_mode,
-				      struct drm_display_mode *mode)
-{
-	DRM_DEBUG_DRIVER("Creating mode %s\n", mode->name);
-
-	mode->type = DRM_MODE_TYPE_DRIVER;
-	mode->clock = 13500;
-	mode->flags = DRM_MODE_FLAG_INTERLACE;
-
-	mode->hdisplay = tv_mode->hdisplay;
-	mode->hsync_start = mode->hdisplay + tv_mode->hfront_porch;
-	mode->hsync_end = mode->hsync_start + tv_mode->hsync_len;
-	mode->htotal = mode->hsync_end  + tv_mode->hback_porch;
-
-	mode->vdisplay = tv_mode->vdisplay;
-	mode->vsync_start = mode->vdisplay + tv_mode->vfront_porch;
-	mode->vsync_end = mode->vsync_start + tv_mode->vsync_len;
-	mode->vtotal = mode->vsync_end  + tv_mode->vback_porch;
-}
-
 static void sun4i_tv_disable(struct drm_encoder *encoder,
 			    struct drm_atomic_state *state)
 {
@@ -355,7 +282,11 @@ static void sun4i_tv_enable(struct drm_encoder *encoder,
 	struct drm_crtc_state *crtc_state =
 		drm_atomic_get_new_crtc_state(state, encoder->crtc);
 	struct drm_display_mode *mode = &crtc_state->mode;
-	const struct tv_mode *tv_mode = sun4i_tv_find_tv_by_mode(mode);
+	struct drm_connector *connector = &tv->connector;
+	struct drm_connector_state *conn_state =
+		drm_atomic_get_new_connector_state(state, connector);
+	const struct tv_mode *tv_mode =
+		sun4i_tv_find_tv_by_mode(conn_state->tv.mode);
 
 	DRM_DEBUG_DRIVER("Enabling the TV Output\n");
 
@@ -403,7 +334,7 @@ static void sun4i_tv_enable(struct drm_encoder *encoder,
 	/* Set the lines setup */
 	regmap_write(tv->regs, SUN4I_TVE_LINE_REG,
 		     SUN4I_TVE_LINE_FIRST(22) |
-		     SUN4I_TVE_LINE_NUMBER(tv_mode->line_number));
+		     SUN4I_TVE_LINE_NUMBER(mode->vtotal));
 
 	regmap_write(tv->regs, SUN4I_TVE_LEVEL_REG,
 		     SUN4I_TVE_LEVEL_BLANK(tv_mode->video_levels->blank) |
@@ -466,35 +397,45 @@ static const struct drm_encoder_helper_funcs sun4i_tv_helper_funcs = {
 
 static int sun4i_tv_comp_get_modes(struct drm_connector *connector)
 {
-	int i;
+	struct drm_display_mode *mode;
+	int count = 0;
 
-	for (i = 0; i < ARRAY_SIZE(tv_modes); i++) {
-		struct drm_display_mode *mode;
-		const struct tv_mode *tv_mode = &tv_modes[i];
-
-		mode = drm_mode_create(connector->dev);
-		if (!mode) {
-			DRM_ERROR("Failed to create a new display mode\n");
-			return 0;
-		}
+	mode = drm_mode_analog_ntsc_480i(connector->dev);
+	if (!mode) {
+		DRM_ERROR("Failed to create a new display mode\n");
+		return -ENOMEM;
+	}
 
-		strcpy(mode->name, tv_mode->name);
+	drm_mode_probed_add(connector, mode);
+	count += 1;
 
-		sun4i_tv_mode_to_drm_mode(tv_mode, mode);
-		drm_mode_probed_add(connector, mode);
+	mode = drm_mode_analog_pal_576i(connector->dev);
+	if (!mode) {
+		DRM_ERROR("Failed to create a new display mode\n");
+		return -ENOMEM;
 	}
 
-	return i;
+	drm_mode_probed_add(connector, mode);
+	count += 1;
+
+	return count;
 }
 
 static const struct drm_connector_helper_funcs sun4i_tv_comp_connector_helper_funcs = {
+	.atomic_check	= drm_atomic_helper_connector_tv_check,
 	.get_modes	= sun4i_tv_comp_get_modes,
 };
 
+static void sun4i_tv_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 sun4i_tv_comp_connector_funcs = {
 	.fill_modes		= drm_helper_probe_single_connector_modes,
 	.destroy		= drm_connector_cleanup,
-	.reset			= drm_atomic_helper_connector_reset,
+	.reset			= sun4i_tv_connector_reset,
 	.atomic_duplicate_state	= drm_atomic_helper_connector_duplicate_state,
 	.atomic_destroy_state	= drm_atomic_helper_connector_destroy_state,
 };
@@ -586,8 +527,20 @@ static int sun4i_tv_bind(struct device *dev, struct device *master,
 
 	drm_connector_attach_encoder(&tv->connector, &tv->encoder);
 
+	ret = drm_mode_create_tv_properties(drm,
+					    BIT(DRM_MODE_TV_MODE_NTSC_M) |
+					    BIT(DRM_MODE_TV_MODE_PAL_B));
+	if (ret)
+		goto err_cleanup_connector;
+
+	drm_object_attach_property(&connector->base,
+				   dev->mode_config.tv_mode_property,
+				   DRM_MODE_TV_MODE_NTSC_M);
+
 	return 0;
 
+err_cleanup_connector:
+	drm_connector_cleanup(&tv->connector);
 err_cleanup_encoder:
 	drm_encoder_cleanup(&tv->encoder);
 err_disable_clk:

-- 
b4 0.10.0-dev-65ba7

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

* Re: [PATCH v2 01/41] drm/tests: Order Kunit tests in Makefile
  2022-08-29 13:11 ` [PATCH v2 01/41] drm/tests: Order Kunit tests in Makefile Maxime Ripard
@ 2022-08-29 18:46   ` Noralf Trønnes
  2022-08-29 19:02     ` Konstantin Ryabitsev
  0 siblings, 1 reply; 128+ messages in thread
From: Noralf Trønnes @ 2022-08-29 18:46 UTC (permalink / raw)
  To: Maxime Ripard, Maxime Ripard, Ben Skeggs, David Airlie,
	Chen-Yu Tsai, Thomas Zimmermann, Jani Nikula, Lyude Paul,
	Philipp Zabel, Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin,
	Jernej Skrabec, Samuel Holland, Karol Herbst, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Hans de Goede, linux-arm-kernel, Phil Elwell, intel-gfx,
	Dave Stevenson, dri-devel, Dom Cobley, linux-kernel, nouveau,
	linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven,
	Noralf Trønnes



Den 29.08.2022 15.11, skrev Maxime Ripard:
> Since we've recently added a ton of tests, the list starts to be a bit
> 
> of a mess and creates unneeded conflicts.
> 
> 
> 
> Let's order it alphabetically.
> 
> 
> 
> Signed-off-by: Maxime Ripard <maxime@cerno.tech>
> 
> 
> 

Something has gone wrong with this patchset, there are double line endings.

I looked at the patchwork version and it look all right there so I
figured it might have fixed up the patches, but it failed:

git apply -v --check
/home/pi/tinydrm.gud-gadget/workdirs/tv_norm_gadget/500003.patch
Checking patch drivers/gpu/drm/tests/Makefile...
error: while searching for:
# SPDX-License-Identifier: GPL-2.0?
?
obj-$(CONFIG_DRM_KUNIT_TEST) += drm_format_helper_test.o
drm_damage_helper_test.o \?
        drm_cmdline_parser_test.o drm_rect_test.o drm_format_test.o
drm_plane_helper_test.o \?
        drm_dp_mst_helper_test.o drm_framebuffer_test.o drm_buddy_test.o
drm_mm_test.o?

error: patch failed: drivers/gpu/drm/tests/Makefile:1
error: drivers/gpu/drm/tests/Makefile: patch does not apply

ERROR: Failed check apply patch

pi@build-server:~/tinydrm.gud-gadget$ file
workdirs/tv_norm_gadget/500003.patch
workdirs/tv_norm_gadget/500003.patch: unified diff output, ASCII text,
with CRLF, LF line terminators

Noralf.

> diff --git a/drivers/gpu/drm/tests/Makefile b/drivers/gpu/drm/tests/Makefile
> 
> index 91b70f7d2769..2d9f49b62ecb 100644
> 
> --- a/drivers/gpu/drm/tests/Makefile
> 
> +++ b/drivers/gpu/drm/tests/Makefile
> 
> @@ -1,5 +1,13 @@
> 
>  # SPDX-License-Identifier: GPL-2.0
> 
>  
> 
> -obj-$(CONFIG_DRM_KUNIT_TEST) += drm_format_helper_test.o drm_damage_helper_test.o \
> 
> -	drm_cmdline_parser_test.o drm_rect_test.o drm_format_test.o drm_plane_helper_test.o \
> 
> -	drm_dp_mst_helper_test.o drm_framebuffer_test.o drm_buddy_test.o drm_mm_test.o
> 
> +obj-$(CONFIG_DRM_KUNIT_TEST) += \
> 
> +	drm_buddy_test.o \
> 
> +	drm_cmdline_parser_test.o \
> 
> +	drm_damage_helper_test.o \
> 
> +	drm_dp_mst_helper_test.o \
> 
> +	drm_format_helper_test.o \
> 
> +	drm_format_test.o \
> 
> +	drm_framebuffer_test.o \
> 
> +	drm_mm_test.o \
> 
> +	drm_plane_helper_test.o \
> 
> +	drm_rect_test.o
> 
> 
> 

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

* Re: [PATCH v2 01/41] drm/tests: Order Kunit tests in Makefile
  2022-08-29 18:46   ` Noralf Trønnes
@ 2022-08-29 19:02     ` Konstantin Ryabitsev
  2022-08-30  8:30       ` Maxime Ripard
  0 siblings, 1 reply; 128+ messages in thread
From: Konstantin Ryabitsev @ 2022-08-29 19:02 UTC (permalink / raw)
  To: Noralf Trønnes
  Cc: Maxime Ripard, Maxime Ripard, Ben Skeggs, David Airlie,
	Chen-Yu Tsai, Thomas Zimmermann, Jani Nikula, Lyude Paul,
	Philipp Zabel, Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin,
	Jernej Skrabec, Samuel Holland, Karol Herbst, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen, Hans de Goede, linux-arm-kernel,
	Phil Elwell, intel-gfx, Dave Stevenson, dri-devel, Dom Cobley,
	linux-kernel, nouveau, linux-sunxi, Mateusz Kwiatkowski,
	Geert Uytterhoeven

On Mon, Aug 29, 2022 at 08:46:42PM +0200, Noralf Trønnes wrote:
> Something has gone wrong with this patchset, there are double line endings.

I noticed this, too, and I think the reason is because these patches were
generated with "b4 send -o", but actually sent using git-send-email. It's not
a use-case I've considered (or tested) and the breakage is because when b4
generates patches with "-o", they are written with CRLF line endings, which is
not something git-send-email expects.

Maxime, any reason you went this direction instead of just letting b4 send
these patches directly?

-K

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

* Re: [PATCH v2 01/41] drm/tests: Order Kunit tests in Makefile
  2022-08-29 19:02     ` Konstantin Ryabitsev
@ 2022-08-30  8:30       ` Maxime Ripard
  0 siblings, 0 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-08-30  8:30 UTC (permalink / raw)
  To: Konstantin Ryabitsev
  Cc: Noralf Trønnes, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec,
	Samuel Holland, Karol Herbst, Emma Anholt, Daniel Vetter,
	Joonas Lahtinen, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

[-- Attachment #1: Type: text/plain, Size: 8754 bytes --]

Hi Konstantin,

On Mon, Aug 29, 2022 at 03:02:42PM -0400, Konstantin Ryabitsev wrote:
> On Mon, Aug 29, 2022 at 08:46:42PM +0200, Noralf Trønnes wrote:
> > Something has gone wrong with this patchset, there are double line endings.
> 
> I noticed this, too, and I think the reason is because these patches were
> generated with "b4 send -o", but actually sent using git-send-email. It's not
> a use-case I've considered (or tested) and the breakage is because when b4
> generates patches with "-o", they are written with CRLF line endings, which is
> not something git-send-email expects.

You're right

> Maxime, any reason you went this direction instead of just letting b4 send
> these patches directly?

For some reason, b4 send doesn't work for my setup and I haven't had the
time to look into why and let you know.

Whenever I used b4 send (on this series for example) I get:

$ b4 send
Converted the branch to 41 patches
Populating the To: and Cc: fields with automatically collected addresses
Invoking get_maintainer.pl for To: addresses
Invoking get_maintainer.pl for Cc: addresses
Will send the following messages:
---
To: David Airlie <airlied@linux.ie>
    Daniel Vetter <daniel@ffwll.ch>
    Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
    Maxime Ripard <mripard@kernel.org>
    Thomas Zimmermann <tzimmermann@suse.de>
    Noralf Trønnes <noralf@tronnes.org>
    Emma Anholt <emma@anholt.net>
    Ben Skeggs <bskeggs@redhat.com>
    Karol Herbst <kherbst@redhat.com>
    Lyude Paul <lyude@redhat.com>
    Jani Nikula <jani.nikula@linux.intel.com>
    Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
    Rodrigo Vivi <rodrigo.vivi@intel.com>
    Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com>
    Chen-Yu Tsai <wens@csie.org>
    Jernej Skrabec <jernej.skrabec@gmail.com>
    Samuel Holland <samuel@sholland.org>
    Philipp Zabel <p.zabel@pengutronix.de>
Cc: dri-devel@lists.freedesktop.org
    linux-kernel@vger.kernel.org
    nouveau@lists.freedesktop.org
    intel-gfx@lists.freedesktop.org
    linux-arm-kernel@lists.infradead.org
    linux-sunxi@lists.linux.dev
    Dom Cobley <dom@raspberrypi.com>
    Maxime Ripard <maxime@cerno.tech>
    Geert Uytterhoeven <geert@linux-m68k.org>
    Hans de Goede <hdegoede@redhat.com>
    Dave Stevenson <dave.stevenson@raspberrypi.com>
    Mateusz Kwiatkowski <kfyatek+publicgit@gmail.com>
    Phil Elwell <phil@raspberrypi.com>
---
  [PATCH v2 00/41] drm: Analog TV Improvements
  [PATCH v2 01/41] drm/tests: Order Kunit tests in Makefile
  [PATCH v2 02/41] drm/tests: Add Kunit Helpers
  [PATCH v2 03/41] drm/atomic-helper: Rename drm_atomic_helper_connector_tv_reset to avoid ambiguity
  [PATCH v2 04/41] drm/connector: Rename subconnector state variable
  [PATCH v2 05/41] drm/atomic: Add TV subconnector property to get/set_property
  [PATCH v2 06/41] drm/connector: Rename legacy TV property
  [PATCH v2 07/41] drm/connector: Only register TV mode property if present
  [PATCH v2 08/41] drm/connector: Rename drm_mode_create_tv_properties
  [PATCH v2 09/41] drm/connector: Add TV standard property
  [PATCH v2 10/41] drm/modes: Add a function to generate analog display modes
  [PATCH v2 11/41] drm/modes: Only consider bpp and refresh before options
  [PATCH v2 12/41] drm/modes: parse_cmdline: Add support for named modes containing dashes
  [PATCH v2 13/41] drm/client: Add some tests for drm_connector_pick_cmdline_mode()
  [PATCH v2 14/41] drm/modes: Move named modes parsing to a separate function
  [PATCH v2 15/41] drm/modes: Switch to named mode descriptors
  [PATCH v2 16/41] drm/modes: Fill drm_cmdline mode from named modes
  [PATCH v2 17/41] drm/connector: Add pixel clock to cmdline mode
  [PATCH v2 18/41] drm/connector: Add a function to lookup a TV mode by its name
  [PATCH v2 19/41] drm/modes: Introduce the tv_mode property as a command-line option
  [PATCH v2 20/41] drm/modes: Properly generate a drm_display_mode from a named mode
  [PATCH v2 21/41] drm/modes: Introduce more named modes
  [PATCH v2 22/41] drm/atomic-helper: Add a TV properties reset helper
  [PATCH v2 23/41] drm/atomic-helper: Add an analog TV atomic_check implementation
  [PATCH v2 24/41] drm/vc4: vec: Remove empty mode_fixup
  [PATCH v2 25/41] drm/vc4: vec: Convert to atomic helpers
  [PATCH v2 26/41] drm/vc4: vec: Refactor VEC TV mode setting
  [PATCH v2 27/41] drm/vc4: vec: Remove redundant atomic_mode_set
  [PATCH v2 28/41] drm/vc4: vec: Fix timings for VEC modes
  [PATCH v2 29/41] drm/vc4: vec: Switch for common modes
  [PATCH v2 30/41] drm/vc4: vec: Fix definition of PAL-M mode
  [PATCH v2 31/41] drm/vc4: vec: Use TV Reset implementation
  [PATCH v2 32/41] drm/vc4: vec: Convert to the new TV mode property
  [PATCH v2 33/41] drm/vc4: vec: Add support for more analog TV standards
  [PATCH v2 34/41] drm/sun4i: tv: Remove unused mode_valid
  [PATCH v2 35/41] drm/sun4i: tv: Convert to atomic hooks
  [PATCH v2 36/41] drm/sun4i: tv: Merge mode_set into atomic_enable
  [PATCH v2 37/41] drm/sun4i: tv: Remove useless function
  [PATCH v2 38/41] drm/sun4i: tv: Remove useless destroy function
  [PATCH v2 39/41] drm/sun4i: tv: Rename error label
  [PATCH v2 40/41] drm/sun4i: tv: Add missing reset assertion
  [PATCH v2 41/41] drm/sun4i: tv: Convert to the new TV mode property
---
Press Enter to send or Ctrl-C to abort
  [PATCH v2 00/41] drm: Analog TV Improvements
  [PATCH v2 01/41] drm/tests: Order Kunit tests in Makefile
  [PATCH v2 02/41] drm/tests: Add Kunit Helpers
  [PATCH v2 03/41] drm/atomic-helper: Rename drm_atomic_helper_connector_tv_reset to avoid ambiguity
  [PATCH v2 04/41] drm/connector: Rename subconnector state variable
  [PATCH v2 05/41] drm/atomic: Add TV subconnector property to get/set_property
  [PATCH v2 06/41] drm/connector: Rename legacy TV property
  [PATCH v2 07/41] drm/connector: Only register TV mode property if present
  [PATCH v2 08/41] drm/connector: Rename drm_mode_create_tv_properties
  [PATCH v2 09/41] drm/connector: Add TV standard property
  [PATCH v2 10/41] drm/modes: Add a function to generate analog display modes
  [PATCH v2 11/41] drm/modes: Only consider bpp and refresh before options
  [PATCH v2 12/41] drm/modes: parse_cmdline: Add support for named modes containing dashes
  [PATCH v2 13/41] drm/client: Add some tests for drm_connector_pick_cmdline_mode()
  [PATCH v2 14/41] drm/modes: Move named modes parsing to a separate function
  [PATCH v2 15/41] drm/modes: Switch to named mode descriptors
  [PATCH v2 16/41] drm/modes: Fill drm_cmdline mode from named modes
  [PATCH v2 17/41] drm/connector: Add pixel clock to cmdline mode
  [PATCH v2 18/41] drm/connector: Add a function to lookup a TV mode by its name
  [PATCH v2 19/41] drm/modes: Introduce the tv_mode property as a command-line option
  [PATCH v2 20/41] drm/modes: Properly generate a drm_display_mode from a named mode
  [PATCH v2 21/41] drm/modes: Introduce more named modes
  [PATCH v2 22/41] drm/atomic-helper: Add a TV properties reset helper
  [PATCH v2 23/41] drm/atomic-helper: Add an analog TV atomic_check implementation
  [PATCH v2 24/41] drm/vc4: vec: Remove empty mode_fixup
  [PATCH v2 25/41] drm/vc4: vec: Convert to atomic helpers
  [PATCH v2 26/41] drm/vc4: vec: Refactor VEC TV mode setting
  [PATCH v2 27/41] drm/vc4: vec: Remove redundant atomic_mode_set
  [PATCH v2 28/41] drm/vc4: vec: Fix timings for VEC modes
  [PATCH v2 29/41] drm/vc4: vec: Switch for common modes
  [PATCH v2 30/41] drm/vc4: vec: Fix definition of PAL-M mode
  [PATCH v2 31/41] drm/vc4: vec: Use TV Reset implementation
  [PATCH v2 32/41] drm/vc4: vec: Convert to the new TV mode property
  [PATCH v2 33/41] drm/vc4: vec: Add support for more analog TV standards
  [PATCH v2 34/41] drm/sun4i: tv: Remove unused mode_valid
  [PATCH v2 35/41] drm/sun4i: tv: Convert to atomic hooks
  [PATCH v2 36/41] drm/sun4i: tv: Merge mode_set into atomic_enable
  [PATCH v2 37/41] drm/sun4i: tv: Remove useless function
  [PATCH v2 38/41] drm/sun4i: tv: Remove useless destroy function
  [PATCH v2 39/41] drm/sun4i: tv: Rename error label
  [PATCH v2 40/41] drm/sun4i: tv: Add missing reset assertion
  [PATCH v2 41/41] drm/sun4i: tv: Convert to the new TV mode property
Connecting to /home/max/.local/bin/msmtpq:0
Failed to configure the smtp connection:
[Errno -2] Name or service not known

msmtpq is basically a sendmail-like tool to queue the mails if the
machine is offline. It is setup in my git config as
sendemail.smtpserver.

git-send-email works just fine, but somehow b4 send fails. I think it's
due to cmd_send calling b4.get_smtp() and expecting to get some
credentials out of it?

Maxime

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

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

* Re: [PATCH v2 14/41] drm/modes: Move named modes parsing to a separate function
  2022-08-29 13:11 ` [PATCH v2 14/41] drm/modes: Move named modes parsing to a separate function Maxime Ripard
@ 2022-08-30 10:06   ` Geert Uytterhoeven
  2022-08-30 10:43     ` Jani Nikula
  0 siblings, 1 reply; 128+ messages in thread
From: Geert Uytterhoeven @ 2022-08-30 10:06 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Maxime Ripard, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec,
	Samuel Holland, Karol Herbst, Noralf Trønnes, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen, Hans de Goede, Linux ARM,
	Phil Elwell, Intel Graphics Development, Dave Stevenson,
	DRI Development, Dom Cobley, Linux Kernel Mailing List,
	Nouveau Dev, linux-sunxi, Mateusz Kwiatkowski

Hi Maxime,

On Mon, Aug 29, 2022 at 3:13 PM Maxime Ripard <maxime@cerno.tech> wrote:
> The current construction of the named mode parsing doesn't allow to extend
> it easily. Let's move it to a separate function so we can add more
> parameters and modes.
>
> Signed-off-by: Maxime Ripard <maxime@cerno.tech>

Thanks for your patch!

> --- a/drivers/gpu/drm/drm_modes.c
> +++ b/drivers/gpu/drm/drm_modes.c
> @@ -1909,6 +1909,9 @@ void drm_connector_list_update(struct drm_connector *connector)
>  }
>  EXPORT_SYMBOL(drm_connector_list_update);
>
> +#define STR_STRICT_EQ(str, len, cmp) \
> +       ((strlen(cmp) == len) && !strncmp(str, cmp, len))

This is not part of the move, but newly added.

> +
>  static int drm_mode_parse_cmdline_bpp(const char *str, char **end_ptr,
>                                       struct drm_cmdline_mode *mode)
>  {
> @@ -2208,6 +2211,52 @@ static const char * const drm_named_modes_whitelist[] = {
>         "PAL",
>  };
>
> +static int drm_mode_parse_cmdline_named_mode(const char *name,
> +                                            unsigned int name_end,
> +                                            struct drm_cmdline_mode *cmdline_mode)
> +{
> +       unsigned int i;
> +
> +       if (!name_end)
> +               return 0;

This is already checked by the caller.

> +
> +       /* If the name starts with a digit, it's not a named mode */
> +       if (isdigit(name[0]))
> +               return 0;
> +
> +       /*
> +        * If there's an equal sign in the name, the command-line
> +        * contains only an option and no mode.
> +        */
> +       if (strnchr(name, name_end, '='))
> +               return 0;
> +
> +       /* The connection status extras can be set without a mode. */
> +       if (STR_STRICT_EQ(name, name_end, "d") ||
> +           STR_STRICT_EQ(name, name_end, "D") ||
> +           STR_STRICT_EQ(name, name_end, "e"))
> +               return 0;

These checks are not part of the move, and should probably be added
in a separate patch.

> +
> +       /*
> +        * We're sure we're a named mode at that point, iterate over the
> +        * list of modes we're aware of.
> +        */
> +       for (i = 0; i < ARRAY_SIZE(drm_named_modes_whitelist); i++) {
> +               int ret;
> +
> +               ret = str_has_prefix(name, drm_named_modes_whitelist[i]);
> +               if (ret != name_end)
> +                       continue;
> +
> +               strcpy(cmdline_mode->name, drm_named_modes_whitelist[i]);
> +               cmdline_mode->specified = true;
> +
> +               return 1;
> +       }
> +
> +       return -EINVAL;
> +}
> +
>  /**
>   * drm_mode_parse_command_line_for_connector - parse command line modeline for connector
>   * @mode_option: optional per connector mode option
> @@ -2244,7 +2293,7 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
>         const char *bpp_ptr = NULL, *refresh_ptr = NULL, *extra_ptr = NULL;
>         const char *options_ptr = NULL;
>         char *bpp_end_ptr = NULL, *refresh_end_ptr = NULL;
> -       int i, len, ret;
> +       int len, ret;
>
>         memset(mode, 0, sizeof(*mode));
>         mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_UNKNOWN;
> @@ -2285,17 +2334,19 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
>                 parse_extras = true;
>         }
>
> -       /* First check for a named mode */
> -       for (i = 0; i < ARRAY_SIZE(drm_named_modes_whitelist); i++) {
> -               ret = str_has_prefix(name, drm_named_modes_whitelist[i]);
> -               if (ret == mode_end) {
> -                       if (refresh_ptr)
> -                               return false; /* named + refresh is invalid */
>
> -                       strcpy(mode->name, drm_named_modes_whitelist[i]);
> -                       mode->specified = true;
> -                       break;
> -               }
> +       if (mode_end) {
> +               ret = drm_mode_parse_cmdline_named_mode(name, mode_end, mode);
> +               if (ret < 0)
> +                       return false;
> +
> +               /*
> +                * Having a mode that starts by a letter (and thus is named)
> +                * and an at-sign (used to specify a refresh rate) is
> +                * disallowed.
> +                */
> +               if (ret && refresh_ptr)
> +                       return false;
>         }
>
>         /* No named mode? Check for a normal mode argument, e.g. 1024x768 */
>

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

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

* Re: [PATCH v2 14/41] drm/modes: Move named modes parsing to a separate function
  2022-08-30 10:06   ` Geert Uytterhoeven
@ 2022-08-30 10:43     ` Jani Nikula
  2022-08-30 12:03       ` Maxime Ripard
  0 siblings, 1 reply; 128+ messages in thread
From: Jani Nikula @ 2022-08-30 10:43 UTC (permalink / raw)
  To: Geert Uytterhoeven, Maxime Ripard
  Cc: Maxime Ripard, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Lyude Paul, Philipp Zabel, Maarten Lankhorst,
	Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec, Samuel Holland,
	Karol Herbst, Noralf Trønnes, Emma Anholt, Daniel Vetter,
	Joonas Lahtinen, Hans de Goede, Linux ARM, Phil Elwell,
	Intel Graphics Development, Dave Stevenson, DRI Development,
	Dom Cobley, Linux Kernel Mailing List, Nouveau Dev, linux-sunxi,
	Mateusz Kwiatkowski

On Tue, 30 Aug 2022, Geert Uytterhoeven <geert@linux-m68k.org> wrote:
> On Mon, Aug 29, 2022 at 3:13 PM Maxime Ripard <maxime@cerno.tech> wrote:
>> +#define STR_STRICT_EQ(str, len, cmp) \
>> +       ((strlen(cmp) == len) && !strncmp(str, cmp, len))
>
> This is not part of the move, but newly added.

The same construct is also duplicated elsewhere in the series, and I
kept being confused by it. The above is precisely the same as:

	str_has_prefix(str, cmp) == len

Which is more intuitive and available in string.h instead of being a
local duplicate.


BR,
Jani.

-- 
Jani Nikula, Intel Open Source Graphics Center

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

* Re: [PATCH v2 14/41] drm/modes: Move named modes parsing to a separate function
  2022-08-30 10:43     ` Jani Nikula
@ 2022-08-30 12:03       ` Maxime Ripard
  2022-08-30 13:36         ` Jani Nikula
  0 siblings, 1 reply; 128+ messages in thread
From: Maxime Ripard @ 2022-08-30 12:03 UTC (permalink / raw)
  To: Jani Nikula
  Cc: Geert Uytterhoeven, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Lyude Paul, Philipp Zabel, Maarten Lankhorst,
	Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec, Samuel Holland,
	Karol Herbst, Noralf Trønnes, Emma Anholt, Daniel Vetter,
	Joonas Lahtinen, Hans de Goede, Linux ARM, Phil Elwell,
	Intel Graphics Development, Dave Stevenson, DRI Development,
	Dom Cobley, Linux Kernel Mailing List, Nouveau Dev, linux-sunxi,
	Mateusz Kwiatkowski

Hi,

On Tue, Aug 30, 2022 at 01:43:07PM +0300, Jani Nikula wrote:
> On Tue, 30 Aug 2022, Geert Uytterhoeven <geert@linux-m68k.org> wrote:
> > On Mon, Aug 29, 2022 at 3:13 PM Maxime Ripard <maxime@cerno.tech> wrote:
> >> +#define STR_STRICT_EQ(str, len, cmp) \
> >> +       ((strlen(cmp) == len) && !strncmp(str, cmp, len))
> >
> > This is not part of the move, but newly added.
> 
> The same construct is also duplicated elsewhere in the series, and I
> kept being confused by it.

I'm not sure what is confusing, but I can add a comment if needed.

> The above is precisely the same as:
> 
> 	str_has_prefix(str, cmp) == len

Here, it's used to make sure we don't have a named mode starting with
either e, d, or D.

If I understood str_has_prefix() right, str_has_prefix("DUMB-MODE", "D")
== strlen("DUMB-MODE") would return true, while it's actually what we
want to avoid.

It's also used indeed in drm_get_tv_mode_from_name(), where we try to
match a list of names with one passed as argument.

With drm_get_tv_mode_from_name("NSTC", strlen("NTSC")), we would end up
calling str_has_prefix("NTSC-J", "NTSC") == strlen("NTSC-J") which would
work. However, we end up calling prefix not a prefix, but an entire
string we want to match against, which is very confusing to me too.

Maxime

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

* Re: [PATCH v2 19/41] drm/modes: Introduce the tv_mode property as a command-line option
  2022-08-29 13:11 ` [PATCH v2 19/41] drm/modes: Introduce the tv_mode property as a command-line option Maxime Ripard
@ 2022-08-30 12:34   ` Maíra Canal
  2022-08-30 12:44   ` Maíra Canal
  2022-09-01 22:46   ` Mateusz Kwiatkowski
  2 siblings, 0 replies; 128+ messages in thread
From: Maíra Canal @ 2022-08-30 12:34 UTC (permalink / raw)
  To: Maxime Ripard, Maxime Ripard, Ben Skeggs, David Airlie,
	Chen-Yu Tsai, Thomas Zimmermann, Jani Nikula, Lyude Paul,
	Philipp Zabel, Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin,
	Jernej Skrabec, Samuel Holland, Karol Herbst,
	Noralf Trønnes, Emma Anholt, Daniel Vetter, Joonas Lahtinen
  Cc: Dom Cobley, Dave Stevenson, nouveau, intel-gfx, linux-kernel,
	dri-devel, linux-sunxi, Hans de Goede, Geert Uytterhoeven,
	Mateusz Kwiatkowski, Phil Elwell, linux-arm-kernel

Hi Maxime,

On 8/29/22 10:11, Maxime Ripard wrote:
> Our new tv mode option allows to specify the TV mode from a property.
> However, it can still be useful, for example to avoid any boot time
> artifact, to set that property directly from the kernel command line.
> 
> Let's add some code to allow it, and some unit tests to exercise that code.
> 
> Signed-off-by: Maxime Ripard <maxime@cerno.tech>
> 
> diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
> index 73d01e755496..a759a4ba0036 100644
> --- a/drivers/gpu/drm/drm_modes.c
> +++ b/drivers/gpu/drm/drm_modes.c
> @@ -2115,6 +2115,30 @@ static int drm_mode_parse_panel_orientation(const char *delim,
>  	return 0;
>  }
>  
> +static int drm_mode_parse_tv_mode(const char *delim,
> +				  struct drm_cmdline_mode *mode)
> +{
> +	const char *value;
> +	unsigned int len;

Looks like this variable len is not being used and is producing the
following warning:

../drivers/gpu/drm/drm_modes.c:2122:15: warning: unused variable 'len'
[-Wunused-variable]
        unsigned int len;
                     ^

Best Regards,
- Maíra Canal

> +	int ret;
> +
> +	if (*delim != '=')
> +		return -EINVAL;
> +
> +	value = delim + 1;
> +	delim = strchr(value, ',');
> +	if (!delim)
> +		delim = value + strlen(value);
> +
> +	ret = drm_get_tv_mode_from_name(value, delim - value);
> +	if (ret < 0)
> +		return ret;
> +
> +	mode->tv_mode = ret;
> +
> +	return 0;
> +}
> +
>  static int drm_mode_parse_cmdline_options(const char *str,
>  					  bool freestanding,
>  					  const struct drm_connector *connector,
> @@ -2184,6 +2208,9 @@ static int drm_mode_parse_cmdline_options(const char *str,
>  		} else if (!strncmp(option, "panel_orientation", delim - option)) {
>  			if (drm_mode_parse_panel_orientation(delim, mode))
>  				return -EINVAL;
> +		} else if (!strncmp(option, "tv_mode", delim - option)) {
> +			if (drm_mode_parse_tv_mode(delim, mode))
> +				return -EINVAL;
>  		} else {
>  			return -EINVAL;
>  		}
> @@ -2212,20 +2239,22 @@ struct drm_named_mode {
>  	unsigned int xres;
>  	unsigned int yres;
>  	unsigned int flags;
> +	unsigned int tv_mode;
>  };
>  
> -#define NAMED_MODE(_name, _pclk, _x, _y, _flags)	\
> +#define NAMED_MODE(_name, _pclk, _x, _y, _flags, _mode)	\
>  	{						\
>  		.name = _name,				\
>  		.pixel_clock_khz = _pclk,		\
>  		.xres = _x,				\
>  		.yres = _y,				\
>  		.flags = _flags,			\
> +		.tv_mode = _mode,			\
>  	}
>  
>  static const struct drm_named_mode drm_named_modes[] = {
> -	NAMED_MODE("NTSC", 13500, 720, 480, DRM_MODE_FLAG_INTERLACE),
> -	NAMED_MODE("PAL", 13500, 720, 576, DRM_MODE_FLAG_INTERLACE),
> +	NAMED_MODE("NTSC", 13500, 720, 480, DRM_MODE_FLAG_INTERLACE, DRM_MODE_TV_MODE_NTSC_M),
> +	NAMED_MODE("PAL", 13500, 720, 576, DRM_MODE_FLAG_INTERLACE, DRM_MODE_TV_MODE_PAL_B),
>  };
>  
>  static int drm_mode_parse_cmdline_named_mode(const char *name,
> @@ -2271,6 +2300,7 @@ static int drm_mode_parse_cmdline_named_mode(const char *name,
>  		cmdline_mode->xres = mode->xres;
>  		cmdline_mode->yres = mode->yres;
>  		cmdline_mode->interlace = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
> +		cmdline_mode->tv_mode = mode->tv_mode;
>  		cmdline_mode->specified = true;
>  
>  		return 1;
> diff --git a/drivers/gpu/drm/tests/drm_cmdline_parser_test.c b/drivers/gpu/drm/tests/drm_cmdline_parser_test.c
> index 59b29cdfdd35..f1e73ed65be0 100644
> --- a/drivers/gpu/drm/tests/drm_cmdline_parser_test.c
> +++ b/drivers/gpu/drm/tests/drm_cmdline_parser_test.c
> @@ -885,6 +885,201 @@ static void drm_cmdline_test_multiple_options(struct kunit *test)
>  	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED);
>  }
>  
> +static void drm_cmdline_test_tv_options(struct kunit *test,
> +					const char *cmdline,
> +					const struct drm_display_mode *expected_mode,
> +					unsigned int expected_tv_mode)
> +{
> +	struct drm_cmdline_mode mode = { };
> +
> +	KUNIT_EXPECT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
> +									  &no_connector, &mode));
> +	KUNIT_EXPECT_TRUE(test, mode.specified);
> +	KUNIT_EXPECT_EQ(test, mode.xres, expected_mode->hdisplay);
> +	KUNIT_EXPECT_EQ(test, mode.yres, expected_mode->vdisplay);
> +	KUNIT_EXPECT_EQ(test, mode.tv_mode, expected_tv_mode);
> +
> +	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
> +
> +	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
> +
> +	KUNIT_EXPECT_FALSE(test, mode.rb);
> +	KUNIT_EXPECT_FALSE(test, mode.cvt);
> +	KUNIT_EXPECT_EQ(test, mode.interlace, !!(expected_mode->flags & DRM_MODE_FLAG_INTERLACE));
> +	KUNIT_EXPECT_FALSE(test, mode.margins);
> +	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED);
> +}
> +
> +static void drm_cmdline_test_tv_option_ntsc_443(struct kunit *test)
> +{
> +	drm_cmdline_test_tv_options(test,
> +				    "720x480i,tv_mode=NTSC-443",
> +				    drm_mode_analog_ntsc_480i(NULL),
> +				    DRM_MODE_TV_MODE_NTSC_443);
> +}
> +
> +static void drm_cmdline_test_tv_option_ntsc_j(struct kunit *test)
> +{
> +	drm_cmdline_test_tv_options(test,
> +				    "720x480i,tv_mode=NTSC-J",
> +				    drm_mode_analog_ntsc_480i(NULL),
> +				    DRM_MODE_TV_MODE_NTSC_J);
> +}
> +
> +static void drm_cmdline_test_tv_option_ntsc_m(struct kunit *test)
> +{
> +	drm_cmdline_test_tv_options(test,
> +				    "720x480i,tv_mode=NTSC-M",
> +				    drm_mode_analog_ntsc_480i(NULL),
> +				    DRM_MODE_TV_MODE_NTSC_M);
> +}
> +
> +static void drm_cmdline_test_tv_option_pal_60(struct kunit *test)
> +{
> +	drm_cmdline_test_tv_options(test,
> +				    "720x576i,tv_mode=PAL-60",
> +				    drm_mode_analog_pal_576i(NULL),
> +				    DRM_MODE_TV_MODE_PAL_60);
> +}
> +
> +static void drm_cmdline_test_tv_option_pal_b(struct kunit *test)
> +{
> +	drm_cmdline_test_tv_options(test,
> +				    "720x576i,tv_mode=PAL-B",
> +				    drm_mode_analog_pal_576i(NULL),
> +				    DRM_MODE_TV_MODE_PAL_B);
> +}
> +
> +static void drm_cmdline_test_tv_option_pal_d(struct kunit *test)
> +{
> +	drm_cmdline_test_tv_options(test,
> +				    "720x576i,tv_mode=PAL-D",
> +				    drm_mode_analog_pal_576i(NULL),
> +				    DRM_MODE_TV_MODE_PAL_D);
> +}
> +
> +static void drm_cmdline_test_tv_option_pal_g(struct kunit *test)
> +{
> +	drm_cmdline_test_tv_options(test,
> +				    "720x576i,tv_mode=PAL-G",
> +				    drm_mode_analog_pal_576i(NULL),
> +				    DRM_MODE_TV_MODE_PAL_G);
> +}
> +
> +static void drm_cmdline_test_tv_option_pal_h(struct kunit *test)
> +{
> +	drm_cmdline_test_tv_options(test,
> +				    "720x576i,tv_mode=PAL-H",
> +				    drm_mode_analog_pal_576i(NULL),
> +				    DRM_MODE_TV_MODE_PAL_H);
> +}
> +
> +static void drm_cmdline_test_tv_option_pal_i(struct kunit *test)
> +{
> +	drm_cmdline_test_tv_options(test,
> +				    "720x576i,tv_mode=PAL-I",
> +				    drm_mode_analog_pal_576i(NULL),
> +				    DRM_MODE_TV_MODE_PAL_I);
> +}
> +
> +static void drm_cmdline_test_tv_option_pal_m(struct kunit *test)
> +{
> +	drm_cmdline_test_tv_options(test,
> +				    "720x480i,tv_mode=PAL-M",
> +				    drm_mode_analog_ntsc_480i(NULL),
> +				    DRM_MODE_TV_MODE_PAL_M);
> +}
> +
> +static void drm_cmdline_test_tv_option_pal_n(struct kunit *test)
> +{
> +	drm_cmdline_test_tv_options(test,
> +				    "720x576i,tv_mode=PAL-N",
> +				    drm_mode_analog_pal_576i(NULL),
> +				    DRM_MODE_TV_MODE_PAL_N);
> +}
> +
> +static void drm_cmdline_test_tv_option_pal_nc(struct kunit *test)
> +{
> +	drm_cmdline_test_tv_options(test,
> +				    "720x576i,tv_mode=PAL-Nc",
> +				    drm_mode_analog_pal_576i(NULL),
> +				    DRM_MODE_TV_MODE_PAL_NC);
> +}
> +
> +static void drm_cmdline_test_tv_option_secam_60(struct kunit *test)
> +{
> +	drm_cmdline_test_tv_options(test,
> +				    "720x576i,tv_mode=SECAM-60",
> +				    drm_mode_analog_pal_576i(NULL),
> +				    DRM_MODE_TV_MODE_SECAM_60);
> +}
> +
> +static void drm_cmdline_test_tv_option_secam_b(struct kunit *test)
> +{
> +	drm_cmdline_test_tv_options(test,
> +				    "720x576i,tv_mode=SECAM-B",
> +				    drm_mode_analog_pal_576i(NULL),
> +				    DRM_MODE_TV_MODE_SECAM_B);
> +}
> +
> +static void drm_cmdline_test_tv_option_secam_d(struct kunit *test)
> +{
> +	drm_cmdline_test_tv_options(test,
> +				    "720x576i,tv_mode=SECAM-D",
> +				    drm_mode_analog_pal_576i(NULL),
> +				    DRM_MODE_TV_MODE_SECAM_D);
> +}
> +
> +static void drm_cmdline_test_tv_option_secam_g(struct kunit *test)
> +{
> +	drm_cmdline_test_tv_options(test,
> +				    "720x576i,tv_mode=SECAM-G",
> +				    drm_mode_analog_pal_576i(NULL),
> +				    DRM_MODE_TV_MODE_SECAM_G);
> +}
> +
> +static void drm_cmdline_test_tv_option_secam_k(struct kunit *test)
> +{
> +	drm_cmdline_test_tv_options(test,
> +				    "720x576i,tv_mode=SECAM-K",
> +				    drm_mode_analog_pal_576i(NULL),
> +				    DRM_MODE_TV_MODE_SECAM_K);
> +}
> +
> +static void drm_cmdline_test_tv_option_secam_k1(struct kunit *test)
> +{
> +	drm_cmdline_test_tv_options(test,
> +				    "720x576i,tv_mode=SECAM-K1",
> +				    drm_mode_analog_pal_576i(NULL),
> +				    DRM_MODE_TV_MODE_SECAM_K1);
> +}
> +
> +static void drm_cmdline_test_tv_option_secam_l(struct kunit *test)
> +{
> +	drm_cmdline_test_tv_options(test,
> +				    "720x576i,tv_mode=SECAM-L",
> +				    drm_mode_analog_pal_576i(NULL),
> +				    DRM_MODE_TV_MODE_SECAM_L);
> +}
> +
> +static void drm_cmdline_test_tv_option_invalid(struct kunit *test)
> +{
> +	struct drm_cmdline_mode mode = { };
> +	const char *cmdline = "720x480i,tv_mode=invalid";
> +
> +	KUNIT_EXPECT_FALSE(test, drm_mode_parse_command_line_for_connector(cmdline,
> +									   &no_connector, &mode));
> +}
> +
> +static void drm_cmdline_test_tv_option_truncated(struct kunit *test)
> +{
> +	struct drm_cmdline_mode mode = { };
> +	const char *cmdline = "720x480i,tv_mode=NTSC";
> +
> +	KUNIT_EXPECT_FALSE(test, drm_mode_parse_command_line_for_connector(cmdline,
> +									   &no_connector, &mode));
> +}
> +
>  static void drm_cmdline_test_invalid_option(struct kunit *test)
>  {
>  	struct drm_cmdline_mode mode = { };
> @@ -1047,6 +1242,27 @@ static struct kunit_case drm_cmdline_parser_tests[] = {
>  	KUNIT_CASE(drm_cmdline_test_name_refresh_invalid_mode),
>  	KUNIT_CASE(drm_cmdline_test_name_option),
>  	KUNIT_CASE(drm_cmdline_test_name_bpp_option),
> +	KUNIT_CASE(drm_cmdline_test_tv_option_ntsc_443),
> +	KUNIT_CASE(drm_cmdline_test_tv_option_ntsc_j),
> +	KUNIT_CASE(drm_cmdline_test_tv_option_ntsc_m),
> +	KUNIT_CASE(drm_cmdline_test_tv_option_pal_60),
> +	KUNIT_CASE(drm_cmdline_test_tv_option_pal_b),
> +	KUNIT_CASE(drm_cmdline_test_tv_option_pal_d),
> +	KUNIT_CASE(drm_cmdline_test_tv_option_pal_g),
> +	KUNIT_CASE(drm_cmdline_test_tv_option_pal_h),
> +	KUNIT_CASE(drm_cmdline_test_tv_option_pal_i),
> +	KUNIT_CASE(drm_cmdline_test_tv_option_pal_m),
> +	KUNIT_CASE(drm_cmdline_test_tv_option_pal_n),
> +	KUNIT_CASE(drm_cmdline_test_tv_option_pal_nc),
> +	KUNIT_CASE(drm_cmdline_test_tv_option_secam_60),
> +	KUNIT_CASE(drm_cmdline_test_tv_option_secam_b),
> +	KUNIT_CASE(drm_cmdline_test_tv_option_secam_d),
> +	KUNIT_CASE(drm_cmdline_test_tv_option_secam_g),
> +	KUNIT_CASE(drm_cmdline_test_tv_option_secam_k),
> +	KUNIT_CASE(drm_cmdline_test_tv_option_secam_k1),
> +	KUNIT_CASE(drm_cmdline_test_tv_option_secam_l),
> +	KUNIT_CASE(drm_cmdline_test_tv_option_invalid),
> +	KUNIT_CASE(drm_cmdline_test_tv_option_truncated),
>  	KUNIT_CASE(drm_cmdline_test_rotate_0),
>  	KUNIT_CASE(drm_cmdline_test_rotate_90),
>  	KUNIT_CASE(drm_cmdline_test_rotate_180),
> diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
> index 49d261977d4e..9589108ba202 100644
> --- a/include/drm/drm_connector.h
> +++ b/include/drm/drm_connector.h
> @@ -1447,6 +1447,11 @@ struct drm_cmdline_mode {
>  	 * @tv_margins: TV margins to apply to the mode.
>  	 */
>  	struct drm_connector_tv_margins tv_margins;
> +
> +	/**
> +	 * @tv_mode: TV mode standard. See DRM_MODE_TV_MODE_*.
> +	 */
> +	enum drm_connector_tv_mode tv_mode;
>  };
>  
>  /**
> 

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

* Re: [PATCH v2 19/41] drm/modes: Introduce the tv_mode property as a command-line option
  2022-08-29 13:11 ` [PATCH v2 19/41] drm/modes: Introduce the tv_mode property as a command-line option Maxime Ripard
  2022-08-30 12:34   ` Maíra Canal
@ 2022-08-30 12:44   ` Maíra Canal
  2022-09-01 22:46   ` Mateusz Kwiatkowski
  2 siblings, 0 replies; 128+ messages in thread
From: Maíra Canal @ 2022-08-30 12:44 UTC (permalink / raw)
  To: Maxime Ripard, Maxime Ripard, Ben Skeggs, David Airlie,
	Chen-Yu Tsai, Thomas Zimmermann, Jani Nikula, Lyude Paul,
	Philipp Zabel, Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin,
	Jernej Skrabec, Samuel Holland, Karol Herbst,
	Noralf Trønnes, Emma Anholt, Daniel Vetter, Joonas Lahtinen
  Cc: Dom Cobley, Dave Stevenson, nouveau, intel-gfx, linux-kernel,
	dri-devel, linux-sunxi, Hans de Goede, Geert Uytterhoeven,
	Mateusz Kwiatkowski, Phil Elwell, linux-arm-kernel

On 8/29/22 10:11, Maxime Ripard wrote:
> Our new tv mode option allows to specify the TV mode from a property.
> However, it can still be useful, for example to avoid any boot time
> artifact, to set that property directly from the kernel command line.
> 
> Let's add some code to allow it, and some unit tests to exercise that code.
> 
> Signed-off-by: Maxime Ripard <maxime@cerno.tech>
> 
> diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
> index 73d01e755496..a759a4ba0036 100644
> --- a/drivers/gpu/drm/drm_modes.c
> +++ b/drivers/gpu/drm/drm_modes.c
> @@ -2115,6 +2115,30 @@ static int drm_mode_parse_panel_orientation(const char *delim,
>  	return 0;
>  }
>  
> +static int drm_mode_parse_tv_mode(const char *delim,
> +				  struct drm_cmdline_mode *mode)
> +{
> +	const char *value;
> +	unsigned int len;
> +	int ret;
> +
> +	if (*delim != '=')
> +		return -EINVAL;
> +
> +	value = delim + 1;
> +	delim = strchr(value, ',');
> +	if (!delim)
> +		delim = value + strlen(value);
> +
> +	ret = drm_get_tv_mode_from_name(value, delim - value);
> +	if (ret < 0)
> +		return ret;
> +
> +	mode->tv_mode = ret;
> +
> +	return 0;
> +}
> +
>  static int drm_mode_parse_cmdline_options(const char *str,
>  					  bool freestanding,
>  					  const struct drm_connector *connector,
> @@ -2184,6 +2208,9 @@ static int drm_mode_parse_cmdline_options(const char *str,
>  		} else if (!strncmp(option, "panel_orientation", delim - option)) {
>  			if (drm_mode_parse_panel_orientation(delim, mode))
>  				return -EINVAL;
> +		} else if (!strncmp(option, "tv_mode", delim - option)) {
> +			if (drm_mode_parse_tv_mode(delim, mode))
> +				return -EINVAL;
>  		} else {
>  			return -EINVAL;
>  		}
> @@ -2212,20 +2239,22 @@ struct drm_named_mode {
>  	unsigned int xres;
>  	unsigned int yres;
>  	unsigned int flags;
> +	unsigned int tv_mode;
>  };
>  
> -#define NAMED_MODE(_name, _pclk, _x, _y, _flags)	\
> +#define NAMED_MODE(_name, _pclk, _x, _y, _flags, _mode)	\
>  	{						\
>  		.name = _name,				\
>  		.pixel_clock_khz = _pclk,		\
>  		.xres = _x,				\
>  		.yres = _y,				\
>  		.flags = _flags,			\
> +		.tv_mode = _mode,			\
>  	}
>  
>  static const struct drm_named_mode drm_named_modes[] = {
> -	NAMED_MODE("NTSC", 13500, 720, 480, DRM_MODE_FLAG_INTERLACE),
> -	NAMED_MODE("PAL", 13500, 720, 576, DRM_MODE_FLAG_INTERLACE),
> +	NAMED_MODE("NTSC", 13500, 720, 480, DRM_MODE_FLAG_INTERLACE, DRM_MODE_TV_MODE_NTSC_M),
> +	NAMED_MODE("PAL", 13500, 720, 576, DRM_MODE_FLAG_INTERLACE, DRM_MODE_TV_MODE_PAL_B),
>  };
>  
>  static int drm_mode_parse_cmdline_named_mode(const char *name,
> @@ -2271,6 +2300,7 @@ static int drm_mode_parse_cmdline_named_mode(const char *name,
>  		cmdline_mode->xres = mode->xres;
>  		cmdline_mode->yres = mode->yres;
>  		cmdline_mode->interlace = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
> +		cmdline_mode->tv_mode = mode->tv_mode;
>  		cmdline_mode->specified = true;
>  
>  		return 1;
> diff --git a/drivers/gpu/drm/tests/drm_cmdline_parser_test.c b/drivers/gpu/drm/tests/drm_cmdline_parser_test.c
> index 59b29cdfdd35..f1e73ed65be0 100644
> --- a/drivers/gpu/drm/tests/drm_cmdline_parser_test.c
> +++ b/drivers/gpu/drm/tests/drm_cmdline_parser_test.c
> @@ -885,6 +885,201 @@ static void drm_cmdline_test_multiple_options(struct kunit *test)
>  	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED);
>  }
>  
> +static void drm_cmdline_test_tv_options(struct kunit *test,
> +					const char *cmdline,
> +					const struct drm_display_mode *expected_mode,
> +					unsigned int expected_tv_mode)
> +{
> +	struct drm_cmdline_mode mode = { };
> +
> +	KUNIT_EXPECT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
> +									  &no_connector, &mode));
> +	KUNIT_EXPECT_TRUE(test, mode.specified);
> +	KUNIT_EXPECT_EQ(test, mode.xres, expected_mode->hdisplay);
> +	KUNIT_EXPECT_EQ(test, mode.yres, expected_mode->vdisplay);
> +	KUNIT_EXPECT_EQ(test, mode.tv_mode, expected_tv_mode);
> +
> +	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
> +
> +	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
> +
> +	KUNIT_EXPECT_FALSE(test, mode.rb);
> +	KUNIT_EXPECT_FALSE(test, mode.cvt);
> +	KUNIT_EXPECT_EQ(test, mode.interlace, !!(expected_mode->flags & DRM_MODE_FLAG_INTERLACE));
> +	KUNIT_EXPECT_FALSE(test, mode.margins);
> +	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED);
> +}
> +
> +static void drm_cmdline_test_tv_option_ntsc_443(struct kunit *test)
> +{
> +	drm_cmdline_test_tv_options(test,
> +				    "720x480i,tv_mode=NTSC-443",
> +				    drm_mode_analog_ntsc_480i(NULL),
> +				    DRM_MODE_TV_MODE_NTSC_443);
> +}
> +
> +static void drm_cmdline_test_tv_option_ntsc_j(struct kunit *test)
> +{
> +	drm_cmdline_test_tv_options(test,
> +				    "720x480i,tv_mode=NTSC-J",
> +				    drm_mode_analog_ntsc_480i(NULL),
> +				    DRM_MODE_TV_MODE_NTSC_J);
> +}
> +
> +static void drm_cmdline_test_tv_option_ntsc_m(struct kunit *test)
> +{
> +	drm_cmdline_test_tv_options(test,
> +				    "720x480i,tv_mode=NTSC-M",
> +				    drm_mode_analog_ntsc_480i(NULL),
> +				    DRM_MODE_TV_MODE_NTSC_M);
> +}
> +
> +static void drm_cmdline_test_tv_option_pal_60(struct kunit *test)
> +{
> +	drm_cmdline_test_tv_options(test,
> +				    "720x576i,tv_mode=PAL-60",
> +				    drm_mode_analog_pal_576i(NULL),
> +				    DRM_MODE_TV_MODE_PAL_60);
> +}
> +
> +static void drm_cmdline_test_tv_option_pal_b(struct kunit *test)
> +{
> +	drm_cmdline_test_tv_options(test,
> +				    "720x576i,tv_mode=PAL-B",
> +				    drm_mode_analog_pal_576i(NULL),
> +				    DRM_MODE_TV_MODE_PAL_B);
> +}
> +
> +static void drm_cmdline_test_tv_option_pal_d(struct kunit *test)
> +{
> +	drm_cmdline_test_tv_options(test,
> +				    "720x576i,tv_mode=PAL-D",
> +				    drm_mode_analog_pal_576i(NULL),
> +				    DRM_MODE_TV_MODE_PAL_D);
> +}
> +
> +static void drm_cmdline_test_tv_option_pal_g(struct kunit *test)
> +{
> +	drm_cmdline_test_tv_options(test,
> +				    "720x576i,tv_mode=PAL-G",
> +				    drm_mode_analog_pal_576i(NULL),
> +				    DRM_MODE_TV_MODE_PAL_G);
> +}
> +
> +static void drm_cmdline_test_tv_option_pal_h(struct kunit *test)
> +{
> +	drm_cmdline_test_tv_options(test,
> +				    "720x576i,tv_mode=PAL-H",
> +				    drm_mode_analog_pal_576i(NULL),
> +				    DRM_MODE_TV_MODE_PAL_H);
> +}
> +
> +static void drm_cmdline_test_tv_option_pal_i(struct kunit *test)
> +{
> +	drm_cmdline_test_tv_options(test,
> +				    "720x576i,tv_mode=PAL-I",
> +				    drm_mode_analog_pal_576i(NULL),
> +				    DRM_MODE_TV_MODE_PAL_I);
> +}
> +
> +static void drm_cmdline_test_tv_option_pal_m(struct kunit *test)
> +{
> +	drm_cmdline_test_tv_options(test,
> +				    "720x480i,tv_mode=PAL-M",
> +				    drm_mode_analog_ntsc_480i(NULL),
> +				    DRM_MODE_TV_MODE_PAL_M);
> +}
> +
> +static void drm_cmdline_test_tv_option_pal_n(struct kunit *test)
> +{
> +	drm_cmdline_test_tv_options(test,
> +				    "720x576i,tv_mode=PAL-N",
> +				    drm_mode_analog_pal_576i(NULL),
> +				    DRM_MODE_TV_MODE_PAL_N);
> +}
> +
> +static void drm_cmdline_test_tv_option_pal_nc(struct kunit *test)
> +{
> +	drm_cmdline_test_tv_options(test,
> +				    "720x576i,tv_mode=PAL-Nc",
> +				    drm_mode_analog_pal_576i(NULL),
> +				    DRM_MODE_TV_MODE_PAL_NC);
> +}
> +
> +static void drm_cmdline_test_tv_option_secam_60(struct kunit *test)
> +{
> +	drm_cmdline_test_tv_options(test,
> +				    "720x576i,tv_mode=SECAM-60",
> +				    drm_mode_analog_pal_576i(NULL),
> +				    DRM_MODE_TV_MODE_SECAM_60);
> +}
> +
> +static void drm_cmdline_test_tv_option_secam_b(struct kunit *test)
> +{
> +	drm_cmdline_test_tv_options(test,
> +				    "720x576i,tv_mode=SECAM-B",
> +				    drm_mode_analog_pal_576i(NULL),
> +				    DRM_MODE_TV_MODE_SECAM_B);
> +}
> +
> +static void drm_cmdline_test_tv_option_secam_d(struct kunit *test)
> +{
> +	drm_cmdline_test_tv_options(test,
> +				    "720x576i,tv_mode=SECAM-D",
> +				    drm_mode_analog_pal_576i(NULL),
> +				    DRM_MODE_TV_MODE_SECAM_D);
> +}
> +
> +static void drm_cmdline_test_tv_option_secam_g(struct kunit *test)
> +{
> +	drm_cmdline_test_tv_options(test,
> +				    "720x576i,tv_mode=SECAM-G",
> +				    drm_mode_analog_pal_576i(NULL),
> +				    DRM_MODE_TV_MODE_SECAM_G);
> +}
> +
> +static void drm_cmdline_test_tv_option_secam_k(struct kunit *test)
> +{
> +	drm_cmdline_test_tv_options(test,
> +				    "720x576i,tv_mode=SECAM-K",
> +				    drm_mode_analog_pal_576i(NULL),
> +				    DRM_MODE_TV_MODE_SECAM_K);
> +}
> +
> +static void drm_cmdline_test_tv_option_secam_k1(struct kunit *test)
> +{
> +	drm_cmdline_test_tv_options(test,
> +				    "720x576i,tv_mode=SECAM-K1",
> +				    drm_mode_analog_pal_576i(NULL),
> +				    DRM_MODE_TV_MODE_SECAM_K1);
> +}
> +
> +static void drm_cmdline_test_tv_option_secam_l(struct kunit *test)
> +{
> +	drm_cmdline_test_tv_options(test,
> +				    "720x576i,tv_mode=SECAM-L",
> +				    drm_mode_analog_pal_576i(NULL),
> +				    DRM_MODE_TV_MODE_SECAM_L);
> +}

Instead of creating a function to each drm_cmdline_test_tv_options test,
you can create a parameterized test [1] for this function. This will
help the readability of the tests.

[1] https://docs.kernel.org/dev-tools/kunit/usage.html#parameterized-testing

> +
> +static void drm_cmdline_test_tv_option_invalid(struct kunit *test)
> +{
> +	struct drm_cmdline_mode mode = { };
> +	const char *cmdline = "720x480i,tv_mode=invalid";
> +
> +	KUNIT_EXPECT_FALSE(test, drm_mode_parse_command_line_for_connector(cmdline,
> +									   &no_connector, &mode));
> +}
> +
> +static void drm_cmdline_test_tv_option_truncated(struct kunit *test)
> +{
> +	struct drm_cmdline_mode mode = { };
> +	const char *cmdline = "720x480i,tv_mode=NTSC";
> +
> +	KUNIT_EXPECT_FALSE(test, drm_mode_parse_command_line_for_connector(cmdline,
> +									   &no_connector, &mode));
> +}
> +

I guess this tests can be incorporated in the future to the negative
tests from Michał Winiarski [2]. I don't know which one will be merged
first.

[2]
https://lore.kernel.org/dri-devel/20220817211236.252091-1-michal.winiarski@intel.com/

Best Regards,
- Maíra Canal

>  static void drm_cmdline_test_invalid_option(struct kunit *test)
>  {
>  	struct drm_cmdline_mode mode = { };
> @@ -1047,6 +1242,27 @@ static struct kunit_case drm_cmdline_parser_tests[] = {
>  	KUNIT_CASE(drm_cmdline_test_name_refresh_invalid_mode),
>  	KUNIT_CASE(drm_cmdline_test_name_option),
>  	KUNIT_CASE(drm_cmdline_test_name_bpp_option),
> +	KUNIT_CASE(drm_cmdline_test_tv_option_ntsc_443),
> +	KUNIT_CASE(drm_cmdline_test_tv_option_ntsc_j),
> +	KUNIT_CASE(drm_cmdline_test_tv_option_ntsc_m),
> +	KUNIT_CASE(drm_cmdline_test_tv_option_pal_60),
> +	KUNIT_CASE(drm_cmdline_test_tv_option_pal_b),
> +	KUNIT_CASE(drm_cmdline_test_tv_option_pal_d),
> +	KUNIT_CASE(drm_cmdline_test_tv_option_pal_g),
> +	KUNIT_CASE(drm_cmdline_test_tv_option_pal_h),
> +	KUNIT_CASE(drm_cmdline_test_tv_option_pal_i),
> +	KUNIT_CASE(drm_cmdline_test_tv_option_pal_m),
> +	KUNIT_CASE(drm_cmdline_test_tv_option_pal_n),
> +	KUNIT_CASE(drm_cmdline_test_tv_option_pal_nc),
> +	KUNIT_CASE(drm_cmdline_test_tv_option_secam_60),
> +	KUNIT_CASE(drm_cmdline_test_tv_option_secam_b),
> +	KUNIT_CASE(drm_cmdline_test_tv_option_secam_d),
> +	KUNIT_CASE(drm_cmdline_test_tv_option_secam_g),
> +	KUNIT_CASE(drm_cmdline_test_tv_option_secam_k),
> +	KUNIT_CASE(drm_cmdline_test_tv_option_secam_k1),
> +	KUNIT_CASE(drm_cmdline_test_tv_option_secam_l),
> +	KUNIT_CASE(drm_cmdline_test_tv_option_invalid),
> +	KUNIT_CASE(drm_cmdline_test_tv_option_truncated),
>  	KUNIT_CASE(drm_cmdline_test_rotate_0),
>  	KUNIT_CASE(drm_cmdline_test_rotate_90),
>  	KUNIT_CASE(drm_cmdline_test_rotate_180),
> diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
> index 49d261977d4e..9589108ba202 100644
> --- a/include/drm/drm_connector.h
> +++ b/include/drm/drm_connector.h
> @@ -1447,6 +1447,11 @@ struct drm_cmdline_mode {
>  	 * @tv_margins: TV margins to apply to the mode.
>  	 */
>  	struct drm_connector_tv_margins tv_margins;
> +
> +	/**
> +	 * @tv_mode: TV mode standard. See DRM_MODE_TV_MODE_*.
> +	 */
> +	enum drm_connector_tv_mode tv_mode;
>  };
>  
>  /**
> 

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

* Re: [PATCH v2 10/41] drm/modes: Add a function to generate analog display modes
  2022-08-29 13:11 ` [PATCH v2 10/41] drm/modes: Add a function to generate analog display modes Maxime Ripard
@ 2022-08-30 13:01   ` Maíra Canal
  2022-09-08 11:10     ` Maxime Ripard
  2022-08-31  1:44   ` Mateusz Kwiatkowski
  2022-09-01 19:09   ` Noralf Trønnes
  2 siblings, 1 reply; 128+ messages in thread
From: Maíra Canal @ 2022-08-30 13:01 UTC (permalink / raw)
  To: Maxime Ripard, Maxime Ripard, Ben Skeggs, David Airlie,
	Chen-Yu Tsai, Thomas Zimmermann, Jani Nikula, Lyude Paul,
	Philipp Zabel, Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin,
	Jernej Skrabec, Samuel Holland, Karol Herbst,
	Noralf Trønnes, Emma Anholt, Daniel Vetter, Joonas Lahtinen
  Cc: Dom Cobley, Dave Stevenson, nouveau, intel-gfx, linux-kernel,
	dri-devel, linux-sunxi, Hans de Goede, Geert Uytterhoeven,
	Mateusz Kwiatkowski, Phil Elwell, linux-arm-kernel

Hi Maxime,

On 8/29/22 10:11, Maxime Ripard wrote:
> Multiple drivers (meson, vc4, sun4i) define analog TV 525-lines and
> 625-lines modes in their drivers.
> 
> Since those modes are fairly standard, and that we'll need to use them
> in more places in the future, it makes sense to move their definition
> into the core framework.
> 
> However, analog display usually have fairly loose timings requirements,
> the only discrete parameters being the total number of lines and pixel
> clock frequency. Thus, we created a function that will create a display
> mode from the standard, the pixel frequency and the active area.
> 
> Signed-off-by: Maxime Ripard <maxime@cerno.tech>
> 
> diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
> index 304004fb80aa..ee581ee17171 100644
> --- a/drivers/gpu/drm/drm_modes.c
> +++ b/drivers/gpu/drm/drm_modes.c
> @@ -116,6 +116,459 @@ void drm_mode_probed_add(struct drm_connector *connector,
>  }
>  EXPORT_SYMBOL(drm_mode_probed_add);
>  
> +enum drm_mode_analog {
> +	DRM_MODE_ANALOG_NTSC,
> +	DRM_MODE_ANALOG_PAL,
> +};
> +
> +/*
> + * The timings come from:
> + * - https://web.archive.org/web/20220406232708/http://www.kolumbus.fi/pami1/video/pal_ntsc.html
> + * - https://web.archive.org/web/20220406124914/http://martin.hinner.info/vga/pal.html
> + * - https://web.archive.org/web/20220609202433/http://www.batsocks.co.uk/readme/video_timing.htm
> + */
> +#define NTSC_LINE_DURATION_NS		63556U
> +#define NTSC_LINES_NUMBER		525
> +
> +#define NTSC_HBLK_DURATION_TYP_NS	10900U
> +#define NTSC_HBLK_DURATION_MIN_NS	(NTSC_HBLK_DURATION_TYP_NS - 200)
> +#define NTSC_HBLK_DURATION_MAX_NS	(NTSC_HBLK_DURATION_TYP_NS + 200)
> +
> +#define NTSC_HACT_DURATION_TYP_NS	(NTSC_LINE_DURATION_NS - NTSC_HBLK_DURATION_TYP_NS)
> +#define NTSC_HACT_DURATION_MIN_NS	(NTSC_LINE_DURATION_NS - NTSC_HBLK_DURATION_MAX_NS)
> +#define NTSC_HACT_DURATION_MAX_NS	(NTSC_LINE_DURATION_NS - NTSC_HBLK_DURATION_MIN_NS)
> +
> +#define NTSC_HFP_DURATION_TYP_NS	1500
> +#define NTSC_HFP_DURATION_MIN_NS	1270
> +#define NTSC_HFP_DURATION_MAX_NS	2220
> +
> +#define NTSC_HSLEN_DURATION_TYP_NS	4700
> +#define NTSC_HSLEN_DURATION_MIN_NS	(NTSC_HSLEN_DURATION_TYP_NS - 100)
> +#define NTSC_HSLEN_DURATION_MAX_NS	(NTSC_HSLEN_DURATION_TYP_NS + 100)
> +
> +#define NTSC_HBP_DURATION_TYP_NS	4700
> +
> +/*
> + * I couldn't find the actual tolerance for the back porch, so let's
> + * just reuse the sync length ones.
> + */
> +#define NTSC_HBP_DURATION_MIN_NS	(NTSC_HBP_DURATION_TYP_NS - 100)
> +#define NTSC_HBP_DURATION_MAX_NS	(NTSC_HBP_DURATION_TYP_NS + 100)
> +
> +#define PAL_LINE_DURATION_NS		64000U
> +#define PAL_LINES_NUMBER		625
> +
> +#define PAL_HACT_DURATION_TYP_NS	51950U
> +#define PAL_HACT_DURATION_MIN_NS	(PAL_HACT_DURATION_TYP_NS - 100)
> +#define PAL_HACT_DURATION_MAX_NS	(PAL_HACT_DURATION_TYP_NS + 400)
> +
> +#define PAL_HBLK_DURATION_TYP_NS	(PAL_LINE_DURATION_NS - PAL_HACT_DURATION_TYP_NS)
> +#define PAL_HBLK_DURATION_MIN_NS	(PAL_LINE_DURATION_NS - PAL_HACT_DURATION_MAX_NS)
> +#define PAL_HBLK_DURATION_MAX_NS	(PAL_LINE_DURATION_NS - PAL_HACT_DURATION_MIN_NS)
> +
> +#define PAL_HFP_DURATION_TYP_NS		1650
> +#define PAL_HFP_DURATION_MIN_NS		(PAL_HFP_DURATION_TYP_NS - 100)
> +#define PAL_HFP_DURATION_MAX_NS		(PAL_HFP_DURATION_TYP_NS + 400)
> +
> +#define PAL_HSLEN_DURATION_TYP_NS	4700
> +#define PAL_HSLEN_DURATION_MIN_NS	(PAL_HSLEN_DURATION_TYP_NS - 200)
> +#define PAL_HSLEN_DURATION_MAX_NS	(PAL_HSLEN_DURATION_TYP_NS + 200)
> +
> +#define PAL_HBP_DURATION_TYP_NS		5700
> +#define PAL_HBP_DURATION_MIN_NS		(PAL_HBP_DURATION_TYP_NS - 200)
> +#define PAL_HBP_DURATION_MAX_NS		(PAL_HBP_DURATION_TYP_NS + 200)
> +
> +#define PAL_VFP_INTERLACE_LINES		5
> +#define PAL_VSLEN_INTERLACE_LINES	5
> +
> +#define PAL_SHORT_SYNC_DURATION_NS	((2 + 30) * NSEC_PER_USEC)
> +#define PAL_LONG_SYNC_DURATION_NS	((30 + 2) * NSEC_PER_USEC)
> +
> +struct analog_param_field {
> +	unsigned int even, odd;
> +};
> +
> +#define PARAM_FIELD(_odd, _even)		\
> +	{ .even = _even, .odd = _odd }
> +
> +struct analog_param_range {
> +	unsigned int	min, typ, max;
> +};
> +
> +#define PARAM_RANGE(_min, _typ, _max)		\
> +	{ .min = _min, .typ = _typ, .max = _max }
> +
> +struct analog_parameters {
> +	unsigned int			num_lines;
> +	unsigned int			line_duration_ns;
> +
> +	struct analog_param_range	hact_ns;
> +	struct analog_param_range	hfp_ns;
> +	struct analog_param_range	hslen_ns;
> +	struct analog_param_range	hbp_ns;
> +	struct analog_param_range	hblk_ns;
> +
> +	struct analog_param_field	vfp_lines;
> +	struct analog_param_field	vslen_lines;
> +	struct analog_param_field	vbp_lines;
> +};
> +
> +#define TV_MODE_PARAMETER(_mode, _lines, _line_dur, _hact, _hfp, _hslen, _hbp, _hblk, _vfp, _vslen, _vbp) \
> +	[_mode] = {							\
> +		.num_lines = _lines,					\
> +		.line_duration_ns = _line_dur,				\
> +		.hact_ns = _hact,					\
> +		.hfp_ns = _hfp,						\
> +		.hslen_ns = _hslen,					\
> +		.hbp_ns = _hbp,						\
> +		.hblk_ns = _hblk,					\
> +		.vfp_lines = _vfp,					\
> +		.vslen_lines = _vslen,					\
> +		.vbp_lines = _vbp,					\
> +	}
> +
> +const static struct analog_parameters tv_modes_parameters[] = {
> +	TV_MODE_PARAMETER(DRM_MODE_ANALOG_NTSC,
> +			  NTSC_LINES_NUMBER,
> +			  NTSC_LINE_DURATION_NS,
> +			  PARAM_RANGE(NTSC_HACT_DURATION_MIN_NS,
> +				      NTSC_HACT_DURATION_TYP_NS,
> +				      NTSC_HACT_DURATION_MAX_NS),
> +			  PARAM_RANGE(NTSC_HFP_DURATION_MIN_NS,
> +				      NTSC_HFP_DURATION_TYP_NS,
> +				      NTSC_HFP_DURATION_MAX_NS),
> +			  PARAM_RANGE(NTSC_HSLEN_DURATION_MIN_NS,
> +				      NTSC_HSLEN_DURATION_TYP_NS,
> +				      NTSC_HSLEN_DURATION_MAX_NS),
> +			  PARAM_RANGE(NTSC_HBP_DURATION_MIN_NS,
> +				      NTSC_HBP_DURATION_TYP_NS,
> +				      NTSC_HBP_DURATION_MAX_NS),
> +			  PARAM_RANGE(NTSC_HBLK_DURATION_MIN_NS,
> +				      NTSC_HBLK_DURATION_TYP_NS,
> +				      NTSC_HBLK_DURATION_MAX_NS),
> +			  PARAM_FIELD(3, 3),
> +			  PARAM_FIELD(3, 3),
> +			  PARAM_FIELD(3, 3)),
> +	TV_MODE_PARAMETER(DRM_MODE_ANALOG_PAL,
> +			  PAL_LINES_NUMBER,
> +			  PAL_LINE_DURATION_NS,
> +			  PARAM_RANGE(PAL_HACT_DURATION_MIN_NS,
> +				      PAL_HACT_DURATION_TYP_NS,
> +				      PAL_HACT_DURATION_MAX_NS),
> +			  PARAM_RANGE(PAL_HFP_DURATION_MIN_NS,
> +				      PAL_HFP_DURATION_TYP_NS,
> +				      PAL_HFP_DURATION_MAX_NS),
> +			  PARAM_RANGE(PAL_HSLEN_DURATION_MIN_NS,
> +				      PAL_HSLEN_DURATION_TYP_NS,
> +				      PAL_HSLEN_DURATION_MAX_NS),
> +			  PARAM_RANGE(PAL_HBP_DURATION_MIN_NS,
> +				      PAL_HBP_DURATION_TYP_NS,
> +				      PAL_HBP_DURATION_MAX_NS),
> +			  PARAM_RANGE(PAL_HBLK_DURATION_MIN_NS,
> +				      PAL_HBLK_DURATION_TYP_NS,
> +				      PAL_HBLK_DURATION_MAX_NS),
> +
> +			  /*
> +			   * The front porch is actually 6 short sync
> +			   * pulses for the even field, and 5 for the
> +			   * odd field. Each sync takes half a life so
> +			   * the odd field front porch is shorter by
> +			   * half a line.
> +			   *
> +			   * In progressive, we're supposed to use 6
> +			   * pulses, so we're fine there
> +			   */
> +			  PARAM_FIELD(3, 2),
> +
> +			  /*
> +			   * The vsync length is 5 long sync pulses,
> +			   * each field taking half a line. We're
> +			   * shorter for both fields by half a line.
> +			   *
> +			   * In progressive, we're supposed to use 5
> +			   * pulses, so we're off by half
> +			   * a line.
> +			   *
> +			   * In interlace, we're now off by half a line
> +			   * for the even field and one line for the odd
> +			   * field.
> +			   */
> +			  PARAM_FIELD(3, 3),
> +
> +			  /*
> +			   * The back porch is actually 5 short sync
> +			   * pulses for the even field, 4 for the odd
> +			   * field. In progressive, it's 5 short syncs.
> +			   *
> +			   * In progressive, we thus have 2.5 lines,
> +			   * plus the 0.5 line we were missing
> +			   * previously, so we should use 3 lines.
> +			   *
> +			   * In interlace, the even field is in the
> +			   * exact same case than progressive. For the
> +			   * odd field, we should be using 2 lines but
> +			   * we're one line short, so we'll make up for
> +			   * it here by using 3.
> +			   */
> +			  PARAM_FIELD(3, 3)),
> +};
> +
> +static int fill_analog_mode(struct drm_display_mode *mode,
> +			    const struct analog_parameters *params,
> +			    unsigned long pixel_clock_hz,
> +			    unsigned int hactive,
> +			    unsigned int vactive,
> +			    bool interlace)
> +{
> +	unsigned long pixel_duration_ns = NSEC_PER_SEC / pixel_clock_hz;
> +	unsigned long long htotal;
> +	unsigned int vtotal;
> +	unsigned int max_hact, hact_duration_ns;
> +	unsigned int hblk, hblk_duration_ns;
> +	unsigned int hfp, hfp_min, hfp_duration_ns;
> +	unsigned int hslen, hslen_duration_ns;
> +	unsigned int hbp, hbp_min, hbp_duration_ns;
> +	unsigned int porches, porches_duration_ns;
> +	unsigned int vfp, vfp_min;
> +	unsigned int vbp, vbp_min;
> +	unsigned int vslen;
> +	int porches_rem;
> +	bool strict = true;
> +
> +	max_hact = params->hact_ns.max / pixel_duration_ns;
> +	if (pixel_clock_hz == 13500000 && hactive > max_hact && hactive <= 720)
> +		strict = false;
> +
> +	/*
> +	 * Our pixel duration is going to be round down by the division,
> +	 * so rounding up is probably going to introduce even more
> +	 * deviation.
> +	 */
> +	htotal = params->line_duration_ns * pixel_clock_hz / NSEC_PER_SEC;
> +
> +	hact_duration_ns = hactive * pixel_duration_ns;
> +	if (strict &&
> +	    (hact_duration_ns < params->hact_ns.min ||
> +	     hact_duration_ns > params->hact_ns.max)) {
> +		DRM_ERROR("Invalid horizontal active area duration: %uns (min: %u, max %u)\n",
> +			  hact_duration_ns, params->hact_ns.min, params->hact_ns.max);
> +		return -EINVAL;
> +	}
> +
> +	hblk = htotal - hactive;
> +	hblk_duration_ns = hblk * pixel_duration_ns;
> +	if (strict &&
> +	    (hblk_duration_ns < params->hblk_ns.min ||
> +	     hblk_duration_ns > params->hblk_ns.max)) {
> +		DRM_ERROR("Invalid horizontal blanking duration: %uns (min: %u, max %u)\n",
> +			  hblk_duration_ns, params->hblk_ns.min, params->hblk_ns.max);
> +		return -EINVAL;
> +	}
> +
> +	hslen = DIV_ROUND_UP(params->hslen_ns.typ, pixel_duration_ns);
> +	hslen_duration_ns = hslen * pixel_duration_ns;
> +	if (strict &&
> +	    (hslen_duration_ns < params->hslen_ns.min ||
> +	     hslen_duration_ns > params->hslen_ns.max)) {
> +		DRM_ERROR("Invalid horizontal sync duration: %uns (min: %u, max %u)\n",
> +			  hslen_duration_ns, params->hslen_ns.min, params->hslen_ns.max);
> +		return -EINVAL;
> +	}
> +
> +	porches = hblk - hslen;
> +	porches_duration_ns = porches * pixel_duration_ns;
> +	if (strict &&
> +	    (porches_duration_ns > (params->hfp_ns.max + params->hbp_ns.max) ||
> +	     porches_duration_ns < (params->hfp_ns.min + params->hbp_ns.min))) {
> +		DRM_ERROR("Invalid horizontal porches duration: %uns\n", porches_duration_ns);
> +		return -EINVAL;
> +	}
> +
> +	hfp_min = DIV_ROUND_UP(params->hfp_ns.min, pixel_duration_ns);
> +	hbp_min = DIV_ROUND_UP(params->hbp_ns.min, pixel_duration_ns);
> +	porches_rem = porches - hfp_min - hbp_min;
> +
> +	hfp = hfp_min + DIV_ROUND_UP(porches_rem, 2);
> +	hfp_duration_ns = hfp * pixel_duration_ns;
> +	if (strict &&
> +	    (hfp_duration_ns < params->hfp_ns.min ||
> +	     hfp_duration_ns > params->hfp_ns.max)) {
> +		DRM_ERROR("Invalid horizontal front porch duration: %uns (min: %u, max %u)\n",
> +			  hfp_duration_ns, params->hfp_ns.min, params->hfp_ns.max);
> +		return -EINVAL;
> +	}
> +
> +	hbp = porches - hfp;
> +	hbp_duration_ns = hbp * pixel_duration_ns;
> +	if (strict &&
> +	    (hbp_duration_ns < params->hbp_ns.min ||
> +	     hbp_duration_ns > params->hbp_ns.max)) {
> +		DRM_ERROR("Invalid horizontal back porch duration: %uns (min: %u, max %u)\n",
> +			  hbp_duration_ns, params->hbp_ns.min, params->hbp_ns.max);
> +		return -EINVAL;
> +	}
> +
> +	if (htotal != (hactive + hfp + hslen + hbp))
> +		return -EINVAL;
> +
> +	mode->clock = pixel_clock_hz / 1000;
> +	mode->hdisplay = hactive;
> +	mode->hsync_start = hactive + hfp;
> +	mode->hsync_end = hactive + hfp + hslen;
> +	mode->htotal = hactive + hfp + hslen + hbp;
> +
> +	if (interlace) {
> +		vfp_min = params->vfp_lines.even + params->vfp_lines.odd;
> +		vbp_min = params->vbp_lines.even + params->vbp_lines.odd;
> +		vslen = params->vslen_lines.even + params->vslen_lines.odd;
> +	} else {
> +		/*
> +		 * By convention, NSTC (aka 525/60) systems start with
> +		 * the even field, but PAL (aka 625/50) systems start
> +		 * with the odd one.
> +		 *
> +		 * PAL systems also have asymetric timings between the
> +		 * even and odd field, while NTSC is symetric.
> +		 *
> +		 * Moreover, if we want to create a progressive mode for
> +		 * PAL, we need to use the odd field timings.
> +		 *
> +		 * Since odd == even for NTSC, we can just use the odd
> +		 * one all the time to simplify the code a bit.
> +		 */
> +		vfp_min = params->vfp_lines.odd;
> +		vbp_min = params->vbp_lines.odd;
> +		vslen = params->vslen_lines.odd;
> +	}
> +
> +	porches = params->num_lines - vactive - vslen;
> +	porches_rem = porches - vfp_min - vbp_min;
> +
> +	vfp = vfp_min + (porches_rem / 2);
> +	vbp = porches - vfp;
> +
> +	vtotal = vactive + vfp + vslen + vbp;
> +	if (params->num_lines != vtotal) {
> +		DRM_ERROR("Invalid vertical total: %upx (expected %upx)\n",
> +			  vtotal, params->num_lines);
> +		return -EINVAL;
> +	}
> +
> +	mode->vdisplay = vactive;
> +	mode->vsync_start = vactive + vfp;
> +	mode->vsync_end = vactive + vfp + vslen;
> +	mode->vtotal = vactive + vfp + vslen + vbp;
> +
> +	mode->type = DRM_MODE_TYPE_DRIVER;
> +	mode->flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC;
> +	if (interlace)
> +		mode->flags |= DRM_MODE_FLAG_INTERLACE;
> +
> +	drm_mode_set_name(mode);
> +
> +	if (mode->vtotal != params->num_lines)
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +/**
> + * drm_analog_tv_mode - create a display mode for an analog TV
> + * @dev: drm device
> + * @tv_mode: TV Mode standard to create a mode for. See DRM_MODE_TV_MODE_*.
> + * @pixel_clock_hz: Pixel Clock Frequency, in Hertz
> + * @hdisplay: hdisplay size
> + * @vdisplay: vdisplay size
> + * @interlace: whether to compute an interlaced mode
> + *
> + * This function creates a struct drm_display_mode instance suited for
> + * an analog TV output, for one of the usual analog TV mode.
> + *
> + * Note that @hdisplay is larger than the usual constraints for the PAL
> + * and NTSC timings, and we'll choose to ignore most timings constraints
> + * to reach those resolutions.
> + *
> + * Returns:
> + *
> + * A pointer to the mode, allocated with drm_mode_create(). Returns NULL
> + * on error.
> + */
> +struct drm_display_mode *drm_analog_tv_mode(struct drm_device *dev,
> +					    enum drm_connector_tv_mode tv_mode,
> +					    unsigned long pixel_clock_hz,
> +					    unsigned int hdisplay,
> +					    unsigned int vdisplay,
> +					    bool interlace)
> +{
> +	struct drm_display_mode *mode;
> +	enum drm_mode_analog analog;
> +	int ret;
> +
> +	switch (tv_mode) {
> +	case DRM_MODE_TV_MODE_NTSC_443:
> +		fallthrough;
> +	case DRM_MODE_TV_MODE_NTSC_J:
> +		fallthrough;
> +	case DRM_MODE_TV_MODE_NTSC_M:
> +		fallthrough;
> +	case DRM_MODE_TV_MODE_PAL_60:
> +		fallthrough;
> +	case DRM_MODE_TV_MODE_PAL_M:
> +		fallthrough;
> +	case DRM_MODE_TV_MODE_SECAM_60:
> +		analog = DRM_MODE_ANALOG_NTSC;
> +		break;
> +
> +	case DRM_MODE_TV_MODE_PAL_B:
> +		fallthrough;
> +	case DRM_MODE_TV_MODE_PAL_D:
> +		fallthrough;
> +	case DRM_MODE_TV_MODE_PAL_G:
> +		fallthrough;
> +	case DRM_MODE_TV_MODE_PAL_H:
> +		fallthrough;
> +	case DRM_MODE_TV_MODE_PAL_I:
> +		fallthrough;
> +	case DRM_MODE_TV_MODE_PAL_N:
> +		fallthrough;
> +	case DRM_MODE_TV_MODE_PAL_NC:
> +		fallthrough;
> +	case DRM_MODE_TV_MODE_SECAM_B:
> +		fallthrough;
> +	case DRM_MODE_TV_MODE_SECAM_D:
> +		fallthrough;
> +	case DRM_MODE_TV_MODE_SECAM_G:
> +		fallthrough;
> +	case DRM_MODE_TV_MODE_SECAM_K:
> +		fallthrough;
> +	case DRM_MODE_TV_MODE_SECAM_K1:
> +		fallthrough;
> +	case DRM_MODE_TV_MODE_SECAM_L:
> +		analog = DRM_MODE_ANALOG_PAL;
> +		break;
> +
> +	default:
> +		return NULL;
> +	}
> +
> +	mode = drm_mode_create(dev);
> +	if (!mode)
> +		return NULL;
> +
> +	ret = fill_analog_mode(mode,
> +			       &tv_modes_parameters[analog],
> +			       pixel_clock_hz, hdisplay, vdisplay, interlace);
> +	if (ret)
> +		goto err_free_mode;
> +
> +	return mode;
> +
> +err_free_mode:
> +	drm_mode_destroy(dev, mode);
> +	return NULL;
> +}
> +EXPORT_SYMBOL(drm_analog_tv_mode);
> +
>  /**
>   * drm_cvt_mode -create a modeline based on the CVT algorithm
>   * @dev: drm device
> diff --git a/drivers/gpu/drm/tests/Makefile b/drivers/gpu/drm/tests/Makefile
> index b29ef1085cad..b22ac96fdd65 100644
> --- a/drivers/gpu/drm/tests/Makefile
> +++ b/drivers/gpu/drm/tests/Makefile
> @@ -10,5 +10,6 @@ obj-$(CONFIG_DRM_KUNIT_TEST) += \
>  	drm_framebuffer_test.o \
>  	drm_kunit_helpers.o \
>  	drm_mm_test.o \
> +	drm_modes_test.o \
>  	drm_plane_helper_test.o \
>  	drm_rect_test.o
> diff --git a/drivers/gpu/drm/tests/drm_modes_test.c b/drivers/gpu/drm/tests/drm_modes_test.c
> new file mode 100644
> index 000000000000..87d398fcb99e
> --- /dev/null
> +++ b/drivers/gpu/drm/tests/drm_modes_test.c
> @@ -0,0 +1,131 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Kunit test for drm_modes functions
> + */
> +
> +#include <kunit/test.h>
> +
> +#include <drm/drm_modes.h>
> +
> +#include "drm_kunit_helpers.h"
> +
> +struct drm_modes_test_priv {
> +	struct drm_device *drm;
> +};
> +
> +static int drm_modes_test_init(struct kunit *test)
> +{
> +	struct drm_modes_test_priv *priv;
> +
> +	priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;

I believe it would be nicer to use KUNIT_ASSERT_NOT_NULL here, instead
of returning a error.

> +	test->priv = priv;
> +
> +	priv->drm = drm_kunit_device_init("drm-modes-test");
> +	if (IS_ERR(priv->drm))
> +		return PTR_ERR(priv->drm);

Here you could use KUNIT_ASSERT_NOT_ERR_OR_NULL.

> +
> +	return 0;
> +}
> +
> +static void drm_modes_test_exit(struct kunit *test)
> +{
> +	struct drm_modes_test_priv *priv = test->priv;
> +
> +	drm_kunit_device_exit(priv->drm);
> +}
> +
> +static void drm_modes_analog_tv_ntsc_480i(struct kunit *test)
> +{
> +	struct drm_modes_test_priv *priv = test->priv;
> +	struct drm_display_mode *mode;
> +
> +	mode = drm_analog_tv_mode(priv->drm,
> +				  DRM_MODE_TV_MODE_NTSC_M,
> +				  13500 * 1000, 720, 480,
> +				  true);
> +	KUNIT_ASSERT_NOT_NULL(test, mode);
> +
> +	KUNIT_EXPECT_EQ(test, drm_mode_vrefresh(mode), 60);
> +	KUNIT_EXPECT_EQ(test, mode->hdisplay, 720);
> +
> +	/* 63.556us * 13.5MHz = 858 pixels */
> +	KUNIT_EXPECT_EQ(test, mode->htotal, 858);
> +	KUNIT_EXPECT_EQ(test, mode->vdisplay, 480);
> +	KUNIT_EXPECT_EQ(test, mode->vtotal, 525);
> +}

I would be nice to see this test and drm_modes_analog_tv_pal_576i
parametrized.

Best Regards,
- Maíra Canal

> +
> +static void drm_modes_analog_tv_ntsc_480i_inlined(struct kunit *test)
> +{
> +	struct drm_modes_test_priv *priv = test->priv;
> +	struct drm_display_mode *expected, *mode;
> +
> +	expected = drm_analog_tv_mode(priv->drm,
> +				      DRM_MODE_TV_MODE_NTSC_M,
> +				      13500 * 1000, 720, 480,
> +				      true);
> +	KUNIT_ASSERT_NOT_NULL(test, expected);
> +
> +	mode = drm_mode_analog_ntsc_480i(priv->drm);
> +	KUNIT_ASSERT_NOT_NULL(test, mode);
> +
> +	KUNIT_EXPECT_TRUE(test, drm_mode_equal(expected, mode));
> +}
> +
> +static void drm_modes_analog_tv_pal_576i(struct kunit *test)
> +{
> +	struct drm_modes_test_priv *priv = test->priv;
> +	struct drm_display_mode *mode;
> +
> +	mode = drm_analog_tv_mode(priv->drm,
> +				  DRM_MODE_TV_MODE_PAL_B,
> +				  13500 * 1000, 720, 576,
> +				  true);
> +	KUNIT_ASSERT_NOT_NULL(test, mode);
> +
> +	KUNIT_EXPECT_EQ(test, drm_mode_vrefresh(mode), 50);
> +	KUNIT_EXPECT_EQ(test, mode->hdisplay, 720);
> +
> +	/* 64us * 13.5MHz = 864 pixels */
> +	KUNIT_EXPECT_EQ(test, mode->htotal, 864);
> +	KUNIT_EXPECT_EQ(test, mode->vdisplay, 576);
> +	KUNIT_EXPECT_EQ(test, mode->vtotal, 625);
> +}
> +
> +static void drm_modes_analog_tv_pal_576i_inlined(struct kunit *test)
> +{
> +	struct drm_modes_test_priv *priv = test->priv;
> +	struct drm_display_mode *expected, *mode;
> +
> +	expected = drm_analog_tv_mode(priv->drm,
> +				      DRM_MODE_TV_MODE_PAL_B,
> +				      13500 * 1000, 720, 576,
> +				      true);
> +	KUNIT_ASSERT_NOT_NULL(test, expected);
> +
> +	mode = drm_mode_analog_pal_576i(priv->drm);
> +	KUNIT_ASSERT_NOT_NULL(test, mode);
> +
> +	KUNIT_EXPECT_TRUE(test, drm_mode_equal(expected, mode));
> +}
> +
> +static struct kunit_case drm_modes_analog_tv_tests[] = {
> +	KUNIT_CASE(drm_modes_analog_tv_ntsc_480i),
> +	KUNIT_CASE(drm_modes_analog_tv_ntsc_480i_inlined),
> +	KUNIT_CASE(drm_modes_analog_tv_pal_576i),
> +	KUNIT_CASE(drm_modes_analog_tv_pal_576i_inlined),
> +	{ }
> +};
> +
> +static struct kunit_suite drm_modes_analog_tv_test_suite = {
> +	.name = "drm_modes_analog_tv",
> +	.init = drm_modes_test_init,
> +	.exit = drm_modes_test_exit,
> +	.test_cases = drm_modes_analog_tv_tests,
> +};
> +
> +kunit_test_suites(
> +	&drm_modes_analog_tv_test_suite
> +);
> +MODULE_LICENSE("GPL v2");
> diff --git a/include/drm/drm_modes.h b/include/drm/drm_modes.h
> index a80ae9639e96..5ccf3d51d313 100644
> --- a/include/drm/drm_modes.h
> +++ b/include/drm/drm_modes.h
> @@ -443,6 +443,23 @@ bool drm_mode_is_420_also(const struct drm_display_info *display,
>  bool drm_mode_is_420(const struct drm_display_info *display,
>  		     const struct drm_display_mode *mode);
>  
> +struct drm_display_mode *drm_analog_tv_mode(struct drm_device *dev,
> +					    enum drm_connector_tv_mode mode,
> +					    unsigned long pixel_clock_hz,
> +					    unsigned int hdisplay,
> +					    unsigned int vdisplay,
> +					    bool interlace);
> +
> +static inline struct drm_display_mode *drm_mode_analog_ntsc_480i(struct drm_device *dev)
> +{
> +	return drm_analog_tv_mode(dev, DRM_MODE_TV_MODE_NTSC_M, 13500000, 720, 480, true);
> +}
> +
> +static inline struct drm_display_mode *drm_mode_analog_pal_576i(struct drm_device *dev)
> +{
> +	return drm_analog_tv_mode(dev, DRM_MODE_TV_MODE_PAL_B, 13500000, 720, 576, true);
> +}
> +
>  struct drm_display_mode *drm_cvt_mode(struct drm_device *dev,
>  				      int hdisplay, int vdisplay, int vrefresh,
>  				      bool reduced, bool interlaced,
> 

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

* Re: [PATCH v2 14/41] drm/modes: Move named modes parsing to a separate function
  2022-08-30 12:03       ` Maxime Ripard
@ 2022-08-30 13:36         ` Jani Nikula
  2022-09-07  8:39           ` Maxime Ripard
  0 siblings, 1 reply; 128+ messages in thread
From: Jani Nikula @ 2022-08-30 13:36 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Geert Uytterhoeven, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Lyude Paul, Philipp Zabel, Maarten Lankhorst,
	Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec, Samuel Holland,
	Karol Herbst, Noralf Trønnes, Emma Anholt, Daniel Vetter,
	Joonas Lahtinen, Hans de Goede, Linux ARM, Phil Elwell,
	Intel Graphics Development, Dave Stevenson, DRI Development,
	Dom Cobley, Linux Kernel Mailing List, Nouveau Dev, linux-sunxi,
	Mateusz Kwiatkowski

On Tue, 30 Aug 2022, Maxime Ripard <maxime@cerno.tech> wrote:
> Hi,
>
> On Tue, Aug 30, 2022 at 01:43:07PM +0300, Jani Nikula wrote:
>> On Tue, 30 Aug 2022, Geert Uytterhoeven <geert@linux-m68k.org> wrote:
>> > On Mon, Aug 29, 2022 at 3:13 PM Maxime Ripard <maxime@cerno.tech> wrote:
>> >> +#define STR_STRICT_EQ(str, len, cmp) \
>> >> +       ((strlen(cmp) == len) && !strncmp(str, cmp, len))
>> >
>> > This is not part of the move, but newly added.
>> 
>> The same construct is also duplicated elsewhere in the series, and I
>> kept being confused by it.
>
> I'm not sure what is confusing, but I can add a comment if needed.

STR_STRICT_EQ() is what's confusing. I have to look at the
implementation to understand what it means. What does "strict" string
equality mean?

>
>> The above is precisely the same as:
>> 
>> 	str_has_prefix(str, cmp) == len
>
> Here, it's used to make sure we don't have a named mode starting with
> either e, d, or D.
>
> If I understood str_has_prefix() right, str_has_prefix("DUMB-MODE", "D")
> == strlen("DUMB-MODE") would return true, while it's actually what we
> want to avoid.

That's not true, str_has_prefix("DUMB-MODE", "D") == strlen("D") is.

> It's also used indeed in drm_get_tv_mode_from_name(), where we try to
> match a list of names with one passed as argument.
>
> With drm_get_tv_mode_from_name("NSTC", strlen("NTSC")), we would end up
> calling str_has_prefix("NTSC-J", "NTSC") == strlen("NTSC-J") which would
> work. However, we end up calling prefix not a prefix, but an entire
> string we want to match against, which is very confusing to me too.

If I get this right, you have a string and you want to check if that has
a certain prefix. Additionally, you want to check the prefix is a
certain length.

Sure, that the prefix is a certain length is more of a property of the
string, which is NUL terminated later than at length, but that's doesn't
really matter.

That condition is simply str_has_prefix(string, prefix) == length.

BR,
Jani.


-- 
Jani Nikula, Intel Open Source Graphics Center

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

* Re: [PATCH v2 24/41] drm/vc4: vec: Remove empty mode_fixup
  2022-08-29 13:11 ` [PATCH v2 24/41] drm/vc4: vec: Remove empty mode_fixup Maxime Ripard
@ 2022-08-30 15:23   ` Noralf Trønnes
  2022-09-07  8:34   ` (subset) " Maxime Ripard
  1 sibling, 0 replies; 128+ messages in thread
From: Noralf Trønnes @ 2022-08-30 15:23 UTC (permalink / raw)
  To: Maxime Ripard, Maxime Ripard, Ben Skeggs, David Airlie,
	Chen-Yu Tsai, Thomas Zimmermann, Jani Nikula, Lyude Paul,
	Philipp Zabel, Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin,
	Jernej Skrabec, Samuel Holland, Karol Herbst, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Hans de Goede, linux-arm-kernel, Phil Elwell, intel-gfx,
	Dave Stevenson, dri-devel, Dom Cobley, linux-kernel, nouveau,
	linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven,
	Noralf Trønnes



Den 29.08.2022 15.11, skrev Maxime Ripard:
> The mode_fixup hooks are deprecated, and the behaviour we implement is the
> 
> default one anyway. Let's remove it.
> 
> 
> 
> Signed-off-by: Maxime Ripard <maxime@cerno.tech>
> 

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

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

* Re: [PATCH v2 25/41] drm/vc4: vec: Convert to atomic helpers
  2022-08-29 13:11 ` [PATCH v2 25/41] drm/vc4: vec: Convert to atomic helpers Maxime Ripard
@ 2022-08-30 15:24   ` Noralf Trønnes
  2022-09-07  8:35   ` (subset) " Maxime Ripard
  1 sibling, 0 replies; 128+ messages in thread
From: Noralf Trønnes @ 2022-08-30 15:24 UTC (permalink / raw)
  To: Maxime Ripard, Maxime Ripard, Ben Skeggs, David Airlie,
	Chen-Yu Tsai, Thomas Zimmermann, Jani Nikula, Lyude Paul,
	Philipp Zabel, Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin,
	Jernej Skrabec, Samuel Holland, Karol Herbst, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Hans de Goede, linux-arm-kernel, Phil Elwell, intel-gfx,
	Dave Stevenson, dri-devel, Dom Cobley, linux-kernel, nouveau,
	linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven,
	Noralf Trønnes



Den 29.08.2022 15.11, skrev Maxime Ripard:
> The VC4 VEC driver still uses legacy enable and disable hook
> 
> implementation. Let's convert to the atomic variants.
> 
> 
> 
> Signed-off-by: Maxime Ripard <maxime@cerno.tech>
> 

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

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

* Re: [PATCH v2 26/41] drm/vc4: vec: Refactor VEC TV mode setting
  2022-08-29 13:11 ` [PATCH v2 26/41] drm/vc4: vec: Refactor VEC TV mode setting Maxime Ripard
@ 2022-08-30 15:29   ` Noralf Trønnes
  2022-09-07  8:35   ` (subset) " Maxime Ripard
  1 sibling, 0 replies; 128+ messages in thread
From: Noralf Trønnes @ 2022-08-30 15:29 UTC (permalink / raw)
  To: Maxime Ripard, Maxime Ripard, Ben Skeggs, David Airlie,
	Chen-Yu Tsai, Thomas Zimmermann, Jani Nikula, Lyude Paul,
	Philipp Zabel, Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin,
	Jernej Skrabec, Samuel Holland, Karol Herbst, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Hans de Goede, linux-arm-kernel, Phil Elwell, intel-gfx,
	Dave Stevenson, dri-devel, Dom Cobley, linux-kernel, nouveau,
	linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven,
	Noralf Trønnes



Den 29.08.2022 15.11, skrev Maxime Ripard:
> From: Mateusz Kwiatkowski <kfyatek+publicgit@gmail.com>
> 
> 
> 
> Change the mode_set function pointer logic to declarative config0,
> 
> config1 and custom_freq fields, to make TV mode setting logic more
> 
> concise and uniform.
> 
> 
> 
> Signed-off-by: Mateusz Kwiatkowski <kfyatek+publicgit@gmail.com>
> 
> Signed-off-by: Maxime Ripard <maxime@cerno.tech>
> 
> 
> 
> diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c
> 
> index 72eee0cbb615..9a37c3fcc295 100644
> 
> --- a/drivers/gpu/drm/vc4/vc4_vec.c
> 
> +++ b/drivers/gpu/drm/vc4/vc4_vec.c
> 
> @@ -194,7 +194,9 @@ enum vc4_vec_tv_mode_id {
> 
>  
> 
>  struct vc4_vec_tv_mode {
> 
>  	const struct drm_display_mode *mode;
> 
> -	void (*mode_set)(struct vc4_vec *vec);
> 
> +	u32 config0;
> 
> +	u32 config1;
> 
> +	u32 custom_freq;
> 
>  };
> 
>  
> 
>  static const struct debugfs_reg32 vec_regs[] = {
> 
> @@ -224,34 +226,6 @@ static const struct debugfs_reg32 vec_regs[] = {
> 
>  	VC4_REG32(VEC_DAC_MISC),
> 
>  };
> 
>  
> 
> -static void vc4_vec_ntsc_mode_set(struct vc4_vec *vec)
> 
> -{
> 
> -	struct drm_device *drm = vec->connector.dev;
> 
> -	int idx;
> 
> -
> 
> -	if (!drm_dev_enter(drm, &idx))
> 
> -		return;
> 
> -
> 
> -	VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_NTSC_STD | VEC_CONFIG0_PDEN);
> 
> -	VEC_WRITE(VEC_CONFIG1, VEC_CONFIG1_C_CVBS_CVBS);
> 
> -
> 
> -	drm_dev_exit(idx);
> 
> -}
> 
> -
> 
> -static void vc4_vec_ntsc_j_mode_set(struct vc4_vec *vec)
> 
> -{
> 
> -	struct drm_device *drm = vec->connector.dev;
> 
> -	int idx;
> 
> -
> 
> -	if (!drm_dev_enter(drm, &idx))
> 
> -		return;
> 
> -
> 
> -	VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_NTSC_STD);
> 
> -	VEC_WRITE(VEC_CONFIG1, VEC_CONFIG1_C_CVBS_CVBS);
> 
> -
> 
> -	drm_dev_exit(idx);
> 
> -}
> 
> -
> 
>  static const struct drm_display_mode ntsc_mode = {
> 
>  	DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 13500,
> 
>  		 720, 720 + 14, 720 + 14 + 64, 720 + 14 + 64 + 60, 0,
> 
> @@ -259,37 +233,6 @@ static const struct drm_display_mode ntsc_mode = {
> 
>  		 DRM_MODE_FLAG_INTERLACE)
> 
>  };
> 
>  
> 
> -static void vc4_vec_pal_mode_set(struct vc4_vec *vec)
> 
> -{
> 
> -	struct drm_device *drm = vec->connector.dev;
> 
> -	int idx;
> 
> -
> 
> -	if (!drm_dev_enter(drm, &idx))
> 
> -		return;
> 
> -
> 
> -	VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_PAL_BDGHI_STD);
> 
> -	VEC_WRITE(VEC_CONFIG1, VEC_CONFIG1_C_CVBS_CVBS);
> 
> -
> 
> -	drm_dev_exit(idx);
> 
> -}
> 
> -
> 
> -static void vc4_vec_pal_m_mode_set(struct vc4_vec *vec)
> 
> -{
> 
> -	struct drm_device *drm = vec->connector.dev;
> 
> -	int idx;
> 
> -
> 
> -	if (!drm_dev_enter(drm, &idx))
> 
> -		return;
> 
> -
> 
> -	VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_PAL_BDGHI_STD);
> 
> -	VEC_WRITE(VEC_CONFIG1,
> 
> -		  VEC_CONFIG1_C_CVBS_CVBS | VEC_CONFIG1_CUSTOM_FREQ);
> 
> -	VEC_WRITE(VEC_FREQ3_2, 0x223b);
> 
> -	VEC_WRITE(VEC_FREQ1_0, 0x61d1);
> 
> -
> 
> -	drm_dev_exit(idx);
> 
> -}
> 
> -
> 
>  static const struct drm_display_mode pal_mode = {
> 
>  	DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 13500,
> 
>  		 720, 720 + 20, 720 + 20 + 64, 720 + 20 + 64 + 60, 0,
> 
> @@ -300,19 +243,24 @@ static const struct drm_display_mode pal_mode = {
> 
>  static const struct vc4_vec_tv_mode vc4_vec_tv_modes[] = {
> 
>  	[VC4_VEC_TV_MODE_NTSC] = {
> 
>  		.mode = &ntsc_mode,
> 
> -		.mode_set = vc4_vec_ntsc_mode_set,
> 
> +		.config0 = VEC_CONFIG0_NTSC_STD | VEC_CONFIG0_PDEN,
> 
> +		.config1 = VEC_CONFIG1_C_CVBS_CVBS,
> 
>  	},
> 
>  	[VC4_VEC_TV_MODE_NTSC_J] = {
> 
>  		.mode = &ntsc_mode,
> 
> -		.mode_set = vc4_vec_ntsc_j_mode_set,
> 
> +		.config0 = VEC_CONFIG0_NTSC_STD,
> 
> +		.config1 = VEC_CONFIG1_C_CVBS_CVBS,
> 
>  	},
> 
>  	[VC4_VEC_TV_MODE_PAL] = {
> 
>  		.mode = &pal_mode,
> 
> -		.mode_set = vc4_vec_pal_mode_set,
> 
> +		.config0 = VEC_CONFIG0_PAL_BDGHI_STD,
> 
> +		.config1 = VEC_CONFIG1_C_CVBS_CVBS,
> 
>  	},
> 
>  	[VC4_VEC_TV_MODE_PAL_M] = {
> 
>  		.mode = &pal_mode,
> 
> -		.mode_set = vc4_vec_pal_m_mode_set,
> 
> +		.config0 = VEC_CONFIG0_PAL_BDGHI_STD,
> 
> +		.config1 = VEC_CONFIG1_C_CVBS_CVBS | VEC_CONFIG1_CUSTOM_FREQ,
> 
> +		.custom_freq = 0x223b61d1,
> 
>  	},
> 
>  };
> 
>  
> 
> @@ -470,7 +418,16 @@ static void vc4_vec_encoder_enable(struct drm_encoder *encoder,
> 
>  	/* Mask all interrupts. */
> 
>  	VEC_WRITE(VEC_MASK0, 0);
> 
>  
> 
> -	vec->tv_mode->mode_set(vec);
> 
> +	VEC_WRITE(VEC_CONFIG0, vec->tv_mode->config0);
> 
> +	VEC_WRITE(VEC_CONFIG1, vec->tv_mode->config1);
> 
> +
> 
> +	if (vec->tv_mode->custom_freq != 0) {

Nit: '!= 0' is not necessary and not common either in kernel code.

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

> 
> +		VEC_WRITE(VEC_FREQ3_2,
> 
> +			  (vec->tv_mode->custom_freq >> 16) &
> 
> +			  0xffff);
> 
> +		VEC_WRITE(VEC_FREQ1_0,
> 
> +			  vec->tv_mode->custom_freq & 0xffff);
> 
> +	}
> 
>  
> 
>  	VEC_WRITE(VEC_DAC_MISC,
> 
>  		  VEC_DAC_MISC_VID_ACT | VEC_DAC_MISC_DAC_RST_N);
> 
> 
> 

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

* Re: [PATCH v2 27/41] drm/vc4: vec: Remove redundant atomic_mode_set
  2022-08-29 13:11 ` [PATCH v2 27/41] drm/vc4: vec: Remove redundant atomic_mode_set Maxime Ripard
@ 2022-08-30 15:45   ` Noralf Trønnes
  2022-09-07  8:35   ` (subset) " Maxime Ripard
  1 sibling, 0 replies; 128+ messages in thread
From: Noralf Trønnes @ 2022-08-30 15:45 UTC (permalink / raw)
  To: Maxime Ripard, Maxime Ripard, Ben Skeggs, David Airlie,
	Chen-Yu Tsai, Thomas Zimmermann, Jani Nikula, Lyude Paul,
	Philipp Zabel, Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin,
	Jernej Skrabec, Samuel Holland, Karol Herbst, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Hans de Goede, linux-arm-kernel, Phil Elwell, intel-gfx,
	Dave Stevenson, dri-devel, Dom Cobley, linux-kernel, nouveau,
	linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven,
	Noralf Trønnes



Den 29.08.2022 15.11, skrev Maxime Ripard:
> From: Mateusz Kwiatkowski <kfyatek+publicgit@gmail.com>
> 
> 
> 
> Let's remove the superfluous tv_mode field, which was redundant with the
> 
> mode field in struct drm_tv_connector_state.
> 
> 
> 
> Signed-off-by: Mateusz Kwiatkowski <kfyatek+publicgit@gmail.com>
> 
> Signed-off-by: Maxime Ripard <maxime@cerno.tech>
> 
> 
> 
> diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c
> 
> index 9a37c3fcc295..4d7bc7c20704 100644
> 
> --- a/drivers/gpu/drm/vc4/vc4_vec.c
> 
> +++ b/drivers/gpu/drm/vc4/vc4_vec.c
> 
> @@ -171,8 +171,6 @@ struct vc4_vec {
> 
>  
> 
>  	struct clk *clock;
> 
>  
> 
> -	const struct vc4_vec_tv_mode *tv_mode;
> 
> -
> 
>  	struct debugfs_regset32 regset;
> 
>  };
> 
>  
> 
> @@ -316,7 +314,6 @@ static int vc4_vec_connector_init(struct drm_device *dev, struct vc4_vec *vec)
> 
>  	drm_object_attach_property(&connector->base,
> 
>  				   dev->mode_config.legacy_tv_mode_property,
> 
>  				   VC4_VEC_TV_MODE_NTSC);
> 
> -	vec->tv_mode = &vc4_vec_tv_modes[VC4_VEC_TV_MODE_NTSC];
> 
>  
> 
>  	drm_connector_attach_encoder(connector, &vec->encoder.base);
> 
>  
> 
> @@ -360,6 +357,11 @@ static void vc4_vec_encoder_enable(struct drm_encoder *encoder,
> 
>  {
> 
>  	struct drm_device *drm = encoder->dev;
> 
>  	struct vc4_vec *vec = encoder_to_vc4_vec(encoder);
> 
> +	struct drm_connector *connector = &vec->connector;
> 
> +	struct drm_connector_state *conn_state =
> 
> +		drm_atomic_get_new_connector_state(state, connector);
> 
> +	const struct vc4_vec_tv_mode *tv_mode =
> 
> +		&vc4_vec_tv_modes[conn_state->tv.mode];
> 
>  	int idx, ret;
> 
>  
> 
>  	if (!drm_dev_enter(drm, &idx))
> 
> @@ -418,15 +420,14 @@ static void vc4_vec_encoder_enable(struct drm_encoder *encoder,
> 
>  	/* Mask all interrupts. */
> 
>  	VEC_WRITE(VEC_MASK0, 0);
> 
>  
> 
> -	VEC_WRITE(VEC_CONFIG0, vec->tv_mode->config0);
> 
> -	VEC_WRITE(VEC_CONFIG1, vec->tv_mode->config1);
> 
> +	VEC_WRITE(VEC_CONFIG0, tv_mode->config0);
> 
> +	VEC_WRITE(VEC_CONFIG1, tv_mode->config1);
> 
>  
> 
> -	if (vec->tv_mode->custom_freq != 0) {
> 
> +	if (tv_mode->custom_freq != 0) {
> 
>  		VEC_WRITE(VEC_FREQ3_2,
> 
> -			  (vec->tv_mode->custom_freq >> 16) &
> 
> -			  0xffff);
> 
> +			  (tv_mode->custom_freq >> 16) & 0xffff);
> 
>  		VEC_WRITE(VEC_FREQ1_0,
> 
> -			  vec->tv_mode->custom_freq & 0xffff);
> 
> +			  tv_mode->custom_freq & 0xffff);
> 

Nit: This patch will be smaller if you add the tv_mode variable to the
previous patch.

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

>  	}
> 
>  
> 
>  	VEC_WRITE(VEC_DAC_MISC,
> 
> @@ -442,15 +443,6 @@ static void vc4_vec_encoder_enable(struct drm_encoder *encoder,
> 
>  	drm_dev_exit(idx);
> 
>  }
> 
>  
> 
> -static void vc4_vec_encoder_atomic_mode_set(struct drm_encoder *encoder,
> 
> -					struct drm_crtc_state *crtc_state,
> 
> -					struct drm_connector_state *conn_state)
> 
> -{
> 
> -	struct vc4_vec *vec = encoder_to_vc4_vec(encoder);
> 
> -
> 
> -	vec->tv_mode = &vc4_vec_tv_modes[conn_state->tv.mode];
> 
> -}
> 
> -
> 
>  static int vc4_vec_encoder_atomic_check(struct drm_encoder *encoder,
> 
>  					struct drm_crtc_state *crtc_state,
> 
>  					struct drm_connector_state *conn_state)
> 
> @@ -470,7 +462,6 @@ static const struct drm_encoder_helper_funcs vc4_vec_encoder_helper_funcs = {
> 
>  	.atomic_check = vc4_vec_encoder_atomic_check,
> 
>  	.atomic_disable = vc4_vec_encoder_disable,
> 
>  	.atomic_enable = vc4_vec_encoder_enable,
> 
> -	.atomic_mode_set = vc4_vec_encoder_atomic_mode_set,
> 
>  };
> 
>  
> 
>  static int vc4_vec_late_register(struct drm_encoder *encoder)
> 
> 
> 

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

* Re: [PATCH v2 28/41] drm/vc4: vec: Fix timings for VEC modes
  2022-08-29 13:11 ` [PATCH v2 28/41] drm/vc4: vec: Fix timings for VEC modes Maxime Ripard
@ 2022-08-30 18:20   ` Noralf Trønnes
  2022-09-07  8:35   ` (subset) " Maxime Ripard
  1 sibling, 0 replies; 128+ messages in thread
From: Noralf Trønnes @ 2022-08-30 18:20 UTC (permalink / raw)
  To: Maxime Ripard, Maxime Ripard, Ben Skeggs, David Airlie,
	Chen-Yu Tsai, Thomas Zimmermann, Jani Nikula, Lyude Paul,
	Philipp Zabel, Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin,
	Jernej Skrabec, Samuel Holland, Karol Herbst, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Hans de Goede, linux-arm-kernel, Phil Elwell, intel-gfx,
	Dave Stevenson, dri-devel, Dom Cobley, linux-kernel, nouveau,
	linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven,
	Noralf Trønnes



Den 29.08.2022 15.11, skrev Maxime Ripard:
> From: Mateusz Kwiatkowski <kfyatek+publicgit@gmail.com>
> 
> 
> 
> This commit fixes vertical timings of the VEC (composite output) modes
> 
> to accurately represent the 525-line ("NTSC") and 625-line ("PAL") ITU-R
> 
> standards.
> 
> 
> 
> Previous timings were actually defined as 502 and 601 lines, resulting
> 
> in non-standard 62.69 Hz and 52 Hz signals being generated,
> 
> respectively.
> 
> 
> 
> Signed-off-by: Mateusz Kwiatkowski <kfyatek+publicgit@gmail.com>
> 
> Signed-off-by: Maxime Ripard <maxime@cerno.tech>
> 
> 

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

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

* Re: [PATCH v2 29/41] drm/vc4: vec: Switch for common modes
  2022-08-29 13:11 ` [PATCH v2 29/41] drm/vc4: vec: Switch for common modes Maxime Ripard
@ 2022-08-30 18:36   ` Noralf Trønnes
  0 siblings, 0 replies; 128+ messages in thread
From: Noralf Trønnes @ 2022-08-30 18:36 UTC (permalink / raw)
  To: Maxime Ripard, Maxime Ripard, Ben Skeggs, David Airlie,
	Chen-Yu Tsai, Thomas Zimmermann, Jani Nikula, Lyude Paul,
	Philipp Zabel, Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin,
	Jernej Skrabec, Samuel Holland, Karol Herbst, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Hans de Goede, linux-arm-kernel, Phil Elwell, intel-gfx,
	Dave Stevenson, dri-devel, Dom Cobley, linux-kernel, nouveau,
	linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven,
	Noralf Trønnes



Den 29.08.2022 15.11, skrev Maxime Ripard:
> Now that the core has a definition for the 525 and 625 lines analog TV
> 
> modes, let's switch to it for vc4.
> 
> 
> 
> Signed-off-by: Maxime Ripard <maxime@cerno.tech>
> 
> 
> 
> diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c
> 
> index d1d40b69279e..63e4e617e321 100644
> 
> --- a/drivers/gpu/drm/vc4/vc4_vec.c
> 
> +++ b/drivers/gpu/drm/vc4/vc4_vec.c
> 
> @@ -224,38 +224,24 @@ static const struct debugfs_reg32 vec_regs[] = {
> 
>  	VC4_REG32(VEC_DAC_MISC),
> 
>  };
> 
>  
> 
> -static const struct drm_display_mode ntsc_mode = {
> 
> -	DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 13500,
> 
> -		 720, 720 + 14, 720 + 14 + 64, 720 + 14 + 64 + 60, 0,
> 
> -		 480, 480 + 7, 480 + 7 + 6, 525, 0,
> 
> -		 DRM_MODE_FLAG_INTERLACE)
> 
> -};
> 
> -
> 
> -static const struct drm_display_mode pal_mode = {
> 
> -	DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 13500,
> 
> -		 720, 720 + 20, 720 + 20 + 64, 720 + 20 + 64 + 60, 0,
> 
> -		 576, 576 + 4, 576 + 4 + 6, 625, 0,
> 
> -		 DRM_MODE_FLAG_INTERLACE)
> 
> -};
> 
> -
> 
>  static const struct vc4_vec_tv_mode vc4_vec_tv_modes[] = {
> 
>  	[VC4_VEC_TV_MODE_NTSC] = {
> 
> -		.mode = &ntsc_mode,
> 
> +		.mode = &drm_mode_480i,
> 

I can't find drm_mode_480i anywhere, maybe the compiler doesn't complain
since you remove the reference in a later patch?

Noralf.

>  		.config0 = VEC_CONFIG0_NTSC_STD | VEC_CONFIG0_PDEN,
> 
>  		.config1 = VEC_CONFIG1_C_CVBS_CVBS,
> 
>  	},
> 
>  	[VC4_VEC_TV_MODE_NTSC_J] = {
> 
> -		.mode = &ntsc_mode,
> 
> +		.mode = &drm_mode_480i,
> 
>  		.config0 = VEC_CONFIG0_NTSC_STD,
> 
>  		.config1 = VEC_CONFIG1_C_CVBS_CVBS,
> 
>  	},
> 
>  	[VC4_VEC_TV_MODE_PAL] = {
> 
> -		.mode = &pal_mode,
> 
> +		.mode = &drm_mode_576i,
> 
>  		.config0 = VEC_CONFIG0_PAL_BDGHI_STD,
> 
>  		.config1 = VEC_CONFIG1_C_CVBS_CVBS,
> 
>  	},
> 
>  	[VC4_VEC_TV_MODE_PAL_M] = {
> 
> -		.mode = &pal_mode,
> 
> +		.mode = &drm_mode_576i,
> 
>  		.config0 = VEC_CONFIG0_PAL_BDGHI_STD,
> 
>  		.config1 = VEC_CONFIG1_C_CVBS_CVBS | VEC_CONFIG1_CUSTOM_FREQ,
> 
>  		.custom_freq = 0x223b61d1,
> 
> 
> 

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

* Re: [PATCH v2 22/41] drm/atomic-helper: Add a TV properties reset helper
  2022-08-29 13:11 ` [PATCH v2 22/41] drm/atomic-helper: Add a TV properties reset helper Maxime Ripard
@ 2022-08-30 18:40   ` Noralf Trønnes
  0 siblings, 0 replies; 128+ messages in thread
From: Noralf Trønnes @ 2022-08-30 18:40 UTC (permalink / raw)
  To: Maxime Ripard, Maxime Ripard, Ben Skeggs, David Airlie,
	Chen-Yu Tsai, Thomas Zimmermann, Jani Nikula, Lyude Paul,
	Philipp Zabel, Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin,
	Jernej Skrabec, Samuel Holland, Karol Herbst, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Hans de Goede, linux-arm-kernel, Phil Elwell, intel-gfx,
	Dave Stevenson, dri-devel, Dom Cobley, linux-kernel, nouveau,
	linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven,
	Noralf Trønnes



Den 29.08.2022 15.11, skrev Maxime Ripard:
> The drm_tv_create_properties() function will create a bunch of properties,
> 
> but it's up to each and every driver using that function to properly reset
> 
> the state of these properties leading to inconsistent behaviours.
> 
> 
> 
> Let's create a helper that will take care of it.
> 
> 
> 
> Signed-off-by: Maxime Ripard <maxime@cerno.tech>
> 

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

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

* Re: [PATCH v2 23/41] drm/atomic-helper: Add an analog TV atomic_check implementation
  2022-08-29 13:11 ` [PATCH v2 23/41] drm/atomic-helper: Add an analog TV atomic_check implementation Maxime Ripard
@ 2022-08-30 18:49   ` Noralf Trønnes
  0 siblings, 0 replies; 128+ messages in thread
From: Noralf Trønnes @ 2022-08-30 18:49 UTC (permalink / raw)
  To: Maxime Ripard, Maxime Ripard, Ben Skeggs, David Airlie,
	Chen-Yu Tsai, Thomas Zimmermann, Jani Nikula, Lyude Paul,
	Philipp Zabel, Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin,
	Jernej Skrabec, Samuel Holland, Karol Herbst, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Hans de Goede, linux-arm-kernel, Phil Elwell, intel-gfx,
	Dave Stevenson, dri-devel, Dom Cobley, linux-kernel, nouveau,
	linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven,
	Noralf Trønnes



Den 29.08.2022 15.11, skrev Maxime Ripard:
> The analog TV connector drivers share some atomic_check logic, and the new
> 
> TV standard property have created a bunch of new constraints that needs to
> 
> be shared across drivers too.
> 
> 
> 
> Let's create an atomic_check helper for those use cases.
> 
> 
> 
> Signed-off-by: Maxime Ripard <maxime@cerno.tech>
> 
> 
> 
> diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c
> 
> index 0373c3dc824b..d64733c6aae3 100644
> 
> --- a/drivers/gpu/drm/drm_atomic_state_helper.c
> 
> +++ b/drivers/gpu/drm/drm_atomic_state_helper.c
> 
> @@ -556,6 +556,42 @@ void drm_atomic_helper_connector_tv_reset(struct drm_connector *connector)
> 
>  }
> 
>  EXPORT_SYMBOL(drm_atomic_helper_connector_tv_reset);
> 
>  
> 
> +/**
> 
> + * @drm_atomic_helper_connector_tv_check: Validate an analog TV connector state
> 
> + * @connector: DRM Connector
> 
> + * @state: the DRM State object
> 
> + *
> 
> + * Checks the state object to see if the requested state is valid for an
> 
> + * analog TV connector.
> 
> + *
> 
> + * Returns:
> 
> + * Zero for success, a negative error code on error.
> 
> + */
> 
> +int drm_atomic_helper_connector_tv_check(struct drm_connector *connector,
> 
> +					 struct drm_atomic_state *state)
> 
> +{
> 
> +	struct drm_connector_state *old_conn_state =
> 
> +		drm_atomic_get_old_connector_state(state, connector);
> 
> +	struct drm_connector_state *new_conn_state =
> 
> +		drm_atomic_get_new_connector_state(state, connector);
> 
> +	struct drm_crtc_state *crtc_state;
> 
> +	struct drm_crtc *crtc;
> 
> +
> 
> +	crtc = new_conn_state->crtc;
> 
> +	if (!crtc)
> 
> +		return 0;
> 
> +
> 
> +	crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
> 
> +	if (!crtc_state)
> 
> +		return -EINVAL;
> 
> +
> 
> +	if (old_conn_state->tv.mode != new_conn_state->tv.mode)
> 
> +		crtc_state->mode_changed = true;
> 

If you can expand this check then I can use it in gud:

	if (old_conn_state->tv.margins.left != new_conn_state->tv.margins.left ||
	    old_conn_state->tv.margins.right != new_conn_state->tv.margins.right ||
	    old_conn_state->tv.margins.top != new_conn_state->tv.margins.top ||
	    old_conn_state->tv.margins.bottom !=
new_conn_state->tv.margins.bottom ||
	    old_conn_state->tv.mode != new_conn_state->tv.mode ||
	    old_conn_state->tv.brightness != new_conn_state->tv.brightness ||
	    old_conn_state->tv.contrast != new_conn_state->tv.contrast ||
	    old_conn_state->tv.flicker_reduction !=
new_conn_state->tv.flicker_reduction ||
	    old_conn_state->tv.overscan != new_conn_state->tv.overscan ||
	    old_conn_state->tv.saturation != new_conn_state->tv.saturation ||
	    old_conn_state->tv.hue != new_conn_state->tv.hue)
		crtc_state->connectors_changed = true;

With that considered:

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

> +
> 
> +	return 0;
> 
> +}
> 
> +EXPORT_SYMBOL(drm_atomic_helper_connector_tv_check);
> 
> +
> 
>  /**
> 
>   * __drm_atomic_helper_connector_duplicate_state - copy atomic connector state
> 
>   * @connector: connector object
> 
> diff --git a/include/drm/drm_atomic_state_helper.h b/include/drm/drm_atomic_state_helper.h
> 
> index c8fbce795ee7..b9740edb2658 100644
> 
> --- a/include/drm/drm_atomic_state_helper.h
> 
> +++ b/include/drm/drm_atomic_state_helper.h
> 
> @@ -26,6 +26,7 @@
> 
>  
> 
>  #include <linux/types.h>
> 
>  
> 
> +struct drm_atomic_state;
> 
>  struct drm_bridge;
> 
>  struct drm_bridge_state;
> 
>  struct drm_crtc;
> 
> @@ -71,6 +72,8 @@ 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);
> 
> +int drm_atomic_helper_connector_tv_check(struct drm_connector *connector,
> 
> +					 struct drm_atomic_state *state);
> 
>  void drm_atomic_helper_connector_tv_margins_reset(struct drm_connector *connector);
> 
>  void
> 
>  __drm_atomic_helper_connector_duplicate_state(struct drm_connector *connector,
> 
> 
> 

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

* Re: [PATCH v2 31/41] drm/vc4: vec: Use TV Reset implementation
  2022-08-29 13:11 ` [PATCH v2 31/41] drm/vc4: vec: Use TV Reset implementation Maxime Ripard
@ 2022-08-30 18:51   ` Noralf Trønnes
  0 siblings, 0 replies; 128+ messages in thread
From: Noralf Trønnes @ 2022-08-30 18:51 UTC (permalink / raw)
  To: Maxime Ripard, Maxime Ripard, Ben Skeggs, David Airlie,
	Chen-Yu Tsai, Thomas Zimmermann, Jani Nikula, Lyude Paul,
	Philipp Zabel, Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin,
	Jernej Skrabec, Samuel Holland, Karol Herbst, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Hans de Goede, linux-arm-kernel, Phil Elwell, intel-gfx,
	Dave Stevenson, dri-devel, Dom Cobley, linux-kernel, nouveau,
	linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven,
	Noralf Trønnes



Den 29.08.2022 15.11, skrev Maxime Ripard:
> The analog TV properties created by the drm_mode_create_tv_properties() are
> 
> not properly initialised at reset. Let's switch our implementation to call
> 
> drm_atomic_helper_connector_tv_reset().
> 
> 
> 
> Signed-off-by: Maxime Ripard <maxime@cerno.tech>
> 

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

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

* Re: [PATCH v2 32/41] drm/vc4: vec: Convert to the new TV mode property
  2022-08-29 13:11 ` [PATCH v2 32/41] drm/vc4: vec: Convert to the new TV mode property Maxime Ripard
@ 2022-08-30 19:01   ` Noralf Trønnes
  2022-09-08 11:23     ` Maxime Ripard
  2022-08-31  2:23   ` Mateusz Kwiatkowski
  1 sibling, 1 reply; 128+ messages in thread
From: Noralf Trønnes @ 2022-08-30 19:01 UTC (permalink / raw)
  To: Maxime Ripard, Maxime Ripard, Ben Skeggs, David Airlie,
	Chen-Yu Tsai, Thomas Zimmermann, Jani Nikula, Lyude Paul,
	Philipp Zabel, Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin,
	Jernej Skrabec, Samuel Holland, Karol Herbst, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Hans de Goede, linux-arm-kernel, Phil Elwell, intel-gfx,
	Dave Stevenson, dri-devel, Dom Cobley, linux-kernel, nouveau,
	linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven,
	Noralf Trønnes



Den 29.08.2022 15.11, skrev Maxime Ripard:
> Now that the core can deal fine with analog TV modes, let's convert the vc4
> 
> VEC driver to leverage those new features.
> 
> 
> 
> We've added some backward compatibility to support the old TV mode property
> 
> and translate it into the new TV norm property.
> 
> 
> 
> Signed-off-by: Maxime Ripard <maxime@cerno.tech>
> 
> 
> 
> diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c
> 
> index ba6f81908923..58286acf4b9e 100644
> 
> --- a/drivers/gpu/drm/vc4/vc4_vec.c
> 
> +++ b/drivers/gpu/drm/vc4/vc4_vec.c

> @@ -192,7 +200,7 @@ enum vc4_vec_tv_mode_id {
> 
>  };
> 
>  
> 
>  struct vc4_vec_tv_mode {
> 
> -	const struct drm_display_mode *mode;
> 
> +	unsigned int mode;
> 
>  	u32 config0;
> 
>  	u32 config1;
> 
>  	u32 custom_freq;
> 
> @@ -226,28 +234,50 @@ static const struct debugfs_reg32 vec_regs[] = {
> 
>  };
> 
>  
> 
>  static const struct vc4_vec_tv_mode vc4_vec_tv_modes[] = {
> 
> -	[VC4_VEC_TV_MODE_NTSC] = {
> 
> -		.mode = &drm_mode_480i,
> 
> +	{
> 
> +		.mode = DRM_MODE_TV_MODE_NTSC_M,
> 
>  		.config0 = VEC_CONFIG0_NTSC_STD | VEC_CONFIG0_PDEN,
> 
>  		.config1 = VEC_CONFIG1_C_CVBS_CVBS,
> 
>  	},
> 
> -	[VC4_VEC_TV_MODE_NTSC_J] = {
> 
> -		.mode = &drm_mode_480i,
> 
> +	{
> 
> +		.mode = DRM_MODE_TV_MODE_NTSC_J,
> 
>  		.config0 = VEC_CONFIG0_NTSC_STD,
> 
>  		.config1 = VEC_CONFIG1_C_CVBS_CVBS,
> 
>  	},
> 
> -	[VC4_VEC_TV_MODE_PAL] = {
> 
> -		.mode = &drm_mode_576i,
> 
> +	{
> 
> +		.mode = DRM_MODE_TV_MODE_PAL_B,
> 
>  		.config0 = VEC_CONFIG0_PAL_BDGHI_STD,
> 
>  		.config1 = VEC_CONFIG1_C_CVBS_CVBS,
> 
>  	},
> 
> -	[VC4_VEC_TV_MODE_PAL_M] = {
> 
> -		.mode = &drm_mode_480i,
> 
> +	{
> 
> +		.mode = DRM_MODE_TV_MODE_PAL_M,
> 
>  		.config0 = VEC_CONFIG0_PAL_M_STD,
> 
>  		.config1 = VEC_CONFIG1_C_CVBS_CVBS,
> 
>  	},
> 
>  };
> 
>  
> 
> +static inline const struct vc4_vec_tv_mode *
> 
> +vc4_vec_tv_mode_lookup(unsigned int mode)
> 
> +{
> 
> +	unsigned int i;
> 
> +
> 
> +	for (i = 0; i < ARRAY_SIZE(vc4_vec_tv_modes); i++) {
> 
> +		const struct vc4_vec_tv_mode *tv_mode = &vc4_vec_tv_modes[i];
> 
> +
> 
> +		if (tv_mode->mode == mode)
> 
> +			return tv_mode;
> 
> +	}
> 
> +
> 
> +	return NULL;
> 
> +}
> 
> +
> 
> +static const struct drm_prop_enum_list tv_mode_names[] = {

Maybe call it legacy_tv_mode_enums?

> 
> +	{ VC4_VEC_TV_MODE_NTSC, "NTSC", },
> 
> +	{ VC4_VEC_TV_MODE_NTSC_J, "NTSC-J", },
> 
> +	{ VC4_VEC_TV_MODE_PAL, "PAL", },
> 
> +	{ VC4_VEC_TV_MODE_PAL_M, "PAL-M", },

If you use DRM_MODE_TV_MODE_* here you don't need to translate the value
using the switch statement in get/set property, you can use the value
directly to get/set tv.mode.

Noralf.

> 
> +};

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

* Re: [PATCH v2 06/41] drm/connector: Rename legacy TV property
  2022-08-29 13:11 ` [PATCH v2 06/41] drm/connector: Rename legacy TV property Maxime Ripard
@ 2022-08-30 19:27   ` Noralf Trønnes
  0 siblings, 0 replies; 128+ messages in thread
From: Noralf Trønnes @ 2022-08-30 19:27 UTC (permalink / raw)
  To: Maxime Ripard, Maxime Ripard, Ben Skeggs, David Airlie,
	Chen-Yu Tsai, Thomas Zimmermann, Jani Nikula, Lyude Paul,
	Philipp Zabel, Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin,
	Jernej Skrabec, Samuel Holland, Karol Herbst, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Hans de Goede, linux-arm-kernel, Phil Elwell, intel-gfx,
	Dave Stevenson, dri-devel, Dom Cobley, linux-kernel, nouveau,
	linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven,
	Noralf Trønnes



Den 29.08.2022 15.11, skrev Maxime Ripard:
> The current tv_mode has driver-specific values that don't allow to
> 
> easily share code using it, either at the userspace or kernel level.
> 
> 
> 
> Since we're going to introduce a new, generic, property that fit the
> 
> same purpose, let's rename this one to legacy_tv_mode to make it
> 
> obvious we should move away from it.
> 
> 
> 
> Signed-off-by: Maxime Ripard <maxime@cerno.tech>
> 

> diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
> 
> index 1d5e3cccb9e3..5cfad8b6ad83 100644
> 
> --- a/include/drm/drm_connector.h
> 
> +++ b/include/drm/drm_connector.h
> 
> @@ -695,7 +695,7 @@ struct drm_connector_tv_margins {
> 
>   * @select_subconnector: selected subconnector
> 
>   * @subconnector: detected subconnector
> 
>   * @margins: TV margins
> 
> - * @mode: TV mode
> 
> + * @legacy_mode: Legacy TV mode, driver specific value
> 
>   * @brightness: brightness in percent
> 
>   * @contrast: contrast in percent
> 
>   * @flicker_reduction: flicker reduction in percent
> 
> @@ -707,7 +707,7 @@ struct drm_tv_connector_state {
> 
>  	enum drm_mode_subconnector select_subconnector;
> 
>  	enum drm_mode_subconnector subconnector;
> 
>  	struct drm_connector_tv_margins margins;
> 
> -	unsigned int mode;
> 
> +	unsigned int legacy_mode;

I suggest you do a build of the affected drivers after adding this patch
to make sure you have changed all mode -> legacy_mode occurrences
_before_ adding back mode in a later patch.

A simple grep gave me these:

drivers/gpu/drm/vc4/vc4_vec.c:
vc4_vec_tv_modes[state->tv.mode].mode);
drivers/gpu/drm/vc4/vc4_vec.c:  vec->tv_mode =
&vc4_vec_tv_modes[conn_state->tv.mode];
drivers/gpu/drm/vc4/vc4_vec.c:  vec_mode =
&vc4_vec_tv_modes[conn_state->tv.mode];
drivers/gpu/drm/i915/display/intel_tv.c:        int format =
conn_state->tv.mode;
drivers/gpu/drm/i915/display/intel_tv.c:
connector->state->tv.mode = i;
drivers/gpu/drm/i915/display/intel_tv.c:        if (old_state->tv.mode
!= new_state->tv.mode ||
drivers/gpu/drm/i915/display/intel_tv.c:        state->tv.mode =
initial_mode;
drivers/gpu/drm/i915/display/intel_tv.c:
   state->tv.mode);
drivers/gpu/drm/i915/display/intel_sdvo.c:      format_map = 1 <<
conn_state->tv.mode;
drivers/gpu/drm/i915/display/intel_sdvo.c:      format_map = 1 <<
conn_state->tv.mode;
drivers/gpu/drm/i915/display/intel_sdvo.c:                      if
(state->tv.mode == intel_sdvo_connector->tv_format_supported[i]) {
drivers/gpu/drm/i915/display/intel_sdvo.c:              state->tv.mode =
intel_sdvo_connector->tv_format_supported[val];
drivers/gpu/drm/i915/display/intel_sdvo.c:
intel_sdvo_connector->base.base.state->tv.mode =
intel_sdvo_connector->tv_format_supported[0];

Not so easy to grep for is this in gud:

static unsigned int *gud_connector_tv_state_val(u16 prop, struct
drm_tv_connector_state *state)
{
	switch (prop) {
...
	case GUD_PROPERTY_TV_MODE:
		return &state->mode;

Noralf.

> 
>  	unsigned int brightness;
> 
>  	unsigned int contrast;
> 
>  	unsigned int flicker_reduction;
> 
> diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h
> 
> index 6b5e01295348..35a827175c24 100644
> 
> --- a/include/drm/drm_mode_config.h
> 
> +++ b/include/drm/drm_mode_config.h
> 
> @@ -714,11 +714,13 @@ struct drm_mode_config {
> 
>  	 * between different TV connector types.
> 
>  	 */
> 
>  	struct drm_property *tv_select_subconnector_property;
> 
> +
> 
>  	/**
> 
> -	 * @tv_mode_property: Optional TV property to select
> 
> +	 * @legacy_tv_mode_property: Optional TV property to select
> 
>  	 * the output TV mode.
> 
>  	 */
> 
> -	struct drm_property *tv_mode_property;
> 
> +	struct drm_property *legacy_tv_mode_property;
> 
> +
> 
>  	/**
> 
>  	 * @tv_left_margin_property: Optional TV property to set the left
> 
>  	 * margin (expressed in pixels).
> 
> 
> 

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

* Re: [PATCH v2 10/41] drm/modes: Add a function to generate analog display modes
  2022-08-29 13:11 ` [PATCH v2 10/41] drm/modes: Add a function to generate analog display modes Maxime Ripard
  2022-08-30 13:01   ` Maíra Canal
@ 2022-08-31  1:44   ` Mateusz Kwiatkowski
  2022-08-31  8:14     ` Geert Uytterhoeven
  2022-09-05 13:37     ` Maxime Ripard
  2022-09-01 19:09   ` Noralf Trønnes
  2 siblings, 2 replies; 128+ messages in thread
From: Mateusz Kwiatkowski @ 2022-08-31  1:44 UTC (permalink / raw)
  To: Maxime Ripard, Maxime Ripard, Ben Skeggs, David Airlie,
	Chen-Yu Tsai, Thomas Zimmermann, Jani Nikula, Lyude Paul,
	Philipp Zabel, Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin,
	Jernej Skrabec, Samuel Holland, Karol Herbst,
	Noralf Trønnes, Emma Anholt, Daniel Vetter, Joonas Lahtinen
  Cc: Hans de Goede, linux-arm-kernel, Phil Elwell, intel-gfx,
	Dave Stevenson, dri-devel, Dom Cobley, linux-kernel, nouveau,
	linux-sunxi, Geert Uytterhoeven

Hi Maxime,

Wow. That's an enormous amount of effort put into this patch.

But I'm tempted to say that this is actually overengineered quite a bit :D
Considering that there's no way to access all these calculations from user
space, and I can't imagine anybody using anything else than those standard
480i/576i (and maybe 240p/288p) modes at 13.5 MHz any time soon... I'm not
sure if we actually need all this.

But anyway, I'm not the maintainer of this subsystem, so I'm not the one to
decide.

> +enum drm_mode_analog {
> +    DRM_MODE_ANALOG_NTSC,
> +    DRM_MODE_ANALOG_PAL,
> +};

Using "NTSC" and "PAL" to describe the 50Hz and 60Hz analog TV modes is common,
but strictly speaking a misnomer. Those are color encoding systems, and your
patchset fully supports lesser used, but standard encodings for those (e.g.
PAL-M for 60Hz and SECAM for 50Hz). I'd propose switching to some more neutral
naming scheme. Some ideas:

- DRM_MODE_ANALOG_60_HZ / DRM_MODE_ANALOG_50_HZ (after standard refresh rate)
- DRM_MODE_ANALOG_525_LINES / DRM_MODE_ANALOG_625_LINES (after standard line
  count)
- DRM_MODE_ANALOG_JM / DRM_MODE_ANALOG_BDGHIKLN (after corresponding ITU System
  Letter Designations)

> +#define NTSC_HFP_DURATION_TYP_NS    1500
> +#define NTSC_HFP_DURATION_MIN_NS    1270
> +#define NTSC_HFP_DURATION_MAX_NS    2220

You've defined those min/typ/max ranges, but you're not using the "typ" field
for anything other than hslen. The actual "typical" value is thus always the
midpoint, which isn't necessarily the best choice.

In particular, for the standard 720px wide modes at 13.5 MHz, hsync_start
ends up being 735 for 480i and 734 for 576i, instead of 736 and 732 requested
by BT.601. That's all obviously within tolerances, but the image ends up
noticeably off-center (at least on modern TVs), especially in the 576i case.

> +    htotal = params->line_duration_ns * pixel_clock_hz / NSEC_PER_SEC;

You're multiplying an unsigned int and an unsigned long - both types are only
required to be 32 bit, so this is likely to overflow. You need to use a cast to
unsigned long long, and then call do_div() for 64-bit division.

This actually overflowed on me on my Pi running ARM32 kernel, resulting in
negative horizontal porch lengths, and drm_helper_probe_add_cmdline_mode()
taking over the mode generation (badly), and a horrible mess on screen.

> +    vfp = vfp_min + (porches_rem / 2);
> +    vbp = porches - vfp;

Relative position of the vertical sync within the VBI effectively moves the
image up and down. Adding that (porches_rem / 2) moves the image up off center
by that many pixels. I'd keep the VFP always at minimum to keep the image
centered.

Best regards,
Mateusz Kwiatkowski

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

* Re: [PATCH v2 32/41] drm/vc4: vec: Convert to the new TV mode property
  2022-08-29 13:11 ` [PATCH v2 32/41] drm/vc4: vec: Convert to the new TV mode property Maxime Ripard
  2022-08-30 19:01   ` Noralf Trønnes
@ 2022-08-31  2:23   ` Mateusz Kwiatkowski
  2022-09-08 13:18     ` Maxime Ripard
  1 sibling, 1 reply; 128+ messages in thread
From: Mateusz Kwiatkowski @ 2022-08-31  2:23 UTC (permalink / raw)
  To: Maxime Ripard, Maxime Ripard, Ben Skeggs, David Airlie,
	Chen-Yu Tsai, Thomas Zimmermann, Jani Nikula, Lyude Paul,
	Philipp Zabel, Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin,
	Jernej Skrabec, Samuel Holland, Karol Herbst,
	Noralf Trønnes, Emma Anholt, Daniel Vetter, Joonas Lahtinen
  Cc: Hans de Goede, linux-arm-kernel, Phil Elwell, intel-gfx,
	Dave Stevenson, dri-devel, Dom Cobley, linux-kernel, nouveau,
	linux-sunxi, Geert Uytterhoeven

Hi Maxime,

I tested your patchset on my Pi and it mostly works. Good work! However,
I noticed a couple of issues.

> -static int vc4_vec_encoder_atomic_check(struct drm_encoder *encoder,
> -                    struct drm_crtc_state *crtc_state,
> -                    struct drm_connector_state *conn_state)
> -{
> -    const struct vc4_vec_tv_mode *vec_mode;
> -
> -    vec_mode = &vc4_vec_tv_modes[conn_state->tv.mode];
> -
> -    if (conn_state->crtc &&
> -        !drm_mode_equal(vec_mode->mode, &crtc_state->adjusted_mode))
> -        return -EINVAL;
> -
> -    return 0;
> -}

I may have said it myself that we should allow custom modelines without too
much validation. The VC4 and VEC, however, have some considerable limitations
when it comes to the modelines that they can reliably output.

In particular, attempting to use "50 Hz" timings in NTSC/PAL-M modes (or
"60 Hz" in PAL/SECAM modes) results in a weirdly skewed image. Here's how it
may look like:
https://user-images.githubusercontent.com/4499762/187575940-736e7262-c82d-42f3-a2d8-f309cbd51139.png

This is because if the CRTC does not trigger the sync pulses within an
acceptable time window, the VEC apparently generates them itself. This causes
the VEC sync pulses (which go onto the wire) not quite line up with the ones
from the modeline, which results in what you see on the screenshot.

I once wrote a validation function based on extensive testing of what
produces a sensible output and what doesn't. You can find it here:
https://github.com/raspberrypi/linux/pull/4406/commits/15c0c51. I think it
might be a good idea to include something like that - even though I know it's
somewhat ugly.

(BTW, those %2 checks on vertical timings in that linked commit can be ignored;
those values are divided by 2 for interlaced modes anyway. Those checks were
intended to ensure proper odd-first or even-first timings; I'm not sure if your
code calculates those in the same way)

>  static int vc4_vec_connector_get_modes(struct drm_connector *connector)
>  {
> -    struct drm_connector_state *state = connector->state;
>      struct drm_display_mode *mode;
> +    int count = 0;
>  
> -    mode = drm_mode_duplicate(connector->dev,
> -                  vc4_vec_tv_modes[state->tv.mode].mode);
> +    mode = drm_mode_analog_ntsc_480i(connector->dev);
>      if (!mode) {
>          DRM_ERROR("Failed to create a new display mode\n");
>          return -ENOMEM;
>      }
>  
>      drm_mode_probed_add(connector, mode);
> +    count += 1;
>  
> -    return 1;
> +    mode = drm_mode_analog_pal_576i(connector->dev);
> +    if (!mode) {
> +        DRM_ERROR("Failed to create a new display mode\n");
> +        return -ENOMEM;
> +    }
> +
> +    drm_mode_probed_add(connector, mode);
> +    count += 1;
> +
> +    return count;
> +}

Xorg is pretty confused by these modes being reported like that. The 576i mode
is *always* preferred, presumably because of the higher resolution. If the NTSC
mode is set (via the kernel cmdline or just due to it being the default), this
results in a mess on the screen - exactly the same thing as on the screenshot
linked above.

Note that drm_helper_probe_add_cmdline_mode() *does* add the
DRM_MODE_TYPE_USERDEF flag to the 480i mode, having detected it as preferred
on the command line - but Xorg does not seem to care about that.

I remember Noralf suggesting setting DRM_MODE_TYPE_PREFERRED for the mode that
corresponds to the currently chosen tv_mode - that would fix the problem.
An alternative would be to _not_ add the "opposite" mode at all, like the
current default Raspberry Pi OS kernel behaves.

Note that if you decide to add the modeline validation like I suggested in the
comment above, then without setting the preferred mode properly, Xorg will just
give up and sit on a blank screen until you run xrandr from another terminal
if tv_mode incompatible with 576i is selected.

Best regards,
Mateusz Kwiatkowski

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

* Re: [PATCH v2 10/41] drm/modes: Add a function to generate analog display modes
  2022-08-31  1:44   ` Mateusz Kwiatkowski
@ 2022-08-31  8:14     ` Geert Uytterhoeven
  2022-09-05 13:32       ` Maxime Ripard
  2022-09-05 13:37     ` Maxime Ripard
  1 sibling, 1 reply; 128+ messages in thread
From: Geert Uytterhoeven @ 2022-08-31  8:14 UTC (permalink / raw)
  To: Mateusz Kwiatkowski
  Cc: Maxime Ripard, Maxime Ripard, Ben Skeggs, David Airlie,
	Chen-Yu Tsai, Thomas Zimmermann, Jani Nikula, Lyude Paul,
	Philipp Zabel, Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin,
	Jernej Skrabec, Samuel Holland, Karol Herbst,
	Noralf Trønnes, Emma Anholt, Daniel Vetter, Joonas Lahtinen,
	Hans de Goede, Linux ARM, Phil Elwell,
	Intel Graphics Development, Dave Stevenson, DRI Development,
	Dom Cobley, Linux Kernel Mailing List, Nouveau Dev, linux-sunxi

Hi Mateusz,

On Wed, Aug 31, 2022 at 3:44 AM Mateusz Kwiatkowski <kfyatek@gmail.com> wrote:
> Wow. That's an enormous amount of effort put into this patch.
>
> But I'm tempted to say that this is actually overengineered quite a bit :D
> Considering that there's no way to access all these calculations from user
> space, and I can't imagine anybody using anything else than those standard
> 480i/576i (and maybe 240p/288p) modes at 13.5 MHz any time soon... I'm not
> sure if we actually need all this.

We'll need it when we get an Amiga DRM driver, which will use
7/14/28 MHz pixel clocks.

> But anyway, I'm not the maintainer of this subsystem, so I'm not the one to
> decide.
>
> > +enum drm_mode_analog {
> > +    DRM_MODE_ANALOG_NTSC,
> > +    DRM_MODE_ANALOG_PAL,
> > +};
>
> Using "NTSC" and "PAL" to describe the 50Hz and 60Hz analog TV modes is common,
> but strictly speaking a misnomer. Those are color encoding systems, and your
> patchset fully supports lesser used, but standard encodings for those (e.g.
> PAL-M for 60Hz and SECAM for 50Hz). I'd propose switching to some more neutral
> naming scheme. Some ideas:
>
> - DRM_MODE_ANALOG_60_HZ / DRM_MODE_ANALOG_50_HZ (after standard refresh rate)
> - DRM_MODE_ANALOG_525_LINES / DRM_MODE_ANALOG_625_LINES (after standard line
>   count)

IMHO these are bad names, as e.g. VGA640x480@60 is also analog, using
60 Hz and 525 lines.  Add "TV" to the name?

> - DRM_MODE_ANALOG_JM / DRM_MODE_ANALOG_BDGHIKLN (after corresponding ITU System
>   Letter Designations)

Or DRM_MODE_ITU_*?
But given the long list of letters, this looks fragile to me.

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

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

* Re: [PATCH v2 18/41] drm/connector: Add a function to lookup a TV mode by its name
  2022-08-29 13:11 ` [PATCH v2 18/41] drm/connector: Add a function to lookup a TV mode by its name Maxime Ripard
@ 2022-08-31 19:14   ` Noralf Trønnes
  0 siblings, 0 replies; 128+ messages in thread
From: Noralf Trønnes @ 2022-08-31 19:14 UTC (permalink / raw)
  To: Maxime Ripard, Maxime Ripard, Ben Skeggs, David Airlie,
	Chen-Yu Tsai, Thomas Zimmermann, Jani Nikula, Lyude Paul,
	Philipp Zabel, Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin,
	Jernej Skrabec, Samuel Holland, Karol Herbst, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Hans de Goede, linux-arm-kernel, Phil Elwell, intel-gfx,
	Dave Stevenson, dri-devel, Dom Cobley, linux-kernel, nouveau,
	linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven,
	Noralf Trønnes



Den 29.08.2022 15.11, skrev Maxime Ripard:
> As part of the command line parsing rework coming in the next patches,
> 
> we'll need to lookup drm_connector_tv_mode values by their name, already
> 
> defined in drm_tv_mode_enum_list.
> 
> 
> 
> In order to avoid any code duplication, let's do a function that will
> 
> perform a lookup of a TV mode name and return its value.
> 
> 
> 
> Signed-off-by: Maxime Ripard <maxime@cerno.tech>
> 
> 
> 
> diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
> 
> index b1fcacd150e8..0fe01a1c20ad 100644
> 
> --- a/drivers/gpu/drm/drm_connector.c
> 
> +++ b/drivers/gpu/drm/drm_connector.c
> 
> @@ -1003,6 +1003,30 @@ static const struct drm_prop_enum_list drm_tv_mode_enum_list[] = {
> 
>  };
> 
>  DRM_ENUM_NAME_FN(drm_get_tv_mode_name, drm_tv_mode_enum_list)
> 
>  
> 
> +/**
> 
> + * drm_get_tv_mode_from_name - Translates a TV mode name into its enum value
> 
> + * @name: TV Mode name we want to convert
> 
> + * @len: Length of @name
> 
> + *
> 
> + * Translates @name into an enum drm_connector_tv_mode.
> 
> + *
> 
> + * Returns: the enum value on success, a negative errno otherwise.
> 
> + */
> 
> +int drm_get_tv_mode_from_name(const char *name, size_t len)
> 
> +{
> 
> +	unsigned int i;
> 
> +
> 
> +	for (i = 0; i < ARRAY_SIZE(drm_tv_mode_enum_list); i++) {
> 
> +		const struct drm_prop_enum_list *item = &drm_tv_mode_enum_list[i];
> 
> +
> 
> +		if (strlen(item->name) == len && !strncmp(item->name, name, len))
> 
> +			return item->type;
> 
> +	}
> 
> +
> 
> +	return -EINVAL;
> 
> +}
> 
> +EXPORT_SYMBOL(drm_get_tv_mode_from_name)

Missing semicolon.

Noralf.

> 
> +
> 
>  static const struct drm_prop_enum_list drm_tv_select_enum_list[] = {
> 
>  	{ DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */
> 
>  	{ DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */
> 
> diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
> 
> index bb39d2bb806e..49d261977d4e 100644
> 
> --- a/include/drm/drm_connector.h
> 
> +++ b/include/drm/drm_connector.h
> 
> @@ -1943,6 +1943,8 @@ const char *drm_get_dp_subconnector_name(int val);
> 
>  const char *drm_get_content_protection_name(int val);
> 
>  const char *drm_get_hdcp_content_type_name(int val);
> 
>  
> 
> +int drm_get_tv_mode_from_name(const char *name, size_t len);
> 
> +
> 
>  int drm_mode_create_dvi_i_properties(struct drm_device *dev);
> 
>  void drm_connector_attach_dp_subconnector_property(struct drm_connector *connector);
> 
>  
> 
> 
> 

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

* Re: [PATCH v2 10/41] drm/modes: Add a function to generate analog display modes
  2022-08-29 13:11 ` [PATCH v2 10/41] drm/modes: Add a function to generate analog display modes Maxime Ripard
  2022-08-30 13:01   ` Maíra Canal
  2022-08-31  1:44   ` Mateusz Kwiatkowski
@ 2022-09-01 19:09   ` Noralf Trønnes
  2 siblings, 0 replies; 128+ messages in thread
From: Noralf Trønnes @ 2022-09-01 19:09 UTC (permalink / raw)
  To: Maxime Ripard, Maxime Ripard, Ben Skeggs, David Airlie,
	Chen-Yu Tsai, Thomas Zimmermann, Jani Nikula, Lyude Paul,
	Philipp Zabel, Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin,
	Jernej Skrabec, Samuel Holland, Karol Herbst, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Hans de Goede, linux-arm-kernel, Phil Elwell, intel-gfx,
	Dave Stevenson, dri-devel, Dom Cobley, linux-kernel, nouveau,
	linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven,
	Noralf Trønnes



Den 29.08.2022 15.11, skrev Maxime Ripard:
> Multiple drivers (meson, vc4, sun4i) define analog TV 525-lines and
> 
> 625-lines modes in their drivers.
> 
> 
> 
> Since those modes are fairly standard, and that we'll need to use them
> 
> in more places in the future, it makes sense to move their definition
> 
> into the core framework.
> 
> 
> 
> However, analog display usually have fairly loose timings requirements,
> 
> the only discrete parameters being the total number of lines and pixel
> 
> clock frequency. Thus, we created a function that will create a display
> 
> mode from the standard, the pixel frequency and the active area.
> 
> 
> 
> Signed-off-by: Maxime Ripard <maxime@cerno.tech>
> 

On a 32-bit build I'm getting bogus modes:

[  249.599997] [drm:drm_helper_probe_single_connector_modes]
[CONNECTOR:45:Composite-1]
[  249.600198] [drm:drm_mode_debug_printmodeline] Modeline "720x480i":
17143 13500 720 308 372 3 480 499 505 525 0x40 0x1a
[  249.600292] [drm:drm_mode_prune_invalid] Not using 720x480i mode:
H_ILLEGAL
[  249.600317] [drm:drm_mode_debug_printmodeline] Modeline "720x576i": 0
13500 720 302 366 0 576 597 603 625 0x40 0x1a
[  249.600349] [drm:drm_mode_prune_invalid] Not using 720x576i mode:
H_ILLEGAL
[  249.600374] [drm:drm_helper_probe_single_connector_modes]
[CONNECTOR:45:Composite-1] probed modes :
[  249.600453] [drm:drm_mode_debug_printmodeline] Modeline "720x240i":
60 27800 720 736 808 896 240 241 244 516 0x20 0x6

It's fine on 64-bit.

Noralf.

> 
> 
> diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
> 
> index 304004fb80aa..ee581ee17171 100644
> 
> --- a/drivers/gpu/drm/drm_modes.c
> 
> +++ b/drivers/gpu/drm/drm_modes.c
> 
> @@ -116,6 +116,459 @@ void drm_mode_probed_add(struct drm_connector *connector,
> 
>  }
> 
>  EXPORT_SYMBOL(drm_mode_probed_add);
> 
>  
> 
> +enum drm_mode_analog {
> 
> +	DRM_MODE_ANALOG_NTSC,
> 
> +	DRM_MODE_ANALOG_PAL,
> 
> +};
> 
> +
> 
> +/*
> 
> + * The timings come from:
> 
> + * - https://web.archive.org/web/20220406232708/http://www.kolumbus.fi/pami1/video/pal_ntsc.html
> 
> + * - https://web.archive.org/web/20220406124914/http://martin.hinner.info/vga/pal.html
> 
> + * - https://web.archive.org/web/20220609202433/http://www.batsocks.co.uk/readme/video_timing.htm
> 
> + */
> 
> +#define NTSC_LINE_DURATION_NS		63556U
> 
> +#define NTSC_LINES_NUMBER		525
> 
> +
> 
> +#define NTSC_HBLK_DURATION_TYP_NS	10900U
> 
> +#define NTSC_HBLK_DURATION_MIN_NS	(NTSC_HBLK_DURATION_TYP_NS - 200)
> 
> +#define NTSC_HBLK_DURATION_MAX_NS	(NTSC_HBLK_DURATION_TYP_NS + 200)
> 
> +
> 
> +#define NTSC_HACT_DURATION_TYP_NS	(NTSC_LINE_DURATION_NS - NTSC_HBLK_DURATION_TYP_NS)
> 
> +#define NTSC_HACT_DURATION_MIN_NS	(NTSC_LINE_DURATION_NS - NTSC_HBLK_DURATION_MAX_NS)
> 
> +#define NTSC_HACT_DURATION_MAX_NS	(NTSC_LINE_DURATION_NS - NTSC_HBLK_DURATION_MIN_NS)
> 
> +
> 
> +#define NTSC_HFP_DURATION_TYP_NS	1500
> 
> +#define NTSC_HFP_DURATION_MIN_NS	1270
> 
> +#define NTSC_HFP_DURATION_MAX_NS	2220
> 
> +
> 
> +#define NTSC_HSLEN_DURATION_TYP_NS	4700
> 
> +#define NTSC_HSLEN_DURATION_MIN_NS	(NTSC_HSLEN_DURATION_TYP_NS - 100)
> 
> +#define NTSC_HSLEN_DURATION_MAX_NS	(NTSC_HSLEN_DURATION_TYP_NS + 100)
> 
> +
> 
> +#define NTSC_HBP_DURATION_TYP_NS	4700
> 
> +
> 
> +/*
> 
> + * I couldn't find the actual tolerance for the back porch, so let's
> 
> + * just reuse the sync length ones.
> 
> + */
> 
> +#define NTSC_HBP_DURATION_MIN_NS	(NTSC_HBP_DURATION_TYP_NS - 100)
> 
> +#define NTSC_HBP_DURATION_MAX_NS	(NTSC_HBP_DURATION_TYP_NS + 100)
> 
> +
> 
> +#define PAL_LINE_DURATION_NS		64000U
> 
> +#define PAL_LINES_NUMBER		625
> 
> +
> 
> +#define PAL_HACT_DURATION_TYP_NS	51950U
> 
> +#define PAL_HACT_DURATION_MIN_NS	(PAL_HACT_DURATION_TYP_NS - 100)
> 
> +#define PAL_HACT_DURATION_MAX_NS	(PAL_HACT_DURATION_TYP_NS + 400)
> 
> +
> 
> +#define PAL_HBLK_DURATION_TYP_NS	(PAL_LINE_DURATION_NS - PAL_HACT_DURATION_TYP_NS)
> 
> +#define PAL_HBLK_DURATION_MIN_NS	(PAL_LINE_DURATION_NS - PAL_HACT_DURATION_MAX_NS)
> 
> +#define PAL_HBLK_DURATION_MAX_NS	(PAL_LINE_DURATION_NS - PAL_HACT_DURATION_MIN_NS)
> 
> +
> 
> +#define PAL_HFP_DURATION_TYP_NS		1650
> 
> +#define PAL_HFP_DURATION_MIN_NS		(PAL_HFP_DURATION_TYP_NS - 100)
> 
> +#define PAL_HFP_DURATION_MAX_NS		(PAL_HFP_DURATION_TYP_NS + 400)
> 
> +
> 
> +#define PAL_HSLEN_DURATION_TYP_NS	4700
> 
> +#define PAL_HSLEN_DURATION_MIN_NS	(PAL_HSLEN_DURATION_TYP_NS - 200)
> 
> +#define PAL_HSLEN_DURATION_MAX_NS	(PAL_HSLEN_DURATION_TYP_NS + 200)
> 
> +
> 
> +#define PAL_HBP_DURATION_TYP_NS		5700
> 
> +#define PAL_HBP_DURATION_MIN_NS		(PAL_HBP_DURATION_TYP_NS - 200)
> 
> +#define PAL_HBP_DURATION_MAX_NS		(PAL_HBP_DURATION_TYP_NS + 200)
> 
> +
> 
> +#define PAL_VFP_INTERLACE_LINES		5
> 
> +#define PAL_VSLEN_INTERLACE_LINES	5
> 
> +
> 
> +#define PAL_SHORT_SYNC_DURATION_NS	((2 + 30) * NSEC_PER_USEC)
> 
> +#define PAL_LONG_SYNC_DURATION_NS	((30 + 2) * NSEC_PER_USEC)
> 
> +
> 
> +struct analog_param_field {
> 
> +	unsigned int even, odd;
> 
> +};
> 
> +
> 
> +#define PARAM_FIELD(_odd, _even)		\
> 
> +	{ .even = _even, .odd = _odd }
> 
> +
> 
> +struct analog_param_range {
> 
> +	unsigned int	min, typ, max;
> 
> +};
> 
> +
> 
> +#define PARAM_RANGE(_min, _typ, _max)		\
> 
> +	{ .min = _min, .typ = _typ, .max = _max }
> 
> +
> 
> +struct analog_parameters {
> 
> +	unsigned int			num_lines;
> 
> +	unsigned int			line_duration_ns;
> 
> +
> 
> +	struct analog_param_range	hact_ns;
> 
> +	struct analog_param_range	hfp_ns;
> 
> +	struct analog_param_range	hslen_ns;
> 
> +	struct analog_param_range	hbp_ns;
> 
> +	struct analog_param_range	hblk_ns;
> 
> +
> 
> +	struct analog_param_field	vfp_lines;
> 
> +	struct analog_param_field	vslen_lines;
> 
> +	struct analog_param_field	vbp_lines;
> 
> +};
> 
> +
> 
> +#define TV_MODE_PARAMETER(_mode, _lines, _line_dur, _hact, _hfp, _hslen, _hbp, _hblk, _vfp, _vslen, _vbp) \
> 
> +	[_mode] = {							\
> 
> +		.num_lines = _lines,					\
> 
> +		.line_duration_ns = _line_dur,				\
> 
> +		.hact_ns = _hact,					\
> 
> +		.hfp_ns = _hfp,						\
> 
> +		.hslen_ns = _hslen,					\
> 
> +		.hbp_ns = _hbp,						\
> 
> +		.hblk_ns = _hblk,					\
> 
> +		.vfp_lines = _vfp,					\
> 
> +		.vslen_lines = _vslen,					\
> 
> +		.vbp_lines = _vbp,					\
> 
> +	}
> 
> +
> 
> +const static struct analog_parameters tv_modes_parameters[] = {
> 
> +	TV_MODE_PARAMETER(DRM_MODE_ANALOG_NTSC,
> 
> +			  NTSC_LINES_NUMBER,
> 
> +			  NTSC_LINE_DURATION_NS,
> 
> +			  PARAM_RANGE(NTSC_HACT_DURATION_MIN_NS,
> 
> +				      NTSC_HACT_DURATION_TYP_NS,
> 
> +				      NTSC_HACT_DURATION_MAX_NS),
> 
> +			  PARAM_RANGE(NTSC_HFP_DURATION_MIN_NS,
> 
> +				      NTSC_HFP_DURATION_TYP_NS,
> 
> +				      NTSC_HFP_DURATION_MAX_NS),
> 
> +			  PARAM_RANGE(NTSC_HSLEN_DURATION_MIN_NS,
> 
> +				      NTSC_HSLEN_DURATION_TYP_NS,
> 
> +				      NTSC_HSLEN_DURATION_MAX_NS),
> 
> +			  PARAM_RANGE(NTSC_HBP_DURATION_MIN_NS,
> 
> +				      NTSC_HBP_DURATION_TYP_NS,
> 
> +				      NTSC_HBP_DURATION_MAX_NS),
> 
> +			  PARAM_RANGE(NTSC_HBLK_DURATION_MIN_NS,
> 
> +				      NTSC_HBLK_DURATION_TYP_NS,
> 
> +				      NTSC_HBLK_DURATION_MAX_NS),
> 
> +			  PARAM_FIELD(3, 3),
> 
> +			  PARAM_FIELD(3, 3),
> 
> +			  PARAM_FIELD(3, 3)),
> 
> +	TV_MODE_PARAMETER(DRM_MODE_ANALOG_PAL,
> 
> +			  PAL_LINES_NUMBER,
> 
> +			  PAL_LINE_DURATION_NS,
> 
> +			  PARAM_RANGE(PAL_HACT_DURATION_MIN_NS,
> 
> +				      PAL_HACT_DURATION_TYP_NS,
> 
> +				      PAL_HACT_DURATION_MAX_NS),
> 
> +			  PARAM_RANGE(PAL_HFP_DURATION_MIN_NS,
> 
> +				      PAL_HFP_DURATION_TYP_NS,
> 
> +				      PAL_HFP_DURATION_MAX_NS),
> 
> +			  PARAM_RANGE(PAL_HSLEN_DURATION_MIN_NS,
> 
> +				      PAL_HSLEN_DURATION_TYP_NS,
> 
> +				      PAL_HSLEN_DURATION_MAX_NS),
> 
> +			  PARAM_RANGE(PAL_HBP_DURATION_MIN_NS,
> 
> +				      PAL_HBP_DURATION_TYP_NS,
> 
> +				      PAL_HBP_DURATION_MAX_NS),
> 
> +			  PARAM_RANGE(PAL_HBLK_DURATION_MIN_NS,
> 
> +				      PAL_HBLK_DURATION_TYP_NS,
> 
> +				      PAL_HBLK_DURATION_MAX_NS),
> 
> +
> 
> +			  /*
> 
> +			   * The front porch is actually 6 short sync
> 
> +			   * pulses for the even field, and 5 for the
> 
> +			   * odd field. Each sync takes half a life so
> 
> +			   * the odd field front porch is shorter by
> 
> +			   * half a line.
> 
> +			   *
> 
> +			   * In progressive, we're supposed to use 6
> 
> +			   * pulses, so we're fine there
> 
> +			   */
> 
> +			  PARAM_FIELD(3, 2),
> 
> +
> 
> +			  /*
> 
> +			   * The vsync length is 5 long sync pulses,
> 
> +			   * each field taking half a line. We're
> 
> +			   * shorter for both fields by half a line.
> 
> +			   *
> 
> +			   * In progressive, we're supposed to use 5
> 
> +			   * pulses, so we're off by half
> 
> +			   * a line.
> 
> +			   *
> 
> +			   * In interlace, we're now off by half a line
> 
> +			   * for the even field and one line for the odd
> 
> +			   * field.
> 
> +			   */
> 
> +			  PARAM_FIELD(3, 3),
> 
> +
> 
> +			  /*
> 
> +			   * The back porch is actually 5 short sync
> 
> +			   * pulses for the even field, 4 for the odd
> 
> +			   * field. In progressive, it's 5 short syncs.
> 
> +			   *
> 
> +			   * In progressive, we thus have 2.5 lines,
> 
> +			   * plus the 0.5 line we were missing
> 
> +			   * previously, so we should use 3 lines.
> 
> +			   *
> 
> +			   * In interlace, the even field is in the
> 
> +			   * exact same case than progressive. For the
> 
> +			   * odd field, we should be using 2 lines but
> 
> +			   * we're one line short, so we'll make up for
> 
> +			   * it here by using 3.
> 
> +			   */
> 
> +			  PARAM_FIELD(3, 3)),
> 
> +};
> 
> +
> 
> +static int fill_analog_mode(struct drm_display_mode *mode,
> 
> +			    const struct analog_parameters *params,
> 
> +			    unsigned long pixel_clock_hz,
> 
> +			    unsigned int hactive,
> 
> +			    unsigned int vactive,
> 
> +			    bool interlace)
> 
> +{
> 
> +	unsigned long pixel_duration_ns = NSEC_PER_SEC / pixel_clock_hz;
> 
> +	unsigned long long htotal;
> 
> +	unsigned int vtotal;
> 
> +	unsigned int max_hact, hact_duration_ns;
> 
> +	unsigned int hblk, hblk_duration_ns;
> 
> +	unsigned int hfp, hfp_min, hfp_duration_ns;
> 
> +	unsigned int hslen, hslen_duration_ns;
> 
> +	unsigned int hbp, hbp_min, hbp_duration_ns;
> 
> +	unsigned int porches, porches_duration_ns;
> 
> +	unsigned int vfp, vfp_min;
> 
> +	unsigned int vbp, vbp_min;
> 
> +	unsigned int vslen;
> 
> +	int porches_rem;
> 
> +	bool strict = true;
> 
> +
> 
> +	max_hact = params->hact_ns.max / pixel_duration_ns;
> 
> +	if (pixel_clock_hz == 13500000 && hactive > max_hact && hactive <= 720)
> 
> +		strict = false;
> 
> +
> 
> +	/*
> 
> +	 * Our pixel duration is going to be round down by the division,
> 
> +	 * so rounding up is probably going to introduce even more
> 
> +	 * deviation.
> 
> +	 */
> 
> +	htotal = params->line_duration_ns * pixel_clock_hz / NSEC_PER_SEC;
> 
> +
> 
> +	hact_duration_ns = hactive * pixel_duration_ns;
> 
> +	if (strict &&
> 
> +	    (hact_duration_ns < params->hact_ns.min ||
> 
> +	     hact_duration_ns > params->hact_ns.max)) {
> 
> +		DRM_ERROR("Invalid horizontal active area duration: %uns (min: %u, max %u)\n",
> 
> +			  hact_duration_ns, params->hact_ns.min, params->hact_ns.max);
> 
> +		return -EINVAL;
> 
> +	}
> 
> +
> 
> +	hblk = htotal - hactive;
> 
> +	hblk_duration_ns = hblk * pixel_duration_ns;
> 
> +	if (strict &&
> 
> +	    (hblk_duration_ns < params->hblk_ns.min ||
> 
> +	     hblk_duration_ns > params->hblk_ns.max)) {
> 
> +		DRM_ERROR("Invalid horizontal blanking duration: %uns (min: %u, max %u)\n",
> 
> +			  hblk_duration_ns, params->hblk_ns.min, params->hblk_ns.max);
> 
> +		return -EINVAL;
> 
> +	}
> 
> +
> 
> +	hslen = DIV_ROUND_UP(params->hslen_ns.typ, pixel_duration_ns);
> 
> +	hslen_duration_ns = hslen * pixel_duration_ns;
> 
> +	if (strict &&
> 
> +	    (hslen_duration_ns < params->hslen_ns.min ||
> 
> +	     hslen_duration_ns > params->hslen_ns.max)) {
> 
> +		DRM_ERROR("Invalid horizontal sync duration: %uns (min: %u, max %u)\n",
> 
> +			  hslen_duration_ns, params->hslen_ns.min, params->hslen_ns.max);
> 
> +		return -EINVAL;
> 
> +	}
> 
> +
> 
> +	porches = hblk - hslen;
> 
> +	porches_duration_ns = porches * pixel_duration_ns;
> 
> +	if (strict &&
> 
> +	    (porches_duration_ns > (params->hfp_ns.max + params->hbp_ns.max) ||
> 
> +	     porches_duration_ns < (params->hfp_ns.min + params->hbp_ns.min))) {
> 
> +		DRM_ERROR("Invalid horizontal porches duration: %uns\n", porches_duration_ns);
> 
> +		return -EINVAL;
> 
> +	}
> 
> +
> 
> +	hfp_min = DIV_ROUND_UP(params->hfp_ns.min, pixel_duration_ns);
> 
> +	hbp_min = DIV_ROUND_UP(params->hbp_ns.min, pixel_duration_ns);
> 
> +	porches_rem = porches - hfp_min - hbp_min;
> 
> +
> 
> +	hfp = hfp_min + DIV_ROUND_UP(porches_rem, 2);
> 
> +	hfp_duration_ns = hfp * pixel_duration_ns;
> 
> +	if (strict &&
> 
> +	    (hfp_duration_ns < params->hfp_ns.min ||
> 
> +	     hfp_duration_ns > params->hfp_ns.max)) {
> 
> +		DRM_ERROR("Invalid horizontal front porch duration: %uns (min: %u, max %u)\n",
> 
> +			  hfp_duration_ns, params->hfp_ns.min, params->hfp_ns.max);
> 
> +		return -EINVAL;
> 
> +	}
> 
> +
> 
> +	hbp = porches - hfp;
> 
> +	hbp_duration_ns = hbp * pixel_duration_ns;
> 
> +	if (strict &&
> 
> +	    (hbp_duration_ns < params->hbp_ns.min ||
> 
> +	     hbp_duration_ns > params->hbp_ns.max)) {
> 
> +		DRM_ERROR("Invalid horizontal back porch duration: %uns (min: %u, max %u)\n",
> 
> +			  hbp_duration_ns, params->hbp_ns.min, params->hbp_ns.max);
> 
> +		return -EINVAL;
> 
> +	}
> 
> +
> 
> +	if (htotal != (hactive + hfp + hslen + hbp))
> 
> +		return -EINVAL;
> 
> +
> 
> +	mode->clock = pixel_clock_hz / 1000;
> 
> +	mode->hdisplay = hactive;
> 
> +	mode->hsync_start = hactive + hfp;
> 
> +	mode->hsync_end = hactive + hfp + hslen;
> 
> +	mode->htotal = hactive + hfp + hslen + hbp;
> 
> +
> 
> +	if (interlace) {
> 
> +		vfp_min = params->vfp_lines.even + params->vfp_lines.odd;
> 
> +		vbp_min = params->vbp_lines.even + params->vbp_lines.odd;
> 
> +		vslen = params->vslen_lines.even + params->vslen_lines.odd;
> 
> +	} else {
> 
> +		/*
> 
> +		 * By convention, NSTC (aka 525/60) systems start with
> 
> +		 * the even field, but PAL (aka 625/50) systems start
> 
> +		 * with the odd one.
> 
> +		 *
> 
> +		 * PAL systems also have asymetric timings between the
> 
> +		 * even and odd field, while NTSC is symetric.
> 
> +		 *
> 
> +		 * Moreover, if we want to create a progressive mode for
> 
> +		 * PAL, we need to use the odd field timings.
> 
> +		 *
> 
> +		 * Since odd == even for NTSC, we can just use the odd
> 
> +		 * one all the time to simplify the code a bit.
> 
> +		 */
> 
> +		vfp_min = params->vfp_lines.odd;
> 
> +		vbp_min = params->vbp_lines.odd;
> 
> +		vslen = params->vslen_lines.odd;
> 
> +	}
> 
> +
> 
> +	porches = params->num_lines - vactive - vslen;
> 
> +	porches_rem = porches - vfp_min - vbp_min;
> 
> +
> 
> +	vfp = vfp_min + (porches_rem / 2);
> 
> +	vbp = porches - vfp;
> 
> +
> 
> +	vtotal = vactive + vfp + vslen + vbp;
> 
> +	if (params->num_lines != vtotal) {
> 
> +		DRM_ERROR("Invalid vertical total: %upx (expected %upx)\n",
> 
> +			  vtotal, params->num_lines);
> 
> +		return -EINVAL;
> 
> +	}
> 
> +
> 
> +	mode->vdisplay = vactive;
> 
> +	mode->vsync_start = vactive + vfp;
> 
> +	mode->vsync_end = vactive + vfp + vslen;
> 
> +	mode->vtotal = vactive + vfp + vslen + vbp;
> 
> +
> 
> +	mode->type = DRM_MODE_TYPE_DRIVER;
> 
> +	mode->flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC;
> 
> +	if (interlace)
> 
> +		mode->flags |= DRM_MODE_FLAG_INTERLACE;
> 
> +
> 
> +	drm_mode_set_name(mode);
> 
> +
> 
> +	if (mode->vtotal != params->num_lines)
> 
> +		return -EINVAL;
> 
> +
> 
> +	return 0;
> 
> +}
> 
> +
> 
> +/**
> 
> + * drm_analog_tv_mode - create a display mode for an analog TV
> 
> + * @dev: drm device
> 
> + * @tv_mode: TV Mode standard to create a mode for. See DRM_MODE_TV_MODE_*.
> 
> + * @pixel_clock_hz: Pixel Clock Frequency, in Hertz
> 
> + * @hdisplay: hdisplay size
> 
> + * @vdisplay: vdisplay size
> 
> + * @interlace: whether to compute an interlaced mode
> 
> + *
> 
> + * This function creates a struct drm_display_mode instance suited for
> 
> + * an analog TV output, for one of the usual analog TV mode.
> 
> + *
> 
> + * Note that @hdisplay is larger than the usual constraints for the PAL
> 
> + * and NTSC timings, and we'll choose to ignore most timings constraints
> 
> + * to reach those resolutions.
> 
> + *
> 
> + * Returns:
> 
> + *
> 
> + * A pointer to the mode, allocated with drm_mode_create(). Returns NULL
> 
> + * on error.
> 
> + */
> 
> +struct drm_display_mode *drm_analog_tv_mode(struct drm_device *dev,
> 
> +					    enum drm_connector_tv_mode tv_mode,
> 
> +					    unsigned long pixel_clock_hz,
> 
> +					    unsigned int hdisplay,
> 
> +					    unsigned int vdisplay,
> 
> +					    bool interlace)
> 
> +{
> 
> +	struct drm_display_mode *mode;
> 
> +	enum drm_mode_analog analog;
> 
> +	int ret;
> 
> +
> 
> +	switch (tv_mode) {
> 
> +	case DRM_MODE_TV_MODE_NTSC_443:
> 
> +		fallthrough;
> 
> +	case DRM_MODE_TV_MODE_NTSC_J:
> 
> +		fallthrough;
> 
> +	case DRM_MODE_TV_MODE_NTSC_M:
> 
> +		fallthrough;
> 
> +	case DRM_MODE_TV_MODE_PAL_60:
> 
> +		fallthrough;
> 
> +	case DRM_MODE_TV_MODE_PAL_M:
> 
> +		fallthrough;
> 
> +	case DRM_MODE_TV_MODE_SECAM_60:
> 
> +		analog = DRM_MODE_ANALOG_NTSC;
> 
> +		break;
> 
> +
> 
> +	case DRM_MODE_TV_MODE_PAL_B:
> 
> +		fallthrough;
> 
> +	case DRM_MODE_TV_MODE_PAL_D:
> 
> +		fallthrough;
> 
> +	case DRM_MODE_TV_MODE_PAL_G:
> 
> +		fallthrough;
> 
> +	case DRM_MODE_TV_MODE_PAL_H:
> 
> +		fallthrough;
> 
> +	case DRM_MODE_TV_MODE_PAL_I:
> 
> +		fallthrough;
> 
> +	case DRM_MODE_TV_MODE_PAL_N:
> 
> +		fallthrough;
> 
> +	case DRM_MODE_TV_MODE_PAL_NC:
> 
> +		fallthrough;
> 
> +	case DRM_MODE_TV_MODE_SECAM_B:
> 
> +		fallthrough;
> 
> +	case DRM_MODE_TV_MODE_SECAM_D:
> 
> +		fallthrough;
> 
> +	case DRM_MODE_TV_MODE_SECAM_G:
> 
> +		fallthrough;
> 
> +	case DRM_MODE_TV_MODE_SECAM_K:
> 
> +		fallthrough;
> 
> +	case DRM_MODE_TV_MODE_SECAM_K1:
> 
> +		fallthrough;
> 
> +	case DRM_MODE_TV_MODE_SECAM_L:
> 
> +		analog = DRM_MODE_ANALOG_PAL;
> 
> +		break;
> 
> +
> 
> +	default:
> 
> +		return NULL;
> 
> +	}
> 
> +
> 
> +	mode = drm_mode_create(dev);
> 
> +	if (!mode)
> 
> +		return NULL;
> 
> +
> 
> +	ret = fill_analog_mode(mode,
> 
> +			       &tv_modes_parameters[analog],
> 
> +			       pixel_clock_hz, hdisplay, vdisplay, interlace);
> 
> +	if (ret)
> 
> +		goto err_free_mode;
> 
> +
> 
> +	return mode;
> 
> +
> 
> +err_free_mode:
> 
> +	drm_mode_destroy(dev, mode);
> 
> +	return NULL;
> 
> +}
> 
> +EXPORT_SYMBOL(drm_analog_tv_mode);
> 
> +
> 
>  /**
> 
>   * drm_cvt_mode -create a modeline based on the CVT algorithm
> 
>   * @dev: drm device
> 
> diff --git a/drivers/gpu/drm/tests/Makefile b/drivers/gpu/drm/tests/Makefile
> 
> index b29ef1085cad..b22ac96fdd65 100644
> 
> --- a/drivers/gpu/drm/tests/Makefile
> 
> +++ b/drivers/gpu/drm/tests/Makefile
> 
> @@ -10,5 +10,6 @@ obj-$(CONFIG_DRM_KUNIT_TEST) += \
> 
>  	drm_framebuffer_test.o \
> 
>  	drm_kunit_helpers.o \
> 
>  	drm_mm_test.o \
> 
> +	drm_modes_test.o \
> 
>  	drm_plane_helper_test.o \
> 
>  	drm_rect_test.o
> 
> diff --git a/drivers/gpu/drm/tests/drm_modes_test.c b/drivers/gpu/drm/tests/drm_modes_test.c
> 
> new file mode 100644
> 
> index 000000000000..87d398fcb99e
> 
> --- /dev/null
> 
> +++ b/drivers/gpu/drm/tests/drm_modes_test.c
> 
> @@ -0,0 +1,131 @@
> 
> +// SPDX-License-Identifier: GPL-2.0
> 
> +/*
> 
> + * Kunit test for drm_modes functions
> 
> + */
> 
> +
> 
> +#include <kunit/test.h>
> 
> +
> 
> +#include <drm/drm_modes.h>
> 
> +
> 
> +#include "drm_kunit_helpers.h"
> 
> +
> 
> +struct drm_modes_test_priv {
> 
> +	struct drm_device *drm;
> 
> +};
> 
> +
> 
> +static int drm_modes_test_init(struct kunit *test)
> 
> +{
> 
> +	struct drm_modes_test_priv *priv;
> 
> +
> 
> +	priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
> 
> +	if (!priv)
> 
> +		return -ENOMEM;
> 
> +	test->priv = priv;
> 
> +
> 
> +	priv->drm = drm_kunit_device_init("drm-modes-test");
> 
> +	if (IS_ERR(priv->drm))
> 
> +		return PTR_ERR(priv->drm);
> 
> +
> 
> +	return 0;
> 
> +}
> 
> +
> 
> +static void drm_modes_test_exit(struct kunit *test)
> 
> +{
> 
> +	struct drm_modes_test_priv *priv = test->priv;
> 
> +
> 
> +	drm_kunit_device_exit(priv->drm);
> 
> +}
> 
> +
> 
> +static void drm_modes_analog_tv_ntsc_480i(struct kunit *test)
> 
> +{
> 
> +	struct drm_modes_test_priv *priv = test->priv;
> 
> +	struct drm_display_mode *mode;
> 
> +
> 
> +	mode = drm_analog_tv_mode(priv->drm,
> 
> +				  DRM_MODE_TV_MODE_NTSC_M,
> 
> +				  13500 * 1000, 720, 480,
> 
> +				  true);
> 
> +	KUNIT_ASSERT_NOT_NULL(test, mode);
> 
> +
> 
> +	KUNIT_EXPECT_EQ(test, drm_mode_vrefresh(mode), 60);
> 
> +	KUNIT_EXPECT_EQ(test, mode->hdisplay, 720);
> 
> +
> 
> +	/* 63.556us * 13.5MHz = 858 pixels */
> 
> +	KUNIT_EXPECT_EQ(test, mode->htotal, 858);
> 
> +	KUNIT_EXPECT_EQ(test, mode->vdisplay, 480);
> 
> +	KUNIT_EXPECT_EQ(test, mode->vtotal, 525);
> 
> +}
> 
> +
> 
> +static void drm_modes_analog_tv_ntsc_480i_inlined(struct kunit *test)
> 
> +{
> 
> +	struct drm_modes_test_priv *priv = test->priv;
> 
> +	struct drm_display_mode *expected, *mode;
> 
> +
> 
> +	expected = drm_analog_tv_mode(priv->drm,
> 
> +				      DRM_MODE_TV_MODE_NTSC_M,
> 
> +				      13500 * 1000, 720, 480,
> 
> +				      true);
> 
> +	KUNIT_ASSERT_NOT_NULL(test, expected);
> 
> +
> 
> +	mode = drm_mode_analog_ntsc_480i(priv->drm);
> 
> +	KUNIT_ASSERT_NOT_NULL(test, mode);
> 
> +
> 
> +	KUNIT_EXPECT_TRUE(test, drm_mode_equal(expected, mode));
> 
> +}
> 
> +
> 
> +static void drm_modes_analog_tv_pal_576i(struct kunit *test)
> 
> +{
> 
> +	struct drm_modes_test_priv *priv = test->priv;
> 
> +	struct drm_display_mode *mode;
> 
> +
> 
> +	mode = drm_analog_tv_mode(priv->drm,
> 
> +				  DRM_MODE_TV_MODE_PAL_B,
> 
> +				  13500 * 1000, 720, 576,
> 
> +				  true);
> 
> +	KUNIT_ASSERT_NOT_NULL(test, mode);
> 
> +
> 
> +	KUNIT_EXPECT_EQ(test, drm_mode_vrefresh(mode), 50);
> 
> +	KUNIT_EXPECT_EQ(test, mode->hdisplay, 720);
> 
> +
> 
> +	/* 64us * 13.5MHz = 864 pixels */
> 
> +	KUNIT_EXPECT_EQ(test, mode->htotal, 864);
> 
> +	KUNIT_EXPECT_EQ(test, mode->vdisplay, 576);
> 
> +	KUNIT_EXPECT_EQ(test, mode->vtotal, 625);
> 
> +}
> 
> +
> 
> +static void drm_modes_analog_tv_pal_576i_inlined(struct kunit *test)
> 
> +{
> 
> +	struct drm_modes_test_priv *priv = test->priv;
> 
> +	struct drm_display_mode *expected, *mode;
> 
> +
> 
> +	expected = drm_analog_tv_mode(priv->drm,
> 
> +				      DRM_MODE_TV_MODE_PAL_B,
> 
> +				      13500 * 1000, 720, 576,
> 
> +				      true);
> 
> +	KUNIT_ASSERT_NOT_NULL(test, expected);
> 
> +
> 
> +	mode = drm_mode_analog_pal_576i(priv->drm);
> 
> +	KUNIT_ASSERT_NOT_NULL(test, mode);
> 
> +
> 
> +	KUNIT_EXPECT_TRUE(test, drm_mode_equal(expected, mode));
> 
> +}
> 
> +
> 
> +static struct kunit_case drm_modes_analog_tv_tests[] = {
> 
> +	KUNIT_CASE(drm_modes_analog_tv_ntsc_480i),
> 
> +	KUNIT_CASE(drm_modes_analog_tv_ntsc_480i_inlined),
> 
> +	KUNIT_CASE(drm_modes_analog_tv_pal_576i),
> 
> +	KUNIT_CASE(drm_modes_analog_tv_pal_576i_inlined),
> 
> +	{ }
> 
> +};
> 
> +
> 
> +static struct kunit_suite drm_modes_analog_tv_test_suite = {
> 
> +	.name = "drm_modes_analog_tv",
> 
> +	.init = drm_modes_test_init,
> 
> +	.exit = drm_modes_test_exit,
> 
> +	.test_cases = drm_modes_analog_tv_tests,
> 
> +};
> 
> +
> 
> +kunit_test_suites(
> 
> +	&drm_modes_analog_tv_test_suite
> 
> +);
> 
> +MODULE_LICENSE("GPL v2");
> 
> diff --git a/include/drm/drm_modes.h b/include/drm/drm_modes.h
> 
> index a80ae9639e96..5ccf3d51d313 100644
> 
> --- a/include/drm/drm_modes.h
> 
> +++ b/include/drm/drm_modes.h
> 
> @@ -443,6 +443,23 @@ bool drm_mode_is_420_also(const struct drm_display_info *display,
> 
>  bool drm_mode_is_420(const struct drm_display_info *display,
> 
>  		     const struct drm_display_mode *mode);
> 
>  
> 
> +struct drm_display_mode *drm_analog_tv_mode(struct drm_device *dev,
> 
> +					    enum drm_connector_tv_mode mode,
> 
> +					    unsigned long pixel_clock_hz,
> 
> +					    unsigned int hdisplay,
> 
> +					    unsigned int vdisplay,
> 
> +					    bool interlace);
> 
> +
> 
> +static inline struct drm_display_mode *drm_mode_analog_ntsc_480i(struct drm_device *dev)
> 
> +{
> 
> +	return drm_analog_tv_mode(dev, DRM_MODE_TV_MODE_NTSC_M, 13500000, 720, 480, true);
> 
> +}
> 
> +
> 
> +static inline struct drm_display_mode *drm_mode_analog_pal_576i(struct drm_device *dev)
> 
> +{
> 
> +	return drm_analog_tv_mode(dev, DRM_MODE_TV_MODE_PAL_B, 13500000, 720, 576, true);
> 
> +}
> 
> +
> 
>  struct drm_display_mode *drm_cvt_mode(struct drm_device *dev,
> 
>  				      int hdisplay, int vdisplay, int vrefresh,
> 
>  				      bool reduced, bool interlaced,
> 
> 
> 

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

* Re: [PATCH v2 00/41] drm: Analog TV Improvements
  2022-08-29 13:11 [PATCH v2 00/41] drm: Analog TV Improvements Maxime Ripard
                   ` (40 preceding siblings ...)
  2022-08-29 13:11 ` [PATCH v2 41/41] drm/sun4i: tv: Convert to the new TV mode property Maxime Ripard
@ 2022-09-01 19:35 ` Noralf Trønnes
  2022-09-02 11:28   ` Noralf Trønnes
  41 siblings, 1 reply; 128+ messages in thread
From: Noralf Trønnes @ 2022-09-01 19:35 UTC (permalink / raw)
  To: Maxime Ripard, Maxime Ripard, Ben Skeggs, David Airlie,
	Chen-Yu Tsai, Thomas Zimmermann, Jani Nikula, Lyude Paul,
	Philipp Zabel, Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin,
	Jernej Skrabec, Samuel Holland, Karol Herbst, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen, Dom Cobley
  Cc: Hans de Goede, linux-arm-kernel, Phil Elwell, intel-gfx,
	Dave Stevenson, dri-devel, linux-kernel, nouveau, linux-sunxi,
	Mateusz Kwiatkowski, Geert Uytterhoeven, Noralf Trønnes



Den 29.08.2022 15.11, skrev Maxime Ripard:
> Hi,
> 
> 
> 
> Here's a series aiming at improving the command line named modes support,
> 
> and more importantly how we deal with all the analog TV variants.
> 
> 
> 
> The named modes support were initially introduced to allow to specify the
> 
> analog TV mode to be used.
> 
> 
> 
> However, this was causing multiple issues:
> 
> 
> 
>   * The mode name parsed on the command line was passed directly to the
> 
>     driver, which had to figure out which mode it was suppose to match;
> 
> 
> 
>   * Figuring that out wasn't really easy, since the video= argument or what
> 
>     the userspace might not even have a name in the first place, but
> 
>     instead could have passed a mode with the same timings;
> 
> 
> 
>   * The fallback to matching on the timings was mostly working as long as
> 
>     we were supporting one 525 lines (most likely NSTC) and one 625 lines
> 
>     (PAL), but couldn't differentiate between two modes with the same
> 
>     timings (NTSC vs PAL-M vs NSTC-J for example);
> 
> 
> 
>   * There was also some overlap with the tv mode property registered by
> 
>     drm_mode_create_tv_properties(), but named modes weren't interacting
> 
>     with that property at all.
> 
> 
> 
>   * Even though that property was generic, its possible values were
> 
>     specific to each drivers, which made some generic support difficult.
> 
> 
> 
> Thus, I chose to tackle in multiple steps:
> 
> 
> 
>   * A new TV norm property was introduced, with generic values, each driver
> 
>     reporting through a bitmask what standard it supports to the userspace;
> 
> 
> 
>   * This option was added to the command line parsing code to be able to
> 
>     specify it on the kernel command line, and new atomic_check and reset
> 
>     helpers were created to integrate properly into atomic KMS;
> 
> 
> 
>   * The named mode parsing code is now creating a proper display mode for
> 
>     the given named mode, and the TV standard will thus be part of the
> 
>     connector state;
> 
> 
> 
>   * Two drivers were converted and tested for now (vc4 and sun4i), with
> 
>     some backward compatibility code to translate the old TV mode to the
> 
>     new TV mode;
> 
> 
> 
> Unit tests were created along the way.
> 
> 
> 
> One can switch from NTSC to PAL now using (on vc4)
> 
> 
> 
> modetest -M vc4  -s 53:720x480i -w 53:'tv norm':0
> 
> 
> 
> modetest -M vc4 -s 53:720x480i -w 53:'tv norm':4
> 

The property name has changed, this gives me PAL:

$ modetest -M vc4 -s 45:720x576i -w 45:'TV mode':4


I have finally found a workaround for my kernel hangs.

Dom had a look at my kernel and found that the VideoCore was fine, and
he said this:

> That suggests cause of lockup was on arm side rather than VC side.
>
> But it's hard to diagnose further. Once you've had a peripheral not
> respond, the AXI bus locks up and no further operations are possible.
> Usual causes of this are required clocks being stopped or domains
> disabled and then trying to access the hardware.
>

So when I got this on my 64-bit build:

[  166.702171] SError Interrupt on CPU1, code 0x00000000bf000002 -- SError
[  166.702187] CPU: 1 PID: 8 Comm: kworker/u8:0 Tainted: G        W
    5.19.0-rc6-00096-gba7973977976-dirty #1
[  166.702200] Hardware name: Raspberry Pi 4 Model B Rev 1.1 (DT)
[  166.702206] Workqueue: events_freezable_power_ thermal_zone_device_check
[  166.702231] pstate: 200000c5 (nzCv daIF -PAN -UAO -TCO -DIT -SSBS
BTYPE=--)
[  166.702242] pc : regmap_mmio_read32le+0x10/0x28
[  166.702261] lr : regmap_mmio_read+0x44/0x70
...
[  166.702606]  bcm2711_get_temp+0x58/0xb0 [bcm2711_thermal]

I wondered if that reg read was stalled due to a clock being stopped.

Lo and behold, disabling runtime pm and keeping the vec clock running
all the time fixed it[1].

I don't know what the problem is, but at least I can now test this patchset.

[1] https://gist.github.com/notro/23b984e7fa05cfbda2db50a421cac065

Noralf.

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

* Re: [PATCH v2 09/41] drm/connector: Add TV standard property
  2022-08-29 13:11 ` [PATCH v2 09/41] drm/connector: Add TV standard property Maxime Ripard
@ 2022-09-01 22:00   ` Mateusz Kwiatkowski
  2022-09-02  7:35     ` Geert Uytterhoeven
  2022-09-07 12:10     ` Maxime Ripard
  2022-09-05 10:18   ` Noralf Trønnes
  1 sibling, 2 replies; 128+ messages in thread
From: Mateusz Kwiatkowski @ 2022-09-01 22:00 UTC (permalink / raw)
  To: Maxime Ripard, Maxime Ripard, Ben Skeggs, David Airlie,
	Chen-Yu Tsai, Thomas Zimmermann, Jani Nikula, Lyude Paul,
	Philipp Zabel, Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin,
	Jernej Skrabec, Samuel Holland, Karol Herbst,
	Noralf Trønnes, Emma Anholt, Daniel Vetter, Joonas Lahtinen
  Cc: Hans de Goede, linux-arm-kernel, Phil Elwell, intel-gfx,
	Dave Stevenson, dri-devel, Dom Cobley, linux-kernel, nouveau,
	linux-sunxi, Geert Uytterhoeven

Hi Maxime,

W dniu 29.08.2022 o 15:11, Maxime Ripard pisze:
> The TV mode property has been around for a while now to select and get the
> current TV mode output on an analog TV connector.
>
> Despite that property name being generic, its content isn't and has been
> driver-specific which makes it hard to build any generic behaviour on top
> of it, both in kernel and user-space.
>
> Let's create a new bitmask tv norm property, that can contain any of the
> analog TV standards currently supported by kernel drivers. Each driver can
> then pass in a bitmask of the modes it supports.

This is not a bitmask property anymore, you've just changed it to an enum.
The commit message is now misleading.

> +static const struct drm_prop_enum_list drm_tv_mode_enum_list[] = {
> +    { DRM_MODE_TV_MODE_NTSC_443, "NTSC-443" },
> +    { DRM_MODE_TV_MODE_NTSC_J, "NTSC-J" },
> +    { DRM_MODE_TV_MODE_NTSC_M, "NTSC-M" },
> +    { DRM_MODE_TV_MODE_PAL_60, "PAL-60" },
> +    { DRM_MODE_TV_MODE_PAL_B, "PAL-B" },
> +    { DRM_MODE_TV_MODE_PAL_D, "PAL-D" },
> +    { DRM_MODE_TV_MODE_PAL_G, "PAL-G" },
> +    { DRM_MODE_TV_MODE_PAL_H, "PAL-H" },
> +    { DRM_MODE_TV_MODE_PAL_I, "PAL-I" },
> +    { DRM_MODE_TV_MODE_PAL_M, "PAL-M" },
> +    { DRM_MODE_TV_MODE_PAL_N, "PAL-N" },
> +    { DRM_MODE_TV_MODE_PAL_NC, "PAL-Nc" },
> +    { DRM_MODE_TV_MODE_SECAM_60, "SECAM-60" },
> +    { DRM_MODE_TV_MODE_SECAM_B, "SECAM-B" },
> +    { DRM_MODE_TV_MODE_SECAM_D, "SECAM-D" },
> +    { DRM_MODE_TV_MODE_SECAM_G, "SECAM-G" },
> +    { DRM_MODE_TV_MODE_SECAM_K, "SECAM-K" },
> +    { DRM_MODE_TV_MODE_SECAM_K1, "SECAM-K1" },
> +    { DRM_MODE_TV_MODE_SECAM_L, "SECAM-L" },
> +};

I did not comment on it the last time, but this list looks a little bit random.

Compared to the standards defined by V4L2, you also define SECAM-60 (a good
thing to define, because why not), but don't define PAL-B1, PAL-D1, PAL-K,
SECAM-H, SECAM-LC (whatever that is - probably just another name for SECAM-L,
see my comment about PAL-Nc below), or NTSC-M-KR (a Korean variant of NTSC).

Like I mentioned previously, I'm personally not a fan of including all those
CCIR/ITU system variants, as they don't mean any difference to the output unless
there is an RF modulator involved. But I get it that they have already been used
and regressing probably wouldn't be a very good idea. But in that case keeping
it consistent with the set of values used by V4L2 would be wise, I think.

> +/**
> + * drm_mode_create_tv_properties - create TV specific connector properties
> + * @dev: DRM device
> + * @supported_tv_modes: Bitmask of TV modes supported (See DRM_MODE_TV_MODE_*)
> +
> + * Called by a driver's TV initialization routine, this function creates
> + * the TV specific connector properties for a given device.  Caller is
> + * responsible for allocating a list of format names and passing them to
> + * this routine.
> + *
> + * Returns:
> + * 0 on success or a negative error code on failure.
> + */
> +int drm_mode_create_tv_properties(struct drm_device *dev,
> +                  unsigned int supported_tv_modes)

supported_tv_modes is supposed to be a bitmask of BIT(DRM_MODE_TV_MODE_*)
(or (1<<DRM_MODE_TV_MODE_*)) rather than DRM_MODE_TV_MODE_* directly, but this
is not said explicitly anywhere in this doc comment.

> +    /**
> +     * @DRM_MODE_TV_MODE_PAL_NC: Seems equivalent to
> +     * @DRM_MODE_TV_MODE_PAL_N.
> +     */
> +    DRM_MODE_TV_MODE_PAL_NC,

AFAIK, the entire reason that "PAL-Nc" is ever mentioned as something separate
from PAL-N is a result of a misunderstanding or misreading of the CCIR/ITU
documents. See also the posting signed as Alchaemist here:
https://en.wikipedia.org/wiki/Talk:PAL#PAL-N_versus_PAL-Nc

That being said, we probably want to keep it if we want to remaing compatible
with the loads of software and drivers which enumerate those as separate
systems. But from a technical standpoint, PAL-N and PAL-Nc (and N/PAL, PAL-CN
etc.) are just different "spellings" referring to exactly the same system.

> +    /**
> +     * @DRM_MODE_TV_MODE_SECAM_K: CCIR System G together with the
> +     * SECAM color system. Similar to @DRM_MODE_TV_MODE_SECAM_G but
> +     * with different channels.
> +     */
> +    DRM_MODE_TV_MODE_SECAM_K,
> +
> +    /**
> +     * @DRM_MODE_TV_MODE_SECAM_K1: CCIR System G together with the
> +     * SECAM color system. Similar to @DRM_MODE_TV_MODE_SECAM_G and
> +     * @DRM_MODE_TV_MODE_SECAM_K but with different channels.
> +     */
> +    DRM_MODE_TV_MODE_SECAM_K1,

Typos: you meant CCIR Systems K and K1, not System G.

Best regards,
Mateusz Kwiatkowski

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

* Re: [PATCH v2 19/41] drm/modes: Introduce the tv_mode property as a command-line option
  2022-08-29 13:11 ` [PATCH v2 19/41] drm/modes: Introduce the tv_mode property as a command-line option Maxime Ripard
  2022-08-30 12:34   ` Maíra Canal
  2022-08-30 12:44   ` Maíra Canal
@ 2022-09-01 22:46   ` Mateusz Kwiatkowski
  2022-09-05 14:28     ` Maxime Ripard
  2 siblings, 1 reply; 128+ messages in thread
From: Mateusz Kwiatkowski @ 2022-09-01 22:46 UTC (permalink / raw)
  To: Maxime Ripard, Maxime Ripard, Ben Skeggs, David Airlie,
	Chen-Yu Tsai, Thomas Zimmermann, Jani Nikula, Lyude Paul,
	Philipp Zabel, Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin,
	Jernej Skrabec, Samuel Holland, Karol Herbst,
	Noralf Trønnes, Emma Anholt, Daniel Vetter, Joonas Lahtinen
  Cc: Hans de Goede, linux-arm-kernel, Phil Elwell, intel-gfx,
	Dave Stevenson, dri-devel, Dom Cobley, linux-kernel, nouveau,
	linux-sunxi, Geert Uytterhoeven

Hi Maxime,

> @@ -2212,20 +2239,22 @@ struct drm_named_mode {
>      unsigned int xres;
>      unsigned int yres;
>      unsigned int flags;
> +    unsigned int tv_mode;
>  };

Are _all_ named modes supposed to be about analog TV?

If so, then probably this structure should be renamed drm_named_analog_tv_mode
or something.

If not, then including tv_mode in all of them sounds almost dangrous. 0 is a
valid value for enum drm_connector_tv_mode, corresponding to
DRM_MODE_TV_MODE_NTSC_443. This is a very weird default (maybe it shouldn't be
the one that has a numeric value of 0?) and if there ever is a named mode that
is not related to analog TV, it looks that it will refer to NTSC-443.

Not sure where could that actually propagate, and maybe what I'm saying can't
happen, but I'm imagining weird scenarios where a GPU that has both a
VGA/HDMI/whatever output, and a composite output, switches to NTSC-443 on the
composite output by default because a named mode for the modern output is
selected.

Maybe something like DRM_MODE_TV_MODE_NONE = 0 would make sense?

Maybe not. This is not an actual suggestion, just "thinking out loud".

Best regards,
Mateusz Kwiatkowski

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

* Re: [PATCH v2 20/41] drm/modes: Properly generate a drm_display_mode from a named mode
  2022-08-29 13:11 ` [PATCH v2 20/41] drm/modes: Properly generate a drm_display_mode from a named mode Maxime Ripard
@ 2022-09-01 22:52   ` Mateusz Kwiatkowski
  0 siblings, 0 replies; 128+ messages in thread
From: Mateusz Kwiatkowski @ 2022-09-01 22:52 UTC (permalink / raw)
  To: Maxime Ripard, Maxime Ripard, Ben Skeggs, David Airlie,
	Chen-Yu Tsai, Thomas Zimmermann, Jani Nikula, Lyude Paul,
	Philipp Zabel, Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin,
	Jernej Skrabec, Samuel Holland, Karol Herbst,
	Noralf Trønnes, Emma Anholt, Daniel Vetter, Joonas Lahtinen
  Cc: Hans de Goede, linux-arm-kernel, Phil Elwell, intel-gfx,
	Dave Stevenson, dri-devel, Dom Cobley, linux-kernel, nouveau,
	linux-sunxi, Geert Uytterhoeven

Hi Maxime,

> +        if (!named_mode->tv_mode)
> +            continue;

As mentioned in the previous email replying to 19/41, this makes it impossible
to specify DRM_MODE_TV_MODE_NTSC_443 as currently defined in the named mode
successfully.

Best regards,
Mateusz Kwiatkowski

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

* Re: [PATCH v2 09/41] drm/connector: Add TV standard property
  2022-09-01 22:00   ` Mateusz Kwiatkowski
@ 2022-09-02  7:35     ` Geert Uytterhoeven
  2022-09-07 12:11       ` Maxime Ripard
  2022-09-07 12:10     ` Maxime Ripard
  1 sibling, 1 reply; 128+ messages in thread
From: Geert Uytterhoeven @ 2022-09-02  7:35 UTC (permalink / raw)
  To: Mateusz Kwiatkowski
  Cc: Maxime Ripard, Maxime Ripard, Ben Skeggs, David Airlie,
	Chen-Yu Tsai, Thomas Zimmermann, Jani Nikula, Lyude Paul,
	Philipp Zabel, Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin,
	Jernej Skrabec, Samuel Holland, Karol Herbst,
	Noralf Trønnes, Emma Anholt, Daniel Vetter, Joonas Lahtinen,
	Hans de Goede, Linux ARM, Phil Elwell,
	Intel Graphics Development, Dave Stevenson, DRI Development,
	Dom Cobley, Linux Kernel Mailing List, Nouveau Dev, linux-sunxi

Hi Mateusz,

On Fri, Sep 2, 2022 at 12:00 AM Mateusz Kwiatkowski <kfyatek@gmail.com> wrote:
> W dniu 29.08.2022 o 15:11, Maxime Ripard pisze:
> > The TV mode property has been around for a while now to select and get the
> > current TV mode output on an analog TV connector.
> >
> > Despite that property name being generic, its content isn't and has been
> > driver-specific which makes it hard to build any generic behaviour on top
> > of it, both in kernel and user-space.
> >
> > Let's create a new bitmask tv norm property, that can contain any of the
> > analog TV standards currently supported by kernel drivers. Each driver can
> > then pass in a bitmask of the modes it supports.
>
> This is not a bitmask property anymore, you've just changed it to an enum.
> The commit message is now misleading.
>
> > +static const struct drm_prop_enum_list drm_tv_mode_enum_list[] = {
> > +    { DRM_MODE_TV_MODE_NTSC_443, "NTSC-443" },
> > +    { DRM_MODE_TV_MODE_NTSC_J, "NTSC-J" },
> > +    { DRM_MODE_TV_MODE_NTSC_M, "NTSC-M" },
> > +    { DRM_MODE_TV_MODE_PAL_60, "PAL-60" },
> > +    { DRM_MODE_TV_MODE_PAL_B, "PAL-B" },
> > +    { DRM_MODE_TV_MODE_PAL_D, "PAL-D" },
> > +    { DRM_MODE_TV_MODE_PAL_G, "PAL-G" },
> > +    { DRM_MODE_TV_MODE_PAL_H, "PAL-H" },
> > +    { DRM_MODE_TV_MODE_PAL_I, "PAL-I" },
> > +    { DRM_MODE_TV_MODE_PAL_M, "PAL-M" },
> > +    { DRM_MODE_TV_MODE_PAL_N, "PAL-N" },
> > +    { DRM_MODE_TV_MODE_PAL_NC, "PAL-Nc" },
> > +    { DRM_MODE_TV_MODE_SECAM_60, "SECAM-60" },
> > +    { DRM_MODE_TV_MODE_SECAM_B, "SECAM-B" },
> > +    { DRM_MODE_TV_MODE_SECAM_D, "SECAM-D" },
> > +    { DRM_MODE_TV_MODE_SECAM_G, "SECAM-G" },
> > +    { DRM_MODE_TV_MODE_SECAM_K, "SECAM-K" },
> > +    { DRM_MODE_TV_MODE_SECAM_K1, "SECAM-K1" },
> > +    { DRM_MODE_TV_MODE_SECAM_L, "SECAM-L" },
> > +};
>
> I did not comment on it the last time, but this list looks a little bit random.
>
> Compared to the standards defined by V4L2, you also define SECAM-60 (a good
> thing to define, because why not), but don't define PAL-B1, PAL-D1, PAL-K,
> SECAM-H, SECAM-LC (whatever that is - probably just another name for SECAM-L,
> see my comment about PAL-Nc below), or NTSC-M-KR (a Korean variant of NTSC).
>
> Like I mentioned previously, I'm personally not a fan of including all those
> CCIR/ITU system variants, as they don't mean any difference to the output unless
> there is an RF modulator involved. But I get it that they have already been used
> and regressing probably wouldn't be a very good idea. But in that case keeping
> it consistent with the set of values used by V4L2 would be wise, I think.

Exactly. Anything outputting RGB (e.g. through a SCART or VGA connector)
doesn't care about the color subcarrier or modulator parts.  Likewise,
anything outputting CVBS doesn't care about the modulator part.

Perhaps "generic" variants of NSTC and PAL/SECAM should be added, which
would really just mean 525/60 resp. 625/50.

Alternatively, the tv_mode field could be split in two parts (either
two separate fields, or bitwise), to maintain a clear separation between
lines/fields versus color encoding and RF modulation (with zero for the
latter meaning a generic version)? That would also keep the door open
for TV_MODE_405_50, TV_MODE_819_50, TV_MODE_750_50, TV_MODE_750_60, ...

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

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

* Re: [PATCH v2 00/41] drm: Analog TV Improvements
  2022-09-01 19:35 ` [PATCH v2 00/41] drm: Analog TV Improvements Noralf Trønnes
@ 2022-09-02 11:28   ` Noralf Trønnes
  2022-09-05 14:57     ` Maxime Ripard
  0 siblings, 1 reply; 128+ messages in thread
From: Noralf Trønnes @ 2022-09-02 11:28 UTC (permalink / raw)
  To: Maxime Ripard, Maxime Ripard, Ben Skeggs, David Airlie,
	Chen-Yu Tsai, Thomas Zimmermann, Jani Nikula, Lyude Paul,
	Philipp Zabel, Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin,
	Jernej Skrabec, Samuel Holland, Karol Herbst, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen, Dom Cobley
  Cc: Hans de Goede, linux-arm-kernel, Phil Elwell, intel-gfx,
	Dave Stevenson, dri-devel, linux-kernel, nouveau, linux-sunxi,
	Mateusz Kwiatkowski, Geert Uytterhoeven, Noralf Trønnes



Den 01.09.2022 21.35, skrev Noralf Trønnes:
> 
> 
> I have finally found a workaround for my kernel hangs.
> 
> Dom had a look at my kernel and found that the VideoCore was fine, and
> he said this:
> 
>> That suggests cause of lockup was on arm side rather than VC side.
>>
>> But it's hard to diagnose further. Once you've had a peripheral not
>> respond, the AXI bus locks up and no further operations are possible.
>> Usual causes of this are required clocks being stopped or domains
>> disabled and then trying to access the hardware.
>>
> 
> So when I got this on my 64-bit build:
> 
> [  166.702171] SError Interrupt on CPU1, code 0x00000000bf000002 -- SError
> [  166.702187] CPU: 1 PID: 8 Comm: kworker/u8:0 Tainted: G        W
>     5.19.0-rc6-00096-gba7973977976-dirty #1
> [  166.702200] Hardware name: Raspberry Pi 4 Model B Rev 1.1 (DT)
> [  166.702206] Workqueue: events_freezable_power_ thermal_zone_device_check
> [  166.702231] pstate: 200000c5 (nzCv daIF -PAN -UAO -TCO -DIT -SSBS
> BTYPE=--)
> [  166.702242] pc : regmap_mmio_read32le+0x10/0x28
> [  166.702261] lr : regmap_mmio_read+0x44/0x70
> ...
> [  166.702606]  bcm2711_get_temp+0x58/0xb0 [bcm2711_thermal]
> 
> I wondered if that reg read was stalled due to a clock being stopped.
> 
> Lo and behold, disabling runtime pm and keeping the vec clock running
> all the time fixed it[1].
> 
> I don't know what the problem is, but at least I can now test this patchset.
> 
> [1] https://gist.github.com/notro/23b984e7fa05cfbda2db50a421cac065
> 

It turns out I didn't have to disable runtime pm:
https://gist.github.com/notro/0adcfcb12460b54e54458afe11dc8ea2

Noralf.

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

* Re: [PATCH v2 09/41] drm/connector: Add TV standard property
  2022-08-29 13:11 ` [PATCH v2 09/41] drm/connector: Add TV standard property Maxime Ripard
  2022-09-01 22:00   ` Mateusz Kwiatkowski
@ 2022-09-05 10:18   ` Noralf Trønnes
  1 sibling, 0 replies; 128+ messages in thread
From: Noralf Trønnes @ 2022-09-05 10:18 UTC (permalink / raw)
  To: Maxime Ripard, Maxime Ripard, Ben Skeggs, David Airlie,
	Chen-Yu Tsai, Thomas Zimmermann, Jani Nikula, Lyude Paul,
	Philipp Zabel, Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin,
	Jernej Skrabec, Samuel Holland, Karol Herbst, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen
  Cc: Hans de Goede, linux-arm-kernel, Phil Elwell, intel-gfx,
	Dave Stevenson, dri-devel, Dom Cobley, linux-kernel, nouveau,
	linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven,
	Noralf Trønnes



Den 29.08.2022 15.11, skrev Maxime Ripard:
> The TV mode property has been around for a while now to select and get the
> 
> current TV mode output on an analog TV connector.
> 
> 
> 
> Despite that property name being generic, its content isn't and has been
> 
> driver-specific which makes it hard to build any generic behaviour on top
> 
> of it, both in kernel and user-space.
> 
> 
> 
> Let's create a new bitmask tv norm property, that can contain any of the
> 
> analog TV standards currently supported by kernel drivers. Each driver can
> 
> then pass in a bitmask of the modes it supports.
> 
> 
> 
> We'll then be able to phase out the older tv mode property.
> 
> 
> 
> Signed-off-by: Maxime Ripard <maxime@cerno.tech>
> 
> 
> 

> diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c

> +/**
> 
> + * drm_mode_create_tv_properties - create TV specific connector properties
> 
> + * @dev: DRM device
> 
> + * @supported_tv_modes: Bitmask of TV modes supported (See DRM_MODE_TV_MODE_*)
> 
> +
> 
> + * Called by a driver's TV initialization routine, this function creates
> 
> + * the TV specific connector properties for a given device.  Caller is
> 
> + * responsible for allocating a list of format names and passing them to
> 
> + * this routine.
> 
> + *
> 
> + * Returns:
> 
> + * 0 on success or a negative error code on failure.
> 
> + */
> 
> +int drm_mode_create_tv_properties(struct drm_device *dev,
> 
> +				  unsigned int supported_tv_modes)
> 
> +{
> 
> +	struct drm_prop_enum_list tv_mode_list[DRM_MODE_TV_MODE_MAX];
> 
> +	struct drm_property *tv_mode;
> 
> +	unsigned int i, len = 0;
> 
> +
> 

Can you add a check here like in the legacy version:

	if (dev->mode_config.tv_mode_property)
		return 0;

This way it's possible to call this multiple times. Like in drm/gud
during connector init if there are multiple TV connectors or if a device
with multiple IP blocks should show up.

Noralf.

> +	for (i = 0; i < DRM_MODE_TV_MODE_MAX; i++) {
> 
> +		if (!(supported_tv_modes & BIT(i)))
> 
> +			continue;
> 
> +
> 
> +		tv_mode_list[len].type = i;
> 
> +		tv_mode_list[len].name = drm_get_tv_mode_name(i);
> 
> +		len++;
> 
> +	}
> 
> +
> 
> +	tv_mode = drm_property_create_enum(dev, 0, "TV mode",
> 
> +					   tv_mode_list, len);
> 
> +	if (!tv_mode)
> 
> +		return -ENOMEM;
> 
> +
> 
> +	dev->mode_config.tv_mode_property = tv_mode;
> 
> +
> 
> +	return drm_mode_create_tv_properties_legacy(dev, 0, NULL);
> 
> +}
> 
> +EXPORT_SYMBOL(drm_mode_create_tv_properties);
> 

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

* Re: [PATCH v2 10/41] drm/modes: Add a function to generate analog display modes
  2022-08-31  8:14     ` Geert Uytterhoeven
@ 2022-09-05 13:32       ` Maxime Ripard
  2022-09-05 16:32         ` Mateusz Kwiatkowski
  0 siblings, 1 reply; 128+ messages in thread
From: Maxime Ripard @ 2022-09-05 13:32 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: Mateusz Kwiatkowski, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec,
	Samuel Holland, Karol Herbst, Noralf Trønnes, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen, Hans de Goede, Linux ARM,
	Phil Elwell, Intel Graphics Development, Dave Stevenson,
	DRI Development, Dom Cobley, Linux Kernel Mailing List,
	Nouveau Dev, linux-sunxi

[-- Attachment #1: Type: text/plain, Size: 1320 bytes --]

Hi,

On Wed, Aug 31, 2022 at 10:14:28AM +0200, Geert Uytterhoeven wrote:
> > > +enum drm_mode_analog {
> > > +    DRM_MODE_ANALOG_NTSC,
> > > +    DRM_MODE_ANALOG_PAL,
> > > +};
> >
> > Using "NTSC" and "PAL" to describe the 50Hz and 60Hz analog TV modes is common,
> > but strictly speaking a misnomer. Those are color encoding systems, and your
> > patchset fully supports lesser used, but standard encodings for those (e.g.
> > PAL-M for 60Hz and SECAM for 50Hz). I'd propose switching to some more neutral
> > naming scheme. Some ideas:
> >
> > - DRM_MODE_ANALOG_60_HZ / DRM_MODE_ANALOG_50_HZ (after standard refresh rate)
> > - DRM_MODE_ANALOG_525_LINES / DRM_MODE_ANALOG_625_LINES (after standard line
> >   count)
> 
> IMHO these are bad names, as e.g. VGA640x480@60 is also analog, using
> 60 Hz and 525 lines.  Add "TV" to the name?
> 
> > - DRM_MODE_ANALOG_JM / DRM_MODE_ANALOG_BDGHIKLN (after corresponding ITU System
> >   Letter Designations)
> 
> Or DRM_MODE_ITU_*?
> But given the long list of letters, this looks fragile to me.

Does it matter at all? It's an internal API that isn't exposed at all.
I'd rather have a common name that everyone can understand in this case
rather than a *perfect* name where most will scratch their head
wondering what it's about.

Maxime

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

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

* Re: [PATCH v2 10/41] drm/modes: Add a function to generate analog display modes
  2022-08-31  1:44   ` Mateusz Kwiatkowski
  2022-08-31  8:14     ` Geert Uytterhoeven
@ 2022-09-05 13:37     ` Maxime Ripard
  2022-09-05 16:44       ` Mateusz Kwiatkowski
  1 sibling, 1 reply; 128+ messages in thread
From: Maxime Ripard @ 2022-09-05 13:37 UTC (permalink / raw)
  To: Mateusz Kwiatkowski
  Cc: Ben Skeggs, David Airlie, Chen-Yu Tsai, Thomas Zimmermann,
	Jani Nikula, Lyude Paul, Philipp Zabel, Maarten Lankhorst,
	Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec, Samuel Holland,
	Karol Herbst, Noralf Trønnes, Emma Anholt, Daniel Vetter,
	Joonas Lahtinen, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Geert Uytterhoeven

[-- Attachment #1: Type: text/plain, Size: 1985 bytes --]

Hi,

On Wed, Aug 31, 2022 at 03:44:52AM +0200, Mateusz Kwiatkowski wrote:
> > +#define NTSC_HFP_DURATION_TYP_NS    1500
> > +#define NTSC_HFP_DURATION_MIN_NS    1270
> > +#define NTSC_HFP_DURATION_MAX_NS    2220
> 
> You've defined those min/typ/max ranges, but you're not using the "typ" field
> for anything other than hslen.

Yeah... I've left most of them because it was so hard to find most of
them, it's useful at least for documentation purposes. And it's a define
so there's pretty much no downside to it as far as the final binary is
involved.

> The actual "typical" value is thus always the midpoint, which isn't
> necessarily the best choice.
> 
> In particular, for the standard 720px wide modes at 13.5 MHz, hsync_start
> ends up being 735 for 480i and 734 for 576i, instead of 736 and 732 requested
> by BT.601. That's all obviously within tolerances, but the image ends up
> noticeably off-center (at least on modern TVs), especially in the 576i case.

I'll try to fix that up.

> > +    htotal = params->line_duration_ns * pixel_clock_hz / NSEC_PER_SEC;
> 
> You're multiplying an unsigned int and an unsigned long - both types are only
> required to be 32 bit, so this is likely to overflow. You need to use a cast to
> unsigned long long, and then call do_div() for 64-bit division.
> 
> This actually overflowed on me on my Pi running ARM32 kernel, resulting in
> negative horizontal porch lengths, and drm_helper_probe_add_cmdline_mode()
> taking over the mode generation (badly), and a horrible mess on screen.

Indeed, that's bad.

> > +    vfp = vfp_min + (porches_rem / 2);
> > +    vbp = porches - vfp;
> 
> Relative position of the vertical sync within the VBI effectively moves the
> image up and down. Adding that (porches_rem / 2) moves the image up off center
> by that many pixels. I'd keep the VFP always at minimum to keep the image
> centered.

And you would increase the back porch only then?

Maxime

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

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

* Re: [PATCH v2 19/41] drm/modes: Introduce the tv_mode property as a command-line option
  2022-09-01 22:46   ` Mateusz Kwiatkowski
@ 2022-09-05 14:28     ` Maxime Ripard
  0 siblings, 0 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-09-05 14:28 UTC (permalink / raw)
  To: Mateusz Kwiatkowski
  Cc: Ben Skeggs, David Airlie, Chen-Yu Tsai, Thomas Zimmermann,
	Jani Nikula, Lyude Paul, Philipp Zabel, Maarten Lankhorst,
	Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec, Samuel Holland,
	Karol Herbst, Noralf Trønnes, Emma Anholt, Daniel Vetter,
	Joonas Lahtinen, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Geert Uytterhoeven

[-- Attachment #1: Type: text/plain, Size: 1738 bytes --]

On Fri, Sep 02, 2022 at 12:46:29AM +0200, Mateusz Kwiatkowski wrote:
> > @@ -2212,20 +2239,22 @@ struct drm_named_mode {
> >      unsigned int xres;
> >      unsigned int yres;
> >      unsigned int flags;
> > +    unsigned int tv_mode;
> >  };
> 
> Are _all_ named modes supposed to be about analog TV?
>
> If so, then probably this structure should be renamed drm_named_analog_tv_mode
> or something.

I don't think they need to, but it's the only use case we've had so far.
We could also imagine using UHD for 3840x2160 for example, so I wouldn't
say it's limited to analog tv.

> If not, then including tv_mode in all of them sounds almost dangrous. 0 is a
> valid value for enum drm_connector_tv_mode, corresponding to
> DRM_MODE_TV_MODE_NTSC_443. This is a very weird default (maybe it shouldn't be
> the one that has a numeric value of 0?) and if there ever is a named mode that
> is not related to analog TV, it looks that it will refer to NTSC-443.
> 
> Not sure where could that actually propagate, and maybe what I'm saying can't
> happen, but I'm imagining weird scenarios where a GPU that has both a
> VGA/HDMI/whatever output, and a composite output, switches to NTSC-443 on the
> composite output by default because a named mode for the modern output is
> selected.

So, named modes are per-connector so the fact that there's another
output doesn't really matter. Then, the answer is quite simple actually,
the HDMI driver wouldn't register and use the TV mode property at all,
so it would completely ignore it, no matter what value it has.

So it's not really a concern.

> Maybe something like DRM_MODE_TV_MODE_NONE = 0 would make sense?

But I guess we can add it still.

Maxime

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

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

* Re: [PATCH v2 00/41] drm: Analog TV Improvements
  2022-09-02 11:28   ` Noralf Trønnes
@ 2022-09-05 14:57     ` Maxime Ripard
  2022-09-05 15:17       ` Noralf Trønnes
  2022-09-07 10:36       ` Stefan Wahren
  0 siblings, 2 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-09-05 14:57 UTC (permalink / raw)
  To: Noralf Trønnes
  Cc: Ben Skeggs, David Airlie, Chen-Yu Tsai, Thomas Zimmermann,
	Jani Nikula, Lyude Paul, Philipp Zabel, Maarten Lankhorst,
	Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec, Samuel Holland,
	Karol Herbst, Emma Anholt, Daniel Vetter, Joonas Lahtinen,
	Dom Cobley, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, linux-kernel, nouveau,
	linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

[-- Attachment #1: Type: text/plain, Size: 2007 bytes --]

On Fri, Sep 02, 2022 at 01:28:16PM +0200, Noralf Trønnes wrote:
> 
> 
> Den 01.09.2022 21.35, skrev Noralf Trønnes:
> > 
> > 
> > I have finally found a workaround for my kernel hangs.
> > 
> > Dom had a look at my kernel and found that the VideoCore was fine, and
> > he said this:
> > 
> >> That suggests cause of lockup was on arm side rather than VC side.
> >>
> >> But it's hard to diagnose further. Once you've had a peripheral not
> >> respond, the AXI bus locks up and no further operations are possible.
> >> Usual causes of this are required clocks being stopped or domains
> >> disabled and then trying to access the hardware.
> >>
> > 
> > So when I got this on my 64-bit build:
> > 
> > [  166.702171] SError Interrupt on CPU1, code 0x00000000bf000002 -- SError
> > [  166.702187] CPU: 1 PID: 8 Comm: kworker/u8:0 Tainted: G        W
> >     5.19.0-rc6-00096-gba7973977976-dirty #1
> > [  166.702200] Hardware name: Raspberry Pi 4 Model B Rev 1.1 (DT)
> > [  166.702206] Workqueue: events_freezable_power_ thermal_zone_device_check
> > [  166.702231] pstate: 200000c5 (nzCv daIF -PAN -UAO -TCO -DIT -SSBS
> > BTYPE=--)
> > [  166.702242] pc : regmap_mmio_read32le+0x10/0x28
> > [  166.702261] lr : regmap_mmio_read+0x44/0x70
> > ...
> > [  166.702606]  bcm2711_get_temp+0x58/0xb0 [bcm2711_thermal]
> > 
> > I wondered if that reg read was stalled due to a clock being stopped.
> > 
> > Lo and behold, disabling runtime pm and keeping the vec clock running
> > all the time fixed it[1].
> > 
> > I don't know what the problem is, but at least I can now test this patchset.
> > 
> > [1] https://gist.github.com/notro/23b984e7fa05cfbda2db50a421cac065
> > 
> 
> It turns out I didn't have to disable runtime pm:
> https://gist.github.com/notro/0adcfcb12460b54e54458afe11dc8ea2

If the bcm2711_thermal IP needs that clock to be enabled, it should grab
a reference itself, but it looks like even the device tree binding
doesn't ask for one.

Maxime

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

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

* Re: [PATCH v2 00/41] drm: Analog TV Improvements
  2022-09-05 14:57     ` Maxime Ripard
@ 2022-09-05 15:17       ` Noralf Trønnes
  2022-09-07  9:58         ` Maxime Ripard
  2022-09-07 10:36       ` Stefan Wahren
  1 sibling, 1 reply; 128+ messages in thread
From: Noralf Trønnes @ 2022-09-05 15:17 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Ben Skeggs, David Airlie, Chen-Yu Tsai, Thomas Zimmermann,
	Jani Nikula, Lyude Paul, Philipp Zabel, Maarten Lankhorst,
	Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec, Samuel Holland,
	Karol Herbst, Emma Anholt, Daniel Vetter, Joonas Lahtinen,
	Dom Cobley, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, linux-kernel, nouveau,
	linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven,
	Noralf Trønnes



Den 05.09.2022 16.57, skrev Maxime Ripard:
> On Fri, Sep 02, 2022 at 01:28:16PM +0200, Noralf Trønnes wrote:
>>
>>
>> Den 01.09.2022 21.35, skrev Noralf Trønnes:
>>>
>>>
>>> I have finally found a workaround for my kernel hangs.
>>>
>>> Dom had a look at my kernel and found that the VideoCore was fine, and
>>> he said this:
>>>
>>>> That suggests cause of lockup was on arm side rather than VC side.
>>>>
>>>> But it's hard to diagnose further. Once you've had a peripheral not
>>>> respond, the AXI bus locks up and no further operations are possible.
>>>> Usual causes of this are required clocks being stopped or domains
>>>> disabled and then trying to access the hardware.
>>>>
>>>
>>> So when I got this on my 64-bit build:
>>>
>>> [  166.702171] SError Interrupt on CPU1, code 0x00000000bf000002 -- SError
>>> [  166.702187] CPU: 1 PID: 8 Comm: kworker/u8:0 Tainted: G        W
>>>     5.19.0-rc6-00096-gba7973977976-dirty #1
>>> [  166.702200] Hardware name: Raspberry Pi 4 Model B Rev 1.1 (DT)
>>> [  166.702206] Workqueue: events_freezable_power_ thermal_zone_device_check
>>> [  166.702231] pstate: 200000c5 (nzCv daIF -PAN -UAO -TCO -DIT -SSBS
>>> BTYPE=--)
>>> [  166.702242] pc : regmap_mmio_read32le+0x10/0x28
>>> [  166.702261] lr : regmap_mmio_read+0x44/0x70
>>> ...
>>> [  166.702606]  bcm2711_get_temp+0x58/0xb0 [bcm2711_thermal]
>>>
>>> I wondered if that reg read was stalled due to a clock being stopped.
>>>
>>> Lo and behold, disabling runtime pm and keeping the vec clock running
>>> all the time fixed it[1].
>>>
>>> I don't know what the problem is, but at least I can now test this patchset.
>>>
>>> [1] https://gist.github.com/notro/23b984e7fa05cfbda2db50a421cac065
>>>
>>
>> It turns out I didn't have to disable runtime pm:
>> https://gist.github.com/notro/0adcfcb12460b54e54458afe11dc8ea2
> 
> If the bcm2711_thermal IP needs that clock to be enabled, it should grab
> a reference itself, but it looks like even the device tree binding
> doesn't ask for one.
> 

The first thing I tried was to unload the bcm2711_thermal module before
running modeset and it still hung, so I don't think that's the problem.

Noralf.

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

* Re: [PATCH v2 10/41] drm/modes: Add a function to generate analog display modes
  2022-09-05 13:32       ` Maxime Ripard
@ 2022-09-05 16:32         ` Mateusz Kwiatkowski
  2022-09-07 14:38           ` Maxime Ripard
  0 siblings, 1 reply; 128+ messages in thread
From: Mateusz Kwiatkowski @ 2022-09-05 16:32 UTC (permalink / raw)
  To: Maxime Ripard, Geert Uytterhoeven
  Cc: Ben Skeggs, David Airlie, Chen-Yu Tsai, Thomas Zimmermann,
	Jani Nikula, Lyude Paul, Philipp Zabel, Maarten Lankhorst,
	Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec, Samuel Holland,
	Karol Herbst, Noralf Trønnes, Emma Anholt, Daniel Vetter,
	Joonas Lahtinen, Hans de Goede, Linux ARM, Phil Elwell,
	Intel Graphics Development, Dave Stevenson, DRI Development,
	Dom Cobley, Linux Kernel Mailing List, Nouveau Dev, linux-sunxi

Hi Maxime,

W dniu 5.09.2022 o 15:32, Maxime Ripard pisze:
> Hi,
>
> On Wed, Aug 31, 2022 at 10:14:28AM +0200, Geert Uytterhoeven wrote:
>>>> +enum drm_mode_analog {
>>>> +    DRM_MODE_ANALOG_NTSC,
>>>> +    DRM_MODE_ANALOG_PAL,
>>>> +};
>>>
>>> Using "NTSC" and "PAL" to describe the 50Hz and 60Hz analog TV modes is common,
>>> but strictly speaking a misnomer. Those are color encoding systems, and your
>>> patchset fully supports lesser used, but standard encodings for those (e.g.
>>> PAL-M for 60Hz and SECAM for 50Hz). I'd propose switching to some more neutral
>>> naming scheme. Some ideas:
>>>
>>> - DRM_MODE_ANALOG_60_HZ / DRM_MODE_ANALOG_50_HZ (after standard refresh rate)
>>> - DRM_MODE_ANALOG_525_LINES / DRM_MODE_ANALOG_625_LINES (after standard line
>>>   count)
>>
>> IMHO these are bad names, as e.g. VGA640x480@60 is also analog, using
>> 60 Hz and 525 lines.  Add "TV" to the name?
>>
>>> - DRM_MODE_ANALOG_JM / DRM_MODE_ANALOG_BDGHIKLN (after corresponding ITU System
>>>   Letter Designations)
>>
>> Or DRM_MODE_ITU_*?
>> But given the long list of letters, this looks fragile to me.
>
> Does it matter at all? It's an internal API that isn't exposed at all.
> I'd rather have a common name that everyone can understand in this case
> rather than a *perfect* name where most will scratch their head
> wondering what it's about.

You may have a point. But in that case, maybe it'd make sense to at least add
a short comment explaining what do you mean by "NTSC" and "PAL" in this context?

Best regards,
Mateusz Kwiatkowski

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

* Re: [PATCH v2 10/41] drm/modes: Add a function to generate analog display modes
  2022-09-05 13:37     ` Maxime Ripard
@ 2022-09-05 16:44       ` Mateusz Kwiatkowski
  2022-09-07 14:34         ` Maxime Ripard
  0 siblings, 1 reply; 128+ messages in thread
From: Mateusz Kwiatkowski @ 2022-09-05 16:44 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Ben Skeggs, David Airlie, Chen-Yu Tsai, Thomas Zimmermann,
	Jani Nikula, Lyude Paul, Philipp Zabel, Maarten Lankhorst,
	Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec, Samuel Holland,
	Karol Herbst, Noralf Trønnes, Emma Anholt, Daniel Vetter,
	Joonas Lahtinen, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Geert Uytterhoeven

Hi Maxime,

W dniu 5.09.2022 o 15:37, Maxime Ripard pisze:
>>> +    vfp = vfp_min + (porches_rem / 2);
>>> +    vbp = porches - vfp;
>>
>> Relative position of the vertical sync within the VBI effectively moves the
>> image up and down. Adding that (porches_rem / 2) moves the image up off center
>> by that many pixels. I'd keep the VFP always at minimum to keep the image
>> centered.
>
> And you would increase the back porch only then?

Well, increasing vbp only gives a centered image with the default 480i/576i
resolutions. However, only ever changing vbp will cause the image to be always
at the bottom of the screen when the active line count is decreased (e.g.
setting the resolution to 720x480 but for 50Hz "PAL" - like many game consoles
did back in the day).

I believe that the perfect solution would:

- Use the canonical / standard-defined blanking line counts for the standard
  vertical resolutions (480/486/576)
- Increase vfp and vbp from there by the same number if a smaller number of
  active lines is specified, so that the resulting image is centered
- Likewise, decrease vfp and vbp by the same number if the active line number
  is larger and there is still leeway (this should allow for seamless handling
  of 480i vs. 486i for 60 Hz "NTSC")
- If even more active lines are specified, once the limit for vfp is hit, then
  decrease vbp only - the resulting image will definitely be off-center, but
  there's no other way

I hope this makes sense for you as well.

Best regards,
Mateusz Kwiatkowski

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

* Re: [PATCH v2 35/41] drm/sun4i: tv: Convert to atomic hooks
  2022-08-29 13:11 ` [PATCH v2 35/41] drm/sun4i: tv: Convert to atomic hooks Maxime Ripard
@ 2022-09-06 20:02   ` Jernej Škrabec
  2022-09-07  8:35   ` (subset) " Maxime Ripard
  1 sibling, 0 replies; 128+ messages in thread
From: Jernej Škrabec @ 2022-09-06 20:02 UTC (permalink / raw)
  To: Maxime Ripard, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Samuel Holland,
	Karol Herbst, Noralf Trønnes, Emma Anholt, Daniel Vetter,
	Joonas Lahtinen, Maxime Ripard
  Cc: Maxime Ripard, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

Dne ponedeljek, 29. avgust 2022 ob 15:11:49 CEST je Maxime Ripard napisal(a):
> The sun4i TV driver still uses legacy enable and disable hook
> implementation. Let's convert to the atomic variants.
> 
> Signed-off-by: Maxime Ripard <maxime@cerno.tech>

Acked-by: Jernej Skrabec <jernej.skrabec@gmail.com>

BTW, I suggest you merge fixes/cleanups, no need to drag them in this super 
long series.

Best regards,
Jernej



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

* Re: [PATCH v2 36/41] drm/sun4i: tv: Merge mode_set into atomic_enable
  2022-08-29 13:11 ` [PATCH v2 36/41] drm/sun4i: tv: Merge mode_set into atomic_enable Maxime Ripard
@ 2022-09-06 20:04   ` Jernej Škrabec
  2022-09-07  7:41     ` Maxime Ripard
  2022-09-08 14:02   ` (subset) " Maxime Ripard
  1 sibling, 1 reply; 128+ messages in thread
From: Jernej Škrabec @ 2022-09-06 20:04 UTC (permalink / raw)
  To: Maxime Ripard, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Samuel Holland,
	Karol Herbst, Noralf Trønnes, Emma Anholt, Daniel Vetter,
	Joonas Lahtinen, Maxime Ripard
  Cc: Maxime Ripard, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

Dne ponedeljek, 29. avgust 2022 ob 15:11:50 CEST je Maxime Ripard napisal(a):
> Our mode_set implementation can be merged into our atomic_enable
> implementation to simplify things, so let's do this.

Are you sure this is a good thing in long term? What if user wants to change 
mode? Unlikely, but why not.

Best regards,
Jernej

> 
> Signed-off-by: Maxime Ripard <maxime@cerno.tech>
> 
> diff --git a/drivers/gpu/drm/sun4i/sun4i_tv.c
> b/drivers/gpu/drm/sun4i/sun4i_tv.c
> index f7aad995ab5b..3944da9a3c34 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_tv.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_tv.c
> @@ -359,23 +359,13 @@ static void sun4i_tv_enable(struct drm_encoder
> *encoder,
 {
>  	struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder);
>  	struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc);
> -
> -	DRM_DEBUG_DRIVER("Enabling the TV Output\n");
> -
> -	sunxi_engine_apply_color_correction(crtc->engine);
> -
> -	regmap_update_bits(tv->regs, SUN4I_TVE_EN_REG,
> -			   SUN4I_TVE_EN_ENABLE,
> -			   SUN4I_TVE_EN_ENABLE);
> -}
> -
> -static void sun4i_tv_mode_set(struct drm_encoder *encoder,
> -			      struct drm_display_mode *mode,
> -			      struct drm_display_mode 
*adjusted_mode)
> -{
> -	struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder);
> +	struct drm_crtc_state *crtc_state =
> +		drm_atomic_get_new_crtc_state(state, encoder->crtc);
> +	struct drm_display_mode *mode = &crtc_state->mode;
>  	const struct tv_mode *tv_mode = sun4i_tv_find_tv_by_mode(mode);
>  
> +	DRM_DEBUG_DRIVER("Enabling the TV Output\n");
> +
>  	/* Enable and map the DAC to the output */
>  	regmap_update_bits(tv->regs, SUN4I_TVE_EN_REG,
>  			   SUN4I_TVE_EN_DAC_MAP_MASK,
> @@ -468,12 +458,17 @@ static void sun4i_tv_mode_set(struct drm_encoder
> *encoder,
> SUN4I_TVE_RESYNC_FIELD : 0));
>  
>  	regmap_write(tv->regs, SUN4I_TVE_SLAVE_REG, 0);
> +
> +	sunxi_engine_apply_color_correction(crtc->engine);
> +
> +	regmap_update_bits(tv->regs, SUN4I_TVE_EN_REG,
> +			   SUN4I_TVE_EN_ENABLE,
> +			   SUN4I_TVE_EN_ENABLE);
>  }
>  
>  static const struct drm_encoder_helper_funcs sun4i_tv_helper_funcs = {
>  	.atomic_disable	= sun4i_tv_disable,
>  	.atomic_enable	= sun4i_tv_enable,
> -	.mode_set	= sun4i_tv_mode_set,
>  };
>  
>  static int sun4i_tv_comp_get_modes(struct drm_connector *connector)
> 
> -- 
> b4 0.10.0-dev-65ba7




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

* Re: [PATCH v2 37/41] drm/sun4i: tv: Remove useless function
  2022-08-29 13:11 ` [PATCH v2 37/41] drm/sun4i: tv: Remove useless function Maxime Ripard
@ 2022-09-06 20:06   ` Jernej Škrabec
  2022-09-07  8:35   ` (subset) " Maxime Ripard
  1 sibling, 0 replies; 128+ messages in thread
From: Jernej Škrabec @ 2022-09-06 20:06 UTC (permalink / raw)
  To: Maxime Ripard, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Samuel Holland,
	Karol Herbst, Noralf Trønnes, Emma Anholt, Daniel Vetter,
	Joonas Lahtinen, Maxime Ripard
  Cc: Maxime Ripard, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

Dne ponedeljek, 29. avgust 2022 ob 15:11:51 CEST je Maxime Ripard napisal(a):
> The drm_connector_to_sun4i_tv() function isn't used anywhere in the driver,
> so let's remove it.
> 
> Signed-off-by: Maxime Ripard <maxime@cerno.tech>

Acked-by: Jernej Skrabec <jernej.skrabec@gmail.com>

Best regards,
Jernej



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

* Re: [PATCH v2 36/41] drm/sun4i: tv: Merge mode_set into atomic_enable
  2022-09-06 20:04   ` Jernej Škrabec
@ 2022-09-07  7:41     ` Maxime Ripard
  2022-09-07 15:09       ` Jernej Škrabec
  0 siblings, 1 reply; 128+ messages in thread
From: Maxime Ripard @ 2022-09-07  7:41 UTC (permalink / raw)
  To: Jernej Škrabec
  Cc: Ben Skeggs, David Airlie, Chen-Yu Tsai, Thomas Zimmermann,
	Jani Nikula, Lyude Paul, Philipp Zabel, Maarten Lankhorst,
	Rodrigo Vivi, Tvrtko Ursulin, Samuel Holland, Karol Herbst,
	Noralf Trønnes, Emma Anholt, Daniel Vetter, Joonas Lahtinen,
	Hans de Goede, linux-arm-kernel, Phil Elwell, intel-gfx,
	Dave Stevenson, dri-devel, Dom Cobley, linux-kernel, nouveau,
	linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

[-- Attachment #1: Type: text/plain, Size: 901 bytes --]

On Tue, Sep 06, 2022 at 10:04:32PM +0200, Jernej Škrabec wrote:
> Dne ponedeljek, 29. avgust 2022 ob 15:11:50 CEST je Maxime Ripard napisal(a):
> > Our mode_set implementation can be merged into our atomic_enable
> > implementation to simplify things, so let's do this.
> 
> Are you sure this is a good thing in long term? What if user wants to change 
> mode? Unlikely, but why not.

It doesn't change anything feature-wise: whenever the mode is changed on
the CRTC, the encoder is going to be disabled and enabled.

It's disabled here:
https://elixir.bootlin.com/linux/latest/source/drivers/gpu/drm/drm_atomic_helper.c#L1064

And enabled here:
https://elixir.bootlin.com/linux/latest/source/drivers/gpu/drm/drm_atomic_helper.c#L1403

With drm_atomic_crtc_needs_modeset() being defined here:
https://elixir.bootlin.com/linux/latest/source/include/drm/drm_atomic.h#L1049

Maxime

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

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

* Re: (subset) [PATCH v2 24/41] drm/vc4: vec: Remove empty mode_fixup
  2022-08-29 13:11 ` [PATCH v2 24/41] drm/vc4: vec: Remove empty mode_fixup Maxime Ripard
  2022-08-30 15:23   ` Noralf Trønnes
@ 2022-09-07  8:34   ` Maxime Ripard
  1 sibling, 0 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-09-07  8:34 UTC (permalink / raw)
  To: David Airlie, Samuel Holland, Daniel Vetter, Chen-Yu Tsai,
	Maxime Ripard, Philipp Zabel, Jani Nikula, Ben Skeggs,
	Joonas Lahtinen, Emma Anholt, Noralf Trønnes, Rodrigo Vivi,
	Lyude Paul, Karol Herbst, Thomas Zimmermann, Tvrtko Ursulin,
	Maarten Lankhorst, Jernej Skrabec, Maxime Ripard
  Cc: Dom Cobley, Dave Stevenson, Hans de Goede, intel-gfx,
	Phil Elwell, linux-sunxi, dri-devel, linux-kernel,
	linux-arm-kernel, Mateusz Kwiatkowski, Geert Uytterhoeven,
	nouveau

On Mon, 29 Aug 2022 15:11:38 +0200, Maxime Ripard wrote:
> The mode_fixup hooks are deprecated, and the behaviour we implement is the
> default one anyway. Let's remove it.
> 
> 

Applied to drm/drm-misc (drm-misc-next).

Thanks!
Maxime

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

* Re: (subset) [PATCH v2 25/41] drm/vc4: vec: Convert to atomic helpers
  2022-08-29 13:11 ` [PATCH v2 25/41] drm/vc4: vec: Convert to atomic helpers Maxime Ripard
  2022-08-30 15:24   ` Noralf Trønnes
@ 2022-09-07  8:35   ` Maxime Ripard
  1 sibling, 0 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-09-07  8:35 UTC (permalink / raw)
  To: David Airlie, Samuel Holland, Daniel Vetter, Chen-Yu Tsai,
	Maxime Ripard, Philipp Zabel, Jani Nikula, Ben Skeggs,
	Joonas Lahtinen, Emma Anholt, Noralf Trønnes, Rodrigo Vivi,
	Lyude Paul, Karol Herbst, Maarten Lankhorst, Thomas Zimmermann,
	Tvrtko Ursulin, Jernej Skrabec, Maxime Ripard
  Cc: Dom Cobley, Dave Stevenson, Hans de Goede, intel-gfx,
	Phil Elwell, dri-devel, linux-sunxi, linux-kernel,
	linux-arm-kernel, Mateusz Kwiatkowski, Geert Uytterhoeven,
	nouveau

On Mon, 29 Aug 2022 15:11:39 +0200, Maxime Ripard wrote:
> The VC4 VEC driver still uses legacy enable and disable hook
> implementation. Let's convert to the atomic variants.
> 
> 

Applied to drm/drm-misc (drm-misc-next).

Thanks!
Maxime

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

* Re: (subset) [PATCH v2 26/41] drm/vc4: vec: Refactor VEC TV mode setting
  2022-08-29 13:11 ` [PATCH v2 26/41] drm/vc4: vec: Refactor VEC TV mode setting Maxime Ripard
  2022-08-30 15:29   ` Noralf Trønnes
@ 2022-09-07  8:35   ` Maxime Ripard
  1 sibling, 0 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-09-07  8:35 UTC (permalink / raw)
  To: David Airlie, Samuel Holland, Daniel Vetter, Chen-Yu Tsai,
	Maxime Ripard, Philipp Zabel, Jani Nikula, Ben Skeggs,
	Joonas Lahtinen, Noralf Trønnes, Emma Anholt, Rodrigo Vivi,
	Lyude Paul, Karol Herbst, Maarten Lankhorst, Thomas Zimmermann,
	Tvrtko Ursulin, Jernej Skrabec, Maxime Ripard
  Cc: Dom Cobley, Hans de Goede, Dave Stevenson, intel-gfx,
	Phil Elwell, dri-devel, linux-sunxi, linux-kernel,
	linux-arm-kernel, Mateusz Kwiatkowski, Geert Uytterhoeven,
	nouveau

On Mon, 29 Aug 2022 15:11:40 +0200, Maxime Ripard wrote:
> From: Mateusz Kwiatkowski <kfyatek+publicgit@gmail.com>
> 
> Change the mode_set function pointer logic to declarative config0,
> config1 and custom_freq fields, to make TV mode setting logic more
> concise and uniform.
> 
> 
> [...]

Applied to drm/drm-misc (drm-misc-next).

Thanks!
Maxime

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

* Re: (subset) [PATCH v2 27/41] drm/vc4: vec: Remove redundant atomic_mode_set
  2022-08-29 13:11 ` [PATCH v2 27/41] drm/vc4: vec: Remove redundant atomic_mode_set Maxime Ripard
  2022-08-30 15:45   ` Noralf Trønnes
@ 2022-09-07  8:35   ` Maxime Ripard
  1 sibling, 0 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-09-07  8:35 UTC (permalink / raw)
  To: David Airlie, Samuel Holland, Daniel Vetter, Chen-Yu Tsai,
	Maxime Ripard, Philipp Zabel, Jani Nikula, Ben Skeggs,
	Joonas Lahtinen, Noralf Trønnes, Emma Anholt, Rodrigo Vivi,
	Lyude Paul, Karol Herbst, Thomas Zimmermann, Tvrtko Ursulin,
	Maarten Lankhorst, Jernej Skrabec, Maxime Ripard
  Cc: Dom Cobley, Hans de Goede, Dave Stevenson, intel-gfx,
	Phil Elwell, linux-sunxi, dri-devel, linux-kernel,
	linux-arm-kernel, Mateusz Kwiatkowski, Geert Uytterhoeven,
	nouveau

On Mon, 29 Aug 2022 15:11:41 +0200, Maxime Ripard wrote:
> From: Mateusz Kwiatkowski <kfyatek+publicgit@gmail.com>
> 
> Let's remove the superfluous tv_mode field, which was redundant with the
> mode field in struct drm_tv_connector_state.
> 
> 

Applied to drm/drm-misc (drm-misc-next).

Thanks!
Maxime

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

* Re: (subset) [PATCH v2 28/41] drm/vc4: vec: Fix timings for VEC modes
  2022-08-29 13:11 ` [PATCH v2 28/41] drm/vc4: vec: Fix timings for VEC modes Maxime Ripard
  2022-08-30 18:20   ` Noralf Trønnes
@ 2022-09-07  8:35   ` Maxime Ripard
  1 sibling, 0 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-09-07  8:35 UTC (permalink / raw)
  To: David Airlie, Samuel Holland, Daniel Vetter, Chen-Yu Tsai,
	Maxime Ripard, Philipp Zabel, Jani Nikula, Ben Skeggs,
	Joonas Lahtinen, Noralf Trønnes, Emma Anholt, Rodrigo Vivi,
	Lyude Paul, Karol Herbst, Maarten Lankhorst, Thomas Zimmermann,
	Tvrtko Ursulin, Jernej Skrabec, Maxime Ripard
  Cc: Hans de Goede, Dave Stevenson, Dom Cobley, intel-gfx,
	Phil Elwell, linux-sunxi, dri-devel, linux-kernel,
	linux-arm-kernel, Mateusz Kwiatkowski, Geert Uytterhoeven,
	nouveau

On Mon, 29 Aug 2022 15:11:42 +0200, Maxime Ripard wrote:
> From: Mateusz Kwiatkowski <kfyatek+publicgit@gmail.com>
> 
> This commit fixes vertical timings of the VEC (composite output) modes
> to accurately represent the 525-line ("NTSC") and 625-line ("PAL") ITU-R
> standards.
> 
> Previous timings were actually defined as 502 and 601 lines, resulting
> in non-standard 62.69 Hz and 52 Hz signals being generated,
> respectively.
> 
> [...]

Applied to drm/drm-misc (drm-misc-next).

Thanks!
Maxime

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

* Re: (subset) [PATCH v2 34/41] drm/sun4i: tv: Remove unused mode_valid
  2022-08-29 13:11 ` [PATCH v2 34/41] drm/sun4i: tv: Remove unused mode_valid Maxime Ripard
@ 2022-09-07  8:35   ` Maxime Ripard
  0 siblings, 0 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-09-07  8:35 UTC (permalink / raw)
  To: David Airlie, Samuel Holland, Daniel Vetter, Chen-Yu Tsai,
	Maxime Ripard, Philipp Zabel, Jani Nikula, Ben Skeggs,
	Joonas Lahtinen, Emma Anholt, Noralf Trønnes, Rodrigo Vivi,
	Lyude Paul, Karol Herbst, Thomas Zimmermann, Tvrtko Ursulin,
	Maarten Lankhorst, Jernej Skrabec, Maxime Ripard
  Cc: Dom Cobley, Hans de Goede, Dave Stevenson, intel-gfx,
	Phil Elwell, dri-devel, linux-sunxi, linux-kernel,
	linux-arm-kernel, Mateusz Kwiatkowski, Geert Uytterhoeven,
	nouveau

On Mon, 29 Aug 2022 15:11:48 +0200, Maxime Ripard wrote:
> The mode_valid implementation is pretty much a nop, let's remove it.
> 
> 

Applied to drm/drm-misc (drm-misc-next).

Thanks!
Maxime

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

* Re: (subset) [PATCH v2 35/41] drm/sun4i: tv: Convert to atomic hooks
  2022-08-29 13:11 ` [PATCH v2 35/41] drm/sun4i: tv: Convert to atomic hooks Maxime Ripard
  2022-09-06 20:02   ` Jernej Škrabec
@ 2022-09-07  8:35   ` Maxime Ripard
  1 sibling, 0 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-09-07  8:35 UTC (permalink / raw)
  To: David Airlie, Samuel Holland, Daniel Vetter, Chen-Yu Tsai,
	Maxime Ripard, Philipp Zabel, Jani Nikula, Ben Skeggs,
	Joonas Lahtinen, Noralf Trønnes, Emma Anholt, Rodrigo Vivi,
	Lyude Paul, Karol Herbst, Thomas Zimmermann, Tvrtko Ursulin,
	Maarten Lankhorst, Jernej Skrabec, Maxime Ripard
  Cc: Hans de Goede, Dom Cobley, Dave Stevenson, intel-gfx,
	Phil Elwell, dri-devel, linux-sunxi, linux-kernel,
	linux-arm-kernel, Mateusz Kwiatkowski, Geert Uytterhoeven,
	nouveau

On Mon, 29 Aug 2022 15:11:49 +0200, Maxime Ripard wrote:
> The sun4i TV driver still uses legacy enable and disable hook
> implementation. Let's convert to the atomic variants.
> 
> 

Applied to drm/drm-misc (drm-misc-next).

Thanks!
Maxime

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

* Re: (subset) [PATCH v2 37/41] drm/sun4i: tv: Remove useless function
  2022-08-29 13:11 ` [PATCH v2 37/41] drm/sun4i: tv: Remove useless function Maxime Ripard
  2022-09-06 20:06   ` Jernej Škrabec
@ 2022-09-07  8:35   ` Maxime Ripard
  1 sibling, 0 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-09-07  8:35 UTC (permalink / raw)
  To: David Airlie, Samuel Holland, Daniel Vetter, Chen-Yu Tsai,
	Maxime Ripard, Philipp Zabel, Jani Nikula, Ben Skeggs,
	Joonas Lahtinen, Noralf Trønnes, Emma Anholt, Rodrigo Vivi,
	Lyude Paul, Karol Herbst, Maarten Lankhorst, Thomas Zimmermann,
	Tvrtko Ursulin, Jernej Skrabec, Maxime Ripard
  Cc: Hans de Goede, Dave Stevenson, Dom Cobley, intel-gfx,
	Phil Elwell, linux-sunxi, dri-devel, linux-kernel,
	linux-arm-kernel, Mateusz Kwiatkowski, Geert Uytterhoeven,
	nouveau

On Mon, 29 Aug 2022 15:11:51 +0200, Maxime Ripard wrote:
> The drm_connector_to_sun4i_tv() function isn't used anywhere in the driver,
> so let's remove it.
> 
> 

Applied to drm/drm-misc (drm-misc-next).

Thanks!
Maxime

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

* Re: (subset) [PATCH v2 38/41] drm/sun4i: tv: Remove useless destroy function
  2022-08-29 13:11 ` [PATCH v2 38/41] drm/sun4i: tv: Remove useless destroy function Maxime Ripard
@ 2022-09-07  8:35   ` Maxime Ripard
  0 siblings, 0 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-09-07  8:35 UTC (permalink / raw)
  To: David Airlie, Samuel Holland, Daniel Vetter, Chen-Yu Tsai,
	Maxime Ripard, Philipp Zabel, Jani Nikula, Ben Skeggs,
	Joonas Lahtinen, Emma Anholt, Noralf Trønnes, Rodrigo Vivi,
	Lyude Paul, Karol Herbst, Thomas Zimmermann, Tvrtko Ursulin,
	Maarten Lankhorst, Jernej Skrabec, Maxime Ripard
  Cc: Dom Cobley, Dave Stevenson, Hans de Goede, intel-gfx,
	Phil Elwell, dri-devel, linux-sunxi, linux-kernel,
	linux-arm-kernel, Mateusz Kwiatkowski, Geert Uytterhoeven,
	nouveau

On Mon, 29 Aug 2022 15:11:52 +0200, Maxime Ripard wrote:
> Our destroy implementation is just calling the generic helper, so let's
> just remove our function and directly use the helper.
> 
> 

Applied to drm/drm-misc (drm-misc-next).

Thanks!
Maxime

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

* Re: (subset) [PATCH v2 39/41] drm/sun4i: tv: Rename error label
  2022-08-29 13:11 ` [PATCH v2 39/41] drm/sun4i: tv: Rename error label Maxime Ripard
@ 2022-09-07  8:35   ` Maxime Ripard
  0 siblings, 0 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-09-07  8:35 UTC (permalink / raw)
  To: David Airlie, Samuel Holland, Daniel Vetter, Chen-Yu Tsai,
	Maxime Ripard, Philipp Zabel, Jani Nikula, Ben Skeggs,
	Joonas Lahtinen, Emma Anholt, Noralf Trønnes, Rodrigo Vivi,
	Lyude Paul, Karol Herbst, Maarten Lankhorst, Tvrtko Ursulin,
	Thomas Zimmermann, Jernej Skrabec, Maxime Ripard
  Cc: Dom Cobley, Dave Stevenson, Hans de Goede, intel-gfx,
	Phil Elwell, linux-sunxi, dri-devel, linux-kernel,
	linux-arm-kernel, Mateusz Kwiatkowski, Geert Uytterhoeven,
	nouveau

On Mon, 29 Aug 2022 15:11:53 +0200, Maxime Ripard wrote:
> The other error labels in sun4i_tv_bind() are named after the task they
> perform (err_disable_clk to call clk_disable_unprepare for example).
> 
> However, the err_cleanup_connector is named after the calling site
> (drm_connector_init failing) and will actually cleanup the encoder. Let's
> rename it to err_cleanup_encoder to be consistent.
> 
> [...]

Applied to drm/drm-misc (drm-misc-next).

Thanks!
Maxime

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

* Re: (subset) [PATCH v2 40/41] drm/sun4i: tv: Add missing reset assertion
  2022-08-29 13:11 ` [PATCH v2 40/41] drm/sun4i: tv: Add missing reset assertion Maxime Ripard
@ 2022-09-07  8:35   ` Maxime Ripard
  0 siblings, 0 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-09-07  8:35 UTC (permalink / raw)
  To: David Airlie, Samuel Holland, Daniel Vetter, Chen-Yu Tsai,
	Maxime Ripard, Philipp Zabel, Jani Nikula, Ben Skeggs,
	Joonas Lahtinen, Noralf Trønnes, Emma Anholt, Rodrigo Vivi,
	Lyude Paul, Karol Herbst, Maarten Lankhorst, Thomas Zimmermann,
	Tvrtko Ursulin, Jernej Skrabec, Maxime Ripard
  Cc: Dom Cobley, Dave Stevenson, Hans de Goede, intel-gfx,
	Phil Elwell, linux-sunxi, dri-devel, linux-kernel,
	linux-arm-kernel, Mateusz Kwiatkowski, Geert Uytterhoeven,
	nouveau

On Mon, 29 Aug 2022 15:11:54 +0200, Maxime Ripard wrote:
> The reset line is deasserted at bind, and asserted if we ever encounter an
> error there. However, it's never asserted in unbind which will lead to a
> resource unbalance.
> 
> 

Applied to drm/drm-misc (drm-misc-next).

Thanks!
Maxime

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

* Re: [PATCH v2 14/41] drm/modes: Move named modes parsing to a separate function
  2022-08-30 13:36         ` Jani Nikula
@ 2022-09-07  8:39           ` Maxime Ripard
  0 siblings, 0 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-09-07  8:39 UTC (permalink / raw)
  To: Jani Nikula
  Cc: Geert Uytterhoeven, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Lyude Paul, Philipp Zabel, Maarten Lankhorst,
	Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec, Samuel Holland,
	Karol Herbst, Noralf Trønnes, Emma Anholt, Daniel Vetter,
	Joonas Lahtinen, Hans de Goede, Linux ARM, Phil Elwell,
	Intel Graphics Development, Dave Stevenson, DRI Development,
	Dom Cobley, Linux Kernel Mailing List, Nouveau Dev, linux-sunxi,
	Mateusz Kwiatkowski

[-- Attachment #1: Type: text/plain, Size: 2480 bytes --]

Hi,

On Tue, Aug 30, 2022 at 04:36:23PM +0300, Jani Nikula wrote:
> On Tue, 30 Aug 2022, Maxime Ripard <maxime@cerno.tech> wrote:
> > Hi,
> >
> > On Tue, Aug 30, 2022 at 01:43:07PM +0300, Jani Nikula wrote:
> >> On Tue, 30 Aug 2022, Geert Uytterhoeven <geert@linux-m68k.org> wrote:
> >> > On Mon, Aug 29, 2022 at 3:13 PM Maxime Ripard <maxime@cerno.tech> wrote:
> >> >> +#define STR_STRICT_EQ(str, len, cmp) \
> >> >> +       ((strlen(cmp) == len) && !strncmp(str, cmp, len))
> >> >
> >> > This is not part of the move, but newly added.
> >> 
> >> The same construct is also duplicated elsewhere in the series, and I
> >> kept being confused by it.
> >
> > I'm not sure what is confusing, but I can add a comment if needed.
> 
> STR_STRICT_EQ() is what's confusing. I have to look at the
> implementation to understand what it means. What does "strict" string
> equality mean?

Same length, same sequence of characters

> >
> >> The above is precisely the same as:
> >> 
> >> 	str_has_prefix(str, cmp) == len
> >
> > Here, it's used to make sure we don't have a named mode starting with
> > either e, d, or D.
> >
> > If I understood str_has_prefix() right, str_has_prefix("DUMB-MODE", "D")
> > == strlen("DUMB-MODE") would return true, while it's actually what we
> > want to avoid.
> 
> That's not true, str_has_prefix("DUMB-MODE", "D") == strlen("D") is.
> 
> > It's also used indeed in drm_get_tv_mode_from_name(), where we try to
> > match a list of names with one passed as argument.
> >
> > With drm_get_tv_mode_from_name("NSTC", strlen("NTSC")), we would end up
> > calling str_has_prefix("NTSC-J", "NTSC") == strlen("NTSC-J") which would
> > work. However, we end up calling prefix not a prefix, but an entire
> > string we want to match against, which is very confusing to me too.
> 
> If I get this right, you have a string and you want to check if that has
> a certain prefix. Additionally, you want to check the prefix is a
> certain length.
> 
> Sure, that the prefix is a certain length is more of a property of the
> string, which is NUL terminated later than at length, but that's doesn't
> really matter.
> 
> That condition is simply str_has_prefix(string, prefix) == length.

Ack. I'm ok with the implementation being done that way, but I'd really
prefer to still have some macro to make the name less confusing. Would
that work for you? What name would be better in your opinion?

Thanks!
Maxime

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

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

* Re: [PATCH v2 00/41] drm: Analog TV Improvements
  2022-09-05 15:17       ` Noralf Trønnes
@ 2022-09-07  9:58         ` Maxime Ripard
  2022-09-07 10:56           ` Noralf Trønnes
  0 siblings, 1 reply; 128+ messages in thread
From: Maxime Ripard @ 2022-09-07  9:58 UTC (permalink / raw)
  To: Noralf Trønnes
  Cc: Ben Skeggs, David Airlie, Chen-Yu Tsai, Thomas Zimmermann,
	Jani Nikula, Lyude Paul, Philipp Zabel, Maarten Lankhorst,
	Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec, Samuel Holland,
	Karol Herbst, Emma Anholt, Daniel Vetter, Joonas Lahtinen,
	Dom Cobley, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, linux-kernel, nouveau,
	linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

[-- Attachment #1: Type: text/plain, Size: 2460 bytes --]

On Mon, Sep 05, 2022 at 05:17:18PM +0200, Noralf Trønnes wrote:
> Den 05.09.2022 16.57, skrev Maxime Ripard:
> > On Fri, Sep 02, 2022 at 01:28:16PM +0200, Noralf Trønnes wrote:
> >>
> >>
> >> Den 01.09.2022 21.35, skrev Noralf Trønnes:
> >>>
> >>>
> >>> I have finally found a workaround for my kernel hangs.
> >>>
> >>> Dom had a look at my kernel and found that the VideoCore was fine, and
> >>> he said this:
> >>>
> >>>> That suggests cause of lockup was on arm side rather than VC side.
> >>>>
> >>>> But it's hard to diagnose further. Once you've had a peripheral not
> >>>> respond, the AXI bus locks up and no further operations are possible.
> >>>> Usual causes of this are required clocks being stopped or domains
> >>>> disabled and then trying to access the hardware.
> >>>>
> >>>
> >>> So when I got this on my 64-bit build:
> >>>
> >>> [  166.702171] SError Interrupt on CPU1, code 0x00000000bf000002 -- SError
> >>> [  166.702187] CPU: 1 PID: 8 Comm: kworker/u8:0 Tainted: G        W
> >>>     5.19.0-rc6-00096-gba7973977976-dirty #1
> >>> [  166.702200] Hardware name: Raspberry Pi 4 Model B Rev 1.1 (DT)
> >>> [  166.702206] Workqueue: events_freezable_power_ thermal_zone_device_check
> >>> [  166.702231] pstate: 200000c5 (nzCv daIF -PAN -UAO -TCO -DIT -SSBS
> >>> BTYPE=--)
> >>> [  166.702242] pc : regmap_mmio_read32le+0x10/0x28
> >>> [  166.702261] lr : regmap_mmio_read+0x44/0x70
> >>> ...
> >>> [  166.702606]  bcm2711_get_temp+0x58/0xb0 [bcm2711_thermal]
> >>>
> >>> I wondered if that reg read was stalled due to a clock being stopped.
> >>>
> >>> Lo and behold, disabling runtime pm and keeping the vec clock running
> >>> all the time fixed it[1].
> >>>
> >>> I don't know what the problem is, but at least I can now test this patchset.
> >>>
> >>> [1] https://gist.github.com/notro/23b984e7fa05cfbda2db50a421cac065
> >>>
> >>
> >> It turns out I didn't have to disable runtime pm:
> >> https://gist.github.com/notro/0adcfcb12460b54e54458afe11dc8ea2
> > 
> > If the bcm2711_thermal IP needs that clock to be enabled, it should grab
> > a reference itself, but it looks like even the device tree binding
> > doesn't ask for one.
> > 
> 
> The first thing I tried was to unload the bcm2711_thermal module before
> running modeset and it still hung, so I don't think that's the problem.

Ack. Just to confirm, is this happening on mainline or on the downstream tree?

Maxime

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

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

* Re: [PATCH v2 00/41] drm: Analog TV Improvements
  2022-09-05 14:57     ` Maxime Ripard
  2022-09-05 15:17       ` Noralf Trønnes
@ 2022-09-07 10:36       ` Stefan Wahren
  2022-09-07 16:44         ` Noralf Trønnes
  1 sibling, 1 reply; 128+ messages in thread
From: Stefan Wahren @ 2022-09-07 10:36 UTC (permalink / raw)
  To: Maxime Ripard, Noralf Trønnes
  Cc: Ben Skeggs, David Airlie, Chen-Yu Tsai, Thomas Zimmermann,
	Jani Nikula, Lyude Paul, Philipp Zabel, Maarten Lankhorst,
	Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec, Samuel Holland,
	Karol Herbst, Emma Anholt, Daniel Vetter, Joonas Lahtinen,
	Dom Cobley, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, linux-kernel, nouveau,
	linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

Hi Maxime,

Am 05.09.22 um 16:57 schrieb Maxime Ripard:
> On Fri, Sep 02, 2022 at 01:28:16PM +0200, Noralf Trønnes wrote:
>>
>> Den 01.09.2022 21.35, skrev Noralf Trønnes:
>>>
>>> I have finally found a workaround for my kernel hangs.
>>>
>>> Dom had a look at my kernel and found that the VideoCore was fine, and
>>> he said this:
>>>
>>>> That suggests cause of lockup was on arm side rather than VC side.
>>>>
>>>> But it's hard to diagnose further. Once you've had a peripheral not
>>>> respond, the AXI bus locks up and no further operations are possible.
>>>> Usual causes of this are required clocks being stopped or domains
>>>> disabled and then trying to access the hardware.
>>>>
>>> So when I got this on my 64-bit build:
>>>
>>> [  166.702171] SError Interrupt on CPU1, code 0x00000000bf000002 -- SError
>>> [  166.702187] CPU: 1 PID: 8 Comm: kworker/u8:0 Tainted: G        W
>>>      5.19.0-rc6-00096-gba7973977976-dirty #1
>>> [  166.702200] Hardware name: Raspberry Pi 4 Model B Rev 1.1 (DT)
>>> [  166.702206] Workqueue: events_freezable_power_ thermal_zone_device_check
>>> [  166.702231] pstate: 200000c5 (nzCv daIF -PAN -UAO -TCO -DIT -SSBS
>>> BTYPE=--)
>>> [  166.702242] pc : regmap_mmio_read32le+0x10/0x28
>>> [  166.702261] lr : regmap_mmio_read+0x44/0x70
>>> ...
>>> [  166.702606]  bcm2711_get_temp+0x58/0xb0 [bcm2711_thermal]
>>>
>>> I wondered if that reg read was stalled due to a clock being stopped.
>>>
>>> Lo and behold, disabling runtime pm and keeping the vec clock running
>>> all the time fixed it[1].
>>>
>>> I don't know what the problem is, but at least I can now test this patchset.
>>>
>>> [1] https://gist.github.com/notro/23b984e7fa05cfbda2db50a421cac065
>>>
>> It turns out I didn't have to disable runtime pm:
>> https://gist.github.com/notro/0adcfcb12460b54e54458afe11dc8ea2
> If the bcm2711_thermal IP needs that clock to be enabled, it should grab
> a reference itself, but it looks like even the device tree binding
> doesn't ask for one.
The missing clock in the device tree binding is expected, because 
despite of the code there is not much information about the BCM2711 
clock tree. But i'm skeptical that the AVS IP actually needs the VEC 
clock, i think it's more likely that the VEC clock parent is changed and 
that cause this issue. I could take care of the bcm2711 binding & driver 
if i know which clock is really necessary.
>
> Maxime
>
> _______________________________________________
> 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] 128+ messages in thread

* Re: [PATCH v2 00/41] drm: Analog TV Improvements
  2022-09-07  9:58         ` Maxime Ripard
@ 2022-09-07 10:56           ` Noralf Trønnes
  0 siblings, 0 replies; 128+ messages in thread
From: Noralf Trønnes @ 2022-09-07 10:56 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Ben Skeggs, David Airlie, Chen-Yu Tsai, Thomas Zimmermann,
	Jani Nikula, Lyude Paul, Philipp Zabel, Maarten Lankhorst,
	Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec, Samuel Holland,
	Karol Herbst, Emma Anholt, Daniel Vetter, Joonas Lahtinen,
	Dom Cobley, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, linux-kernel, nouveau,
	linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven,
	Noralf Trønnes



Den 07.09.2022 11.58, skrev Maxime Ripard:
> On Mon, Sep 05, 2022 at 05:17:18PM +0200, Noralf Trønnes wrote:
>> Den 05.09.2022 16.57, skrev Maxime Ripard:
>>> On Fri, Sep 02, 2022 at 01:28:16PM +0200, Noralf Trønnes wrote:
>>>>
>>>>
>>>> Den 01.09.2022 21.35, skrev Noralf Trønnes:
>>>>>
>>>>>
>>>>> I have finally found a workaround for my kernel hangs.
>>>>>
>>>>> Dom had a look at my kernel and found that the VideoCore was fine, and
>>>>> he said this:
>>>>>
>>>>>> That suggests cause of lockup was on arm side rather than VC side.
>>>>>>
>>>>>> But it's hard to diagnose further. Once you've had a peripheral not
>>>>>> respond, the AXI bus locks up and no further operations are possible.
>>>>>> Usual causes of this are required clocks being stopped or domains
>>>>>> disabled and then trying to access the hardware.
>>>>>>
>>>>>
>>>>> So when I got this on my 64-bit build:
>>>>>
>>>>> [  166.702171] SError Interrupt on CPU1, code 0x00000000bf000002 -- SError
>>>>> [  166.702187] CPU: 1 PID: 8 Comm: kworker/u8:0 Tainted: G        W
>>>>>     5.19.0-rc6-00096-gba7973977976-dirty #1
>>>>> [  166.702200] Hardware name: Raspberry Pi 4 Model B Rev 1.1 (DT)
>>>>> [  166.702206] Workqueue: events_freezable_power_ thermal_zone_device_check
>>>>> [  166.702231] pstate: 200000c5 (nzCv daIF -PAN -UAO -TCO -DIT -SSBS
>>>>> BTYPE=--)
>>>>> [  166.702242] pc : regmap_mmio_read32le+0x10/0x28
>>>>> [  166.702261] lr : regmap_mmio_read+0x44/0x70
>>>>> ...
>>>>> [  166.702606]  bcm2711_get_temp+0x58/0xb0 [bcm2711_thermal]
>>>>>
>>>>> I wondered if that reg read was stalled due to a clock being stopped.
>>>>>
>>>>> Lo and behold, disabling runtime pm and keeping the vec clock running
>>>>> all the time fixed it[1].
>>>>>
>>>>> I don't know what the problem is, but at least I can now test this patchset.
>>>>>
>>>>> [1] https://gist.github.com/notro/23b984e7fa05cfbda2db50a421cac065
>>>>>
>>>>
>>>> It turns out I didn't have to disable runtime pm:
>>>> https://gist.github.com/notro/0adcfcb12460b54e54458afe11dc8ea2
>>>
>>> If the bcm2711_thermal IP needs that clock to be enabled, it should grab
>>> a reference itself, but it looks like even the device tree binding
>>> doesn't ask for one.
>>>
>>
>> The first thing I tried was to unload the bcm2711_thermal module before
>> running modeset and it still hung, so I don't think that's the problem.
> 
> Ack. Just to confirm, is this happening on mainline or on the downstream tree?
> 

It's mainline.

Noralf.

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

* Re: [PATCH v2 09/41] drm/connector: Add TV standard property
  2022-09-01 22:00   ` Mateusz Kwiatkowski
  2022-09-02  7:35     ` Geert Uytterhoeven
@ 2022-09-07 12:10     ` Maxime Ripard
  2022-09-07 19:52       ` Mateusz Kwiatkowski
  1 sibling, 1 reply; 128+ messages in thread
From: Maxime Ripard @ 2022-09-07 12:10 UTC (permalink / raw)
  To: Mateusz Kwiatkowski
  Cc: Ben Skeggs, David Airlie, Chen-Yu Tsai, Thomas Zimmermann,
	Jani Nikula, Lyude Paul, Philipp Zabel, Maarten Lankhorst,
	Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec, Samuel Holland,
	Karol Herbst, Noralf Trønnes, Emma Anholt, Daniel Vetter,
	Joonas Lahtinen, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Geert Uytterhoeven

[-- Attachment #1: Type: text/plain, Size: 3830 bytes --]

Hi,

On Fri, Sep 02, 2022 at 12:00:33AM +0200, Mateusz Kwiatkowski wrote:
> W dniu 29.08.2022 o 15:11, Maxime Ripard pisze:
> > The TV mode property has been around for a while now to select and get the
> > current TV mode output on an analog TV connector.
> >
> > Despite that property name being generic, its content isn't and has been
> > driver-specific which makes it hard to build any generic behaviour on top
> > of it, both in kernel and user-space.
> >
> > Let's create a new bitmask tv norm property, that can contain any of the
> > analog TV standards currently supported by kernel drivers. Each driver can
> > then pass in a bitmask of the modes it supports.
> 
> This is not a bitmask property anymore, you've just changed it to an enum.
> The commit message is now misleading.
> 
> > +static const struct drm_prop_enum_list drm_tv_mode_enum_list[] = {
> > +    { DRM_MODE_TV_MODE_NTSC_443, "NTSC-443" },
> > +    { DRM_MODE_TV_MODE_NTSC_J, "NTSC-J" },
> > +    { DRM_MODE_TV_MODE_NTSC_M, "NTSC-M" },
> > +    { DRM_MODE_TV_MODE_PAL_60, "PAL-60" },
> > +    { DRM_MODE_TV_MODE_PAL_B, "PAL-B" },
> > +    { DRM_MODE_TV_MODE_PAL_D, "PAL-D" },
> > +    { DRM_MODE_TV_MODE_PAL_G, "PAL-G" },
> > +    { DRM_MODE_TV_MODE_PAL_H, "PAL-H" },
> > +    { DRM_MODE_TV_MODE_PAL_I, "PAL-I" },
> > +    { DRM_MODE_TV_MODE_PAL_M, "PAL-M" },
> > +    { DRM_MODE_TV_MODE_PAL_N, "PAL-N" },
> > +    { DRM_MODE_TV_MODE_PAL_NC, "PAL-Nc" },
> > +    { DRM_MODE_TV_MODE_SECAM_60, "SECAM-60" },
> > +    { DRM_MODE_TV_MODE_SECAM_B, "SECAM-B" },
> > +    { DRM_MODE_TV_MODE_SECAM_D, "SECAM-D" },
> > +    { DRM_MODE_TV_MODE_SECAM_G, "SECAM-G" },
> > +    { DRM_MODE_TV_MODE_SECAM_K, "SECAM-K" },
> > +    { DRM_MODE_TV_MODE_SECAM_K1, "SECAM-K1" },
> > +    { DRM_MODE_TV_MODE_SECAM_L, "SECAM-L" },
> > +};
> 
> I did not comment on it the last time, but this list looks a little bit random.
> 
> Compared to the standards defined by V4L2, you also define SECAM-60 (a good
> thing to define, because why not), but don't define PAL-B1, PAL-D1, PAL-K,
> SECAM-H, SECAM-LC (whatever that is - probably just another name for SECAM-L,
> see my comment about PAL-Nc below), or NTSC-M-KR (a Korean variant of NTSC).
> 
> Like I mentioned previously, I'm personally not a fan of including all those
> CCIR/ITU system variants, as they don't mean any difference to the output unless
> there is an RF modulator involved. But I get it that they have already been used
> and regressing probably wouldn't be a very good idea. But in that case keeping
> it consistent with the set of values used by V4L2 would be wise, I think.

Ack. What would be the list of standards we'd absolutely need? NSTC-M,
NTSC-J, PAL-60, PAL-B, PAL-M, SECAM-60 and SECAM-B?

> > +/**
> > + * drm_mode_create_tv_properties - create TV specific connector properties
> > + * @dev: DRM device
> > + * @supported_tv_modes: Bitmask of TV modes supported (See DRM_MODE_TV_MODE_*)
> > +
> > + * Called by a driver's TV initialization routine, this function creates
> > + * the TV specific connector properties for a given device.  Caller is
> > + * responsible for allocating a list of format names and passing them to
> > + * this routine.
> > + *
> > + * Returns:
> > + * 0 on success or a negative error code on failure.
> > + */
> > +int drm_mode_create_tv_properties(struct drm_device *dev,
> > +                  unsigned int supported_tv_modes)
> 
> supported_tv_modes is supposed to be a bitmask of BIT(DRM_MODE_TV_MODE_*)
> (or (1<<DRM_MODE_TV_MODE_*)) rather than DRM_MODE_TV_MODE_* directly, but this
> is not said explicitly anywhere in this doc comment.

The argument doc mentions that it's a "Bitmask of TV modes supported
(See DRM_MODE_TV_MODE_*)", how would you improve it?

Thanks!
Maxime

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

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

* Re: [PATCH v2 09/41] drm/connector: Add TV standard property
  2022-09-02  7:35     ` Geert Uytterhoeven
@ 2022-09-07 12:11       ` Maxime Ripard
  0 siblings, 0 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-09-07 12:11 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: Mateusz Kwiatkowski, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec,
	Samuel Holland, Karol Herbst, Noralf Trønnes, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen, Hans de Goede, Linux ARM,
	Phil Elwell, Intel Graphics Development, Dave Stevenson,
	DRI Development, Dom Cobley, Linux Kernel Mailing List,
	Nouveau Dev, linux-sunxi

[-- Attachment #1: Type: text/plain, Size: 3758 bytes --]

On Fri, Sep 02, 2022 at 09:35:20AM +0200, Geert Uytterhoeven wrote:
> On Fri, Sep 2, 2022 at 12:00 AM Mateusz Kwiatkowski <kfyatek@gmail.com> wrote:
> > W dniu 29.08.2022 o 15:11, Maxime Ripard pisze:
> > > The TV mode property has been around for a while now to select and get the
> > > current TV mode output on an analog TV connector.
> > >
> > > Despite that property name being generic, its content isn't and has been
> > > driver-specific which makes it hard to build any generic behaviour on top
> > > of it, both in kernel and user-space.
> > >
> > > Let's create a new bitmask tv norm property, that can contain any of the
> > > analog TV standards currently supported by kernel drivers. Each driver can
> > > then pass in a bitmask of the modes it supports.
> >
> > This is not a bitmask property anymore, you've just changed it to an enum.
> > The commit message is now misleading.
> >
> > > +static const struct drm_prop_enum_list drm_tv_mode_enum_list[] = {
> > > +    { DRM_MODE_TV_MODE_NTSC_443, "NTSC-443" },
> > > +    { DRM_MODE_TV_MODE_NTSC_J, "NTSC-J" },
> > > +    { DRM_MODE_TV_MODE_NTSC_M, "NTSC-M" },
> > > +    { DRM_MODE_TV_MODE_PAL_60, "PAL-60" },
> > > +    { DRM_MODE_TV_MODE_PAL_B, "PAL-B" },
> > > +    { DRM_MODE_TV_MODE_PAL_D, "PAL-D" },
> > > +    { DRM_MODE_TV_MODE_PAL_G, "PAL-G" },
> > > +    { DRM_MODE_TV_MODE_PAL_H, "PAL-H" },
> > > +    { DRM_MODE_TV_MODE_PAL_I, "PAL-I" },
> > > +    { DRM_MODE_TV_MODE_PAL_M, "PAL-M" },
> > > +    { DRM_MODE_TV_MODE_PAL_N, "PAL-N" },
> > > +    { DRM_MODE_TV_MODE_PAL_NC, "PAL-Nc" },
> > > +    { DRM_MODE_TV_MODE_SECAM_60, "SECAM-60" },
> > > +    { DRM_MODE_TV_MODE_SECAM_B, "SECAM-B" },
> > > +    { DRM_MODE_TV_MODE_SECAM_D, "SECAM-D" },
> > > +    { DRM_MODE_TV_MODE_SECAM_G, "SECAM-G" },
> > > +    { DRM_MODE_TV_MODE_SECAM_K, "SECAM-K" },
> > > +    { DRM_MODE_TV_MODE_SECAM_K1, "SECAM-K1" },
> > > +    { DRM_MODE_TV_MODE_SECAM_L, "SECAM-L" },
> > > +};
> >
> > I did not comment on it the last time, but this list looks a little bit random.
> >
> > Compared to the standards defined by V4L2, you also define SECAM-60 (a good
> > thing to define, because why not), but don't define PAL-B1, PAL-D1, PAL-K,
> > SECAM-H, SECAM-LC (whatever that is - probably just another name for SECAM-L,
> > see my comment about PAL-Nc below), or NTSC-M-KR (a Korean variant of NTSC).
> >
> > Like I mentioned previously, I'm personally not a fan of including all those
> > CCIR/ITU system variants, as they don't mean any difference to the output unless
> > there is an RF modulator involved. But I get it that they have already been used
> > and regressing probably wouldn't be a very good idea. But in that case keeping
> > it consistent with the set of values used by V4L2 would be wise, I think.
> 
> Exactly. Anything outputting RGB (e.g. through a SCART or VGA connector)
> doesn't care about the color subcarrier or modulator parts.  Likewise,
> anything outputting CVBS doesn't care about the modulator part.
> 
> Perhaps "generic" variants of NSTC and PAL/SECAM should be added, which
> would really just mean 525/60 resp. 625/50.
> 
> Alternatively, the tv_mode field could be split in two parts (either
> two separate fields, or bitwise), to maintain a clear separation between
> lines/fields versus color encoding and RF modulation (with zero for the
> latter meaning a generic version)? That would also keep the door open
> for TV_MODE_405_50, TV_MODE_819_50, TV_MODE_750_50, TV_MODE_750_60, ...

Again, that property is only about color encoding and RF modulation. The
lines numbers and whether it's interlaced or not is encoded in the mode,
not here. So what you suggest is totally doable today.

Maxime

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

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

* Re: [PATCH v2 10/41] drm/modes: Add a function to generate analog display modes
  2022-09-05 16:44       ` Mateusz Kwiatkowski
@ 2022-09-07 14:34         ` Maxime Ripard
  2022-09-07 21:31           ` Mateusz Kwiatkowski
  0 siblings, 1 reply; 128+ messages in thread
From: Maxime Ripard @ 2022-09-07 14:34 UTC (permalink / raw)
  To: Mateusz Kwiatkowski
  Cc: Ben Skeggs, David Airlie, Chen-Yu Tsai, Thomas Zimmermann,
	Jani Nikula, Lyude Paul, Philipp Zabel, Maarten Lankhorst,
	Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec, Samuel Holland,
	Karol Herbst, Noralf Trønnes, Emma Anholt, Daniel Vetter,
	Joonas Lahtinen, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Geert Uytterhoeven

[-- Attachment #1: Type: text/plain, Size: 2080 bytes --]

On Mon, Sep 05, 2022 at 06:44:42PM +0200, Mateusz Kwiatkowski wrote:
> Hi Maxime,
> 
> W dniu 5.09.2022 o 15:37, Maxime Ripard pisze:
> >>> +    vfp = vfp_min + (porches_rem / 2);
> >>> +    vbp = porches - vfp;
> >>
> >> Relative position of the vertical sync within the VBI effectively moves the
> >> image up and down. Adding that (porches_rem / 2) moves the image up off center
> >> by that many pixels. I'd keep the VFP always at minimum to keep the image
> >> centered.
> >
> > And you would increase the back porch only then?
> 
> Well, increasing vbp only gives a centered image with the default 480i/576i
> resolutions. However, only ever changing vbp will cause the image to be always
> at the bottom of the screen when the active line count is decreased (e.g.
> setting the resolution to 720x480 but for 50Hz "PAL" - like many game consoles
> did back in the day).
> 
> I believe that the perfect solution would:
> 
> - Use the canonical / standard-defined blanking line counts for the standard
>   vertical resolutions (480/486/576)
> - Increase vfp and vbp from there by the same number if a smaller number of
>   active lines is specified, so that the resulting image is centered
> - Likewise, decrease vfp and vbp by the same number if the active line number
>   is larger and there is still leeway (this should allow for seamless handling
>   of 480i vs. 486i for 60 Hz "NTSC")

I'm not sure I understand how that's any different than the code you
initially commented on.

I would start by taking the entire blanking area, remove the sync
period. We only have the two porches now, and I'm starting from the
minimum, adding as many pixels in both (unless it's not an even number,
in which case the backporch will have the extra pixel).

Isn't it the same thing?

> - If even more active lines are specified, once the limit for vfp is hit, then
>   decrease vbp only - the resulting image will definitely be off-center, but
>   there's no other way

Unless you only want me to consider the front porch maximum?

Maxime

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

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

* Re: [PATCH v2 10/41] drm/modes: Add a function to generate analog display modes
  2022-09-05 16:32         ` Mateusz Kwiatkowski
@ 2022-09-07 14:38           ` Maxime Ripard
  0 siblings, 0 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-09-07 14:38 UTC (permalink / raw)
  To: Mateusz Kwiatkowski
  Cc: Geert Uytterhoeven, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec,
	Samuel Holland, Karol Herbst, Noralf Trønnes, Emma Anholt,
	Daniel Vetter, Joonas Lahtinen, Hans de Goede, Linux ARM,
	Phil Elwell, Intel Graphics Development, Dave Stevenson,
	DRI Development, Dom Cobley, Linux Kernel Mailing List,
	Nouveau Dev, linux-sunxi

[-- Attachment #1: Type: text/plain, Size: 1726 bytes --]

On Mon, Sep 05, 2022 at 06:32:14PM +0200, Mateusz Kwiatkowski wrote:
> Hi Maxime,
> 
> W dniu 5.09.2022 o 15:32, Maxime Ripard pisze:
> > Hi,
> >
> > On Wed, Aug 31, 2022 at 10:14:28AM +0200, Geert Uytterhoeven wrote:
> >>>> +enum drm_mode_analog {
> >>>> +    DRM_MODE_ANALOG_NTSC,
> >>>> +    DRM_MODE_ANALOG_PAL,
> >>>> +};
> >>>
> >>> Using "NTSC" and "PAL" to describe the 50Hz and 60Hz analog TV modes is common,
> >>> but strictly speaking a misnomer. Those are color encoding systems, and your
> >>> patchset fully supports lesser used, but standard encodings for those (e.g.
> >>> PAL-M for 60Hz and SECAM for 50Hz). I'd propose switching to some more neutral
> >>> naming scheme. Some ideas:
> >>>
> >>> - DRM_MODE_ANALOG_60_HZ / DRM_MODE_ANALOG_50_HZ (after standard refresh rate)
> >>> - DRM_MODE_ANALOG_525_LINES / DRM_MODE_ANALOG_625_LINES (after standard line
> >>>   count)
> >>
> >> IMHO these are bad names, as e.g. VGA640x480@60 is also analog, using
> >> 60 Hz and 525 lines.  Add "TV" to the name?
> >>
> >>> - DRM_MODE_ANALOG_JM / DRM_MODE_ANALOG_BDGHIKLN (after corresponding ITU System
> >>>   Letter Designations)
> >>
> >> Or DRM_MODE_ITU_*?
> >> But given the long list of letters, this looks fragile to me.
> >
> > Does it matter at all? It's an internal API that isn't exposed at all.
> > I'd rather have a common name that everyone can understand in this case
> > rather than a *perfect* name where most will scratch their head
> > wondering what it's about.
> 
> You may have a point. But in that case, maybe it'd make sense to at least add
> a short comment explaining what do you mean by "NTSC" and "PAL" in this context?

Consider it done :)

Maxime

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

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

* Re: Re: [PATCH v2 36/41] drm/sun4i: tv: Merge mode_set into atomic_enable
  2022-09-07  7:41     ` Maxime Ripard
@ 2022-09-07 15:09       ` Jernej Škrabec
  0 siblings, 0 replies; 128+ messages in thread
From: Jernej Škrabec @ 2022-09-07 15:09 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Ben Skeggs, David Airlie, Chen-Yu Tsai, Thomas Zimmermann,
	Jani Nikula, Lyude Paul, Philipp Zabel, Maarten Lankhorst,
	Rodrigo Vivi, Tvrtko Ursulin, Samuel Holland, Karol Herbst,
	Noralf Trønnes, Emma Anholt, Daniel Vetter, Joonas Lahtinen,
	Hans de Goede, linux-arm-kernel, Phil Elwell, intel-gfx,
	Dave Stevenson, dri-devel, Dom Cobley, linux-kernel, nouveau,
	linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

Dne sreda, 07. september 2022 ob 09:41:34 CEST je Maxime Ripard napisal(a):
> On Tue, Sep 06, 2022 at 10:04:32PM +0200, Jernej Škrabec wrote:
> > Dne ponedeljek, 29. avgust 2022 ob 15:11:50 CEST je Maxime Ripard 
napisal(a):
> > > Our mode_set implementation can be merged into our atomic_enable
> > > implementation to simplify things, so let's do this.
> > 
> > Are you sure this is a good thing in long term? What if user wants to
> > change mode? Unlikely, but why not.
> 
> It doesn't change anything feature-wise: whenever the mode is changed on
> the CRTC, the encoder is going to be disabled and enabled.
> 
> It's disabled here:
> https://elixir.bootlin.com/linux/latest/source/drivers/gpu/drm/drm_atomic_he
> lper.c#L1064
> 
> And enabled here:
> https://elixir.bootlin.com/linux/latest/source/drivers/gpu/drm/drm_atomic_he
> lper.c#L1403
> 
> With drm_atomic_crtc_needs_modeset() being defined here:
> https://elixir.bootlin.com/linux/latest/source/include/drm/drm_atomic.h#L104
> 9

Right.

Acked-by: Jernej Skrabec <jernej.skrabec@gmail.com>

Best regards,
Jernej



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

* Re: [PATCH v2 00/41] drm: Analog TV Improvements
  2022-09-07 10:36       ` Stefan Wahren
@ 2022-09-07 16:44         ` Noralf Trønnes
  2022-09-10 15:34           ` Noralf Trønnes
  2022-09-21 14:03           ` Maxime Ripard
  0 siblings, 2 replies; 128+ messages in thread
From: Noralf Trønnes @ 2022-09-07 16:44 UTC (permalink / raw)
  To: Stefan Wahren, Maxime Ripard
  Cc: Ben Skeggs, David Airlie, Chen-Yu Tsai, Thomas Zimmermann,
	Jani Nikula, Lyude Paul, Philipp Zabel, Maarten Lankhorst,
	Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec, Samuel Holland,
	Karol Herbst, Emma Anholt, Daniel Vetter, Joonas Lahtinen,
	Dom Cobley, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, linux-kernel, nouveau,
	linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven,
	Noralf Trønnes



Den 07.09.2022 12.36, skrev Stefan Wahren:
> Hi Maxime,
> 
> Am 05.09.22 um 16:57 schrieb Maxime Ripard:
>> On Fri, Sep 02, 2022 at 01:28:16PM +0200, Noralf Trønnes wrote:
>>>
>>> Den 01.09.2022 21.35, skrev Noralf Trønnes:
>>>>
>>>> I have finally found a workaround for my kernel hangs.
>>>>
>>>> Dom had a look at my kernel and found that the VideoCore was fine, and
>>>> he said this:
>>>>
>>>>> That suggests cause of lockup was on arm side rather than VC side.
>>>>>
>>>>> But it's hard to diagnose further. Once you've had a peripheral not
>>>>> respond, the AXI bus locks up and no further operations are possible.
>>>>> Usual causes of this are required clocks being stopped or domains
>>>>> disabled and then trying to access the hardware.
>>>>>
>>>> So when I got this on my 64-bit build:
>>>>
>>>> [  166.702171] SError Interrupt on CPU1, code 0x00000000bf000002 --
>>>> SError
>>>> [  166.702187] CPU: 1 PID: 8 Comm: kworker/u8:0 Tainted: G        W
>>>>      5.19.0-rc6-00096-gba7973977976-dirty #1
>>>> [  166.702200] Hardware name: Raspberry Pi 4 Model B Rev 1.1 (DT)
>>>> [  166.702206] Workqueue: events_freezable_power_
>>>> thermal_zone_device_check
>>>> [  166.702231] pstate: 200000c5 (nzCv daIF -PAN -UAO -TCO -DIT -SSBS
>>>> BTYPE=--)
>>>> [  166.702242] pc : regmap_mmio_read32le+0x10/0x28
>>>> [  166.702261] lr : regmap_mmio_read+0x44/0x70
>>>> ...
>>>> [  166.702606]  bcm2711_get_temp+0x58/0xb0 [bcm2711_thermal]
>>>>
>>>> I wondered if that reg read was stalled due to a clock being stopped.
>>>>
>>>> Lo and behold, disabling runtime pm and keeping the vec clock running
>>>> all the time fixed it[1].
>>>>
>>>> I don't know what the problem is, but at least I can now test this
>>>> patchset.
>>>>
>>>> [1] https://gist.github.com/notro/23b984e7fa05cfbda2db50a421cac065
>>>>
>>> It turns out I didn't have to disable runtime pm:
>>> https://gist.github.com/notro/0adcfcb12460b54e54458afe11dc8ea2
>> If the bcm2711_thermal IP needs that clock to be enabled, it should grab
>> a reference itself, but it looks like even the device tree binding
>> doesn't ask for one.
> The missing clock in the device tree binding is expected, because
> despite of the code there is not much information about the BCM2711
> clock tree. But i'm skeptical that the AVS IP actually needs the VEC
> clock, i think it's more likely that the VEC clock parent is changed and
> that cause this issue. I could take care of the bcm2711 binding & driver
> if i know which clock is really necessary.

Seems you're right, keeping the parent always enabled is enough:

	clk_prepare_enable(clk_get_parent(vec->clock)); // pllc_per

I tried enabling just the grandparent clock as well, but that didn't help.

Without the clock hack it seems the hang occurs when switching between
NTSC and PAL, at most I've been able to do that 4-5 times before it hangs.

For a while it looked like fbdev/fbcon had a play in this, but then I
realised that it just gave me a NTSC mode to start from and to go back
to when qutting modetest.

Noralf.

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

* Re: [PATCH v2 09/41] drm/connector: Add TV standard property
  2022-09-07 12:10     ` Maxime Ripard
@ 2022-09-07 19:52       ` Mateusz Kwiatkowski
  2022-09-09  9:46         ` Maxime Ripard
  0 siblings, 1 reply; 128+ messages in thread
From: Mateusz Kwiatkowski @ 2022-09-07 19:52 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Ben Skeggs, David Airlie, Chen-Yu Tsai, Thomas Zimmermann,
	Jani Nikula, Lyude Paul, Philipp Zabel, Maarten Lankhorst,
	Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec, Samuel Holland,
	Karol Herbst, Noralf Trønnes, Emma Anholt, Daniel Vetter,
	Joonas Lahtinen, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Geert Uytterhoeven

Hi Maxime,

W dniu 7.09.2022 o 14:10, Maxime Ripard pisze:
> Hi,
>
> On Fri, Sep 02, 2022 at 12:00:33AM +0200, Mateusz Kwiatkowski wrote:
>> W dniu 29.08.2022 o 15:11, Maxime Ripard pisze:
>>> The TV mode property has been around for a while now to select and get the
>>> current TV mode output on an analog TV connector.
>>>
>>> Despite that property name being generic, its content isn't and has been
>>> driver-specific which makes it hard to build any generic behaviour on top
>>> of it, both in kernel and user-space.
>>>
>>> Let's create a new bitmask tv norm property, that can contain any of the
>>> analog TV standards currently supported by kernel drivers. Each driver can
>>> then pass in a bitmask of the modes it supports.
>>
>> This is not a bitmask property anymore, you've just changed it to an enum.
>> The commit message is now misleading.
>>
>>> +static const struct drm_prop_enum_list drm_tv_mode_enum_list[] = {
>>> +    { DRM_MODE_TV_MODE_NTSC_443, "NTSC-443" },
>>> +    { DRM_MODE_TV_MODE_NTSC_J, "NTSC-J" },
>>> +    { DRM_MODE_TV_MODE_NTSC_M, "NTSC-M" },
>>> +    { DRM_MODE_TV_MODE_PAL_60, "PAL-60" },
>>> +    { DRM_MODE_TV_MODE_PAL_B, "PAL-B" },
>>> +    { DRM_MODE_TV_MODE_PAL_D, "PAL-D" },
>>> +    { DRM_MODE_TV_MODE_PAL_G, "PAL-G" },
>>> +    { DRM_MODE_TV_MODE_PAL_H, "PAL-H" },
>>> +    { DRM_MODE_TV_MODE_PAL_I, "PAL-I" },
>>> +    { DRM_MODE_TV_MODE_PAL_M, "PAL-M" },
>>> +    { DRM_MODE_TV_MODE_PAL_N, "PAL-N" },
>>> +    { DRM_MODE_TV_MODE_PAL_NC, "PAL-Nc" },
>>> +    { DRM_MODE_TV_MODE_SECAM_60, "SECAM-60" },
>>> +    { DRM_MODE_TV_MODE_SECAM_B, "SECAM-B" },
>>> +    { DRM_MODE_TV_MODE_SECAM_D, "SECAM-D" },
>>> +    { DRM_MODE_TV_MODE_SECAM_G, "SECAM-G" },
>>> +    { DRM_MODE_TV_MODE_SECAM_K, "SECAM-K" },
>>> +    { DRM_MODE_TV_MODE_SECAM_K1, "SECAM-K1" },
>>> +    { DRM_MODE_TV_MODE_SECAM_L, "SECAM-L" },
>>> +};
>>
>> I did not comment on it the last time, but this list looks a little bit random.
>>
>> Compared to the standards defined by V4L2, you also define SECAM-60 (a good
>> thing to define, because why not), but don't define PAL-B1, PAL-D1, PAL-K,
>> SECAM-H, SECAM-LC (whatever that is - probably just another name for SECAM-L,
>> see my comment about PAL-Nc below), or NTSC-M-KR (a Korean variant of NTSC).
>>
>> Like I mentioned previously, I'm personally not a fan of including all those
>> CCIR/ITU system variants, as they don't mean any difference to the output unless
>> there is an RF modulator involved. But I get it that they have already been used
>> and regressing probably wouldn't be a very good idea. But in that case keeping
>> it consistent with the set of values used by V4L2 would be wise, I think.
>
> Ack. What would be the list of standards we'd absolutely need? NSTC-M,
> NTSC-J, PAL-60, PAL-B, PAL-M, SECAM-60 and SECAM-B?

The "essential list" IMO is NTSC, NTSC-J, NTSC-443, PAL, PAL-M, PAL-N and SECAM.
Note that:

- I intentionally propose "NTSC", "PAL" and "SECAM" without an ITU system
  designation. If we only consider composite signals, there's no difference
  between e.g. PAL-B, PAL-D and PAL-I, so it's better to label it as a generic
  mode, IMO.

  * PAL-M and PAL-N are different, because those unique color encodings were
    only ever used with Systems M and N, respectively.

  * NTSC-J is also different, because "System J" doesn't exist anywhere in ITU
    documents. Japan technically uses System M with a non-standard black level.
    But "NTSC-J" stuck as a universally recognized name for that variant.

- I intentionally did not list PAL-60 or SECAM-60. TBH... PAL-60 is just
  regular PAL paired with 480i60 modeline. Most if not all displays that
  accept PAL-60 input will just label it as "PAL". If we are not introducing
  strict modeline validation, then maybe separating PAL and PAL-60 isn't really
  necessary? Same goes for SECAM vs. SECAM-60.
 
  ...and same goes for NTSC vs. NTSC-50 a.k.a NTSC-N, which is a very exotic
  mode, but known to exist at least in the Atari ST world, see also:
  https://en.wikipedia.org/wiki/NTSC#NTSC-N/NTSC50

Combining PAL and PAL-60 into a single setting would complicate the vc4 driver
a little bit, though, as the registers need to be set up differently for those.

My feelings about the PAL-60 issue are not that strong, though. Merging PAL
and PAL-60 in this context is just a loose suggestion, I won't even try to
argue if you disagree.

>>> +/**
>>> + * drm_mode_create_tv_properties - create TV specific connector properties
>>> + * @dev: DRM device
>>> + * @supported_tv_modes: Bitmask of TV modes supported (See DRM_MODE_TV_MODE_*)
>>> +
>>> + * Called by a driver's TV initialization routine, this function creates
>>> + * the TV specific connector properties for a given device.  Caller is
>>> + * responsible for allocating a list of format names and passing them to
>>> + * this routine.
>>> + *
>>> + * Returns:
>>> + * 0 on success or a negative error code on failure.
>>> + */
>>> +int drm_mode_create_tv_properties(struct drm_device *dev,
>>> +                  unsigned int supported_tv_modes)
>>
>> supported_tv_modes is supposed to be a bitmask of BIT(DRM_MODE_TV_MODE_*)
>> (or (1<<DRM_MODE_TV_MODE_*)) rather than DRM_MODE_TV_MODE_* directly, but this
>> is not said explicitly anywhere in this doc comment.
>
> The argument doc mentions that it's a "Bitmask of TV modes supported
> (See DRM_MODE_TV_MODE_*)", how would you improve it?

Maybe something like "Bitwise OR of BIT(DRM_MODE_TV_MODE_*) values"? Or maybe
just add a little usage example?

> Thanks!
> Maxime

Best regards,
Mateusz Kwiatkowski

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

* Re: [PATCH v2 10/41] drm/modes: Add a function to generate analog display modes
  2022-09-07 14:34         ` Maxime Ripard
@ 2022-09-07 21:31           ` Mateusz Kwiatkowski
  2022-09-09 13:54             ` Maxime Ripard
  2022-09-09 14:00             ` Maxime Ripard
  0 siblings, 2 replies; 128+ messages in thread
From: Mateusz Kwiatkowski @ 2022-09-07 21:31 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Ben Skeggs, David Airlie, Chen-Yu Tsai, Thomas Zimmermann,
	Jani Nikula, Lyude Paul, Philipp Zabel, Maarten Lankhorst,
	Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec, Samuel Holland,
	Karol Herbst, Noralf Trønnes, Emma Anholt, Daniel Vetter,
	Joonas Lahtinen, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Geert Uytterhoeven

Hi Maxime,

W dniu 7.09.2022 o 16:34, Maxime Ripard pisze:
> On Mon, Sep 05, 2022 at 06:44:42PM +0200, Mateusz Kwiatkowski wrote:
>> Hi Maxime,
>>
>> W dniu 5.09.2022 o 15:37, Maxime Ripard pisze:
>>>>> +    vfp = vfp_min + (porches_rem / 2);
>>>>> +    vbp = porches - vfp;
>>>>
>>>> Relative position of the vertical sync within the VBI effectively moves the
>>>> image up and down. Adding that (porches_rem / 2) moves the image up off center
>>>> by that many pixels. I'd keep the VFP always at minimum to keep the image
>>>> centered.
>>>
>>> And you would increase the back porch only then?
>>
>> Well, increasing vbp only gives a centered image with the default 480i/576i
>> resolutions. However, only ever changing vbp will cause the image to be always
>> at the bottom of the screen when the active line count is decreased (e.g.
>> setting the resolution to 720x480 but for 50Hz "PAL" - like many game consoles
>> did back in the day).
>>
>> I believe that the perfect solution would:
>>
>> - Use the canonical / standard-defined blanking line counts for the standard
>>   vertical resolutions (480/486/576)
>> - Increase vfp and vbp from there by the same number if a smaller number of
>>   active lines is specified, so that the resulting image is centered
>> - Likewise, decrease vfp and vbp by the same number if the active line number
>>   is larger and there is still leeway (this should allow for seamless handling
>>   of 480i vs. 486i for 60 Hz "NTSC")
>
> I'm not sure I understand how that's any different than the code you
> initially commented on.
>
> I would start by taking the entire blanking area, remove the sync
> period. We only have the two porches now, and I'm starting from the
> minimum, adding as many pixels in both (unless it's not an even number,
> in which case the backporch will have the extra pixel).
>
> Isn't it the same thing?
> [...]
> Unless you only want me to consider the front porch maximum?

I think you're confusing the "post-equalizing pulses" with the "vertical back
porch" a little bit. The "vertical back porch" includes both the post-equalizing
pulses and the entire rest of the VBI period, for the standard resolutions at
least.

The "canonical" modelines (at least for vc4's VEC, see the notes below):

- (vfp==4, vsync==6, vbp==39) for 576i
- (vfp==7, vsync==6, vbp==32) for 480i
- (vfp==5, vsync==6, vbp==28) for 486i (full frame NTSC as originally specified)

The numbers for vfp don't exactly match the theoretical values, because:

- VEC actually adds a half-line pulse on top of VFP_ODD, and in the 625-line
  mode also on top of VFP_EVEN (not always, but let's not dwell too much)
- Conversely, VEC subtracts the half-line pulse from VSYNC_ODD and VSYNC_EVEN
  in the 625-line mode
- SMPTE S170M (see https://www.itu.int/rec/R-REC-BT.1700-0-200502-I/en) defines
  that active picture for NTSC is on lines 21-263 and 283-525; 263 and 283 are
  half-lines that are represented as full lines in the "486i" spec
- SMPTE 314M, which is the spec for DV, defines the 480 active lines as lines
  23-262 and 285-524; see Table 20 on page 26 in
  https://last.hit.bme.hu/download/firtha/video/SMPTE/SMPTE-314M%20DV25-50.pdf;
  this means that the standard 480i frame shaves off four topmost and two
  bottommost lines (2 and 1 per field) of the 486i full frame

Note that the half-line pulses in vfp/vsync may be generated in a different way
on encoders other than vc4's VEC. Maybe we should define some concrete
semantics for vfp/vsync in analog TV modes, and compensate for that in the
drivers. But anyway, that's a separate issue.

My point is that, to get a centered image, you can then proportionately add
values to those "canonical" vfp/vbp values. For example if someone specifies
720x480 frame, but 50 Hz PAL, you should set (vfp==52, vsync==6, vbp==87).
Those extra vbp lines will be treated as a black bar at the top of the frame,
and extra vfp lines will be at the bottom of the frame.

However if someone specifies e.g. 720x604, there's nothing more you could
remove from vfp, so your only option is to reduce vbp compared to the standard
mode, so you'll end up with (vfp==4, vsync==6, vbp==11). The image will not be
centered, the topmost lines will get cropped out, but that's the best we can do
and if someone is requesting such resolution, they most likely want to actually
access the VBI to e.g. emit teletext.

Your current code always starts at (vfp==5 or 6, vsync=6, vbp==6) and then
increases both vfp and vbp proportionately. This puts vsync dead center in the
VBI, which is not how it's supposed to be - and that in turn causes the image
to be significantly shifted upwards.

I hope this makes more sense to you now.

Best regards,
Mateusz Kwiatkowski

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

* Re: [PATCH v2 10/41] drm/modes: Add a function to generate analog display modes
  2022-08-30 13:01   ` Maíra Canal
@ 2022-09-08 11:10     ` Maxime Ripard
  0 siblings, 0 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-09-08 11:10 UTC (permalink / raw)
  To: Maíra Canal
  Cc: Ben Skeggs, David Airlie, Chen-Yu Tsai, Thomas Zimmermann,
	Jani Nikula, Lyude Paul, Philipp Zabel, Maarten Lankhorst,
	Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec, Samuel Holland,
	Karol Herbst, Noralf Trønnes, Emma Anholt, Daniel Vetter,
	Joonas Lahtinen, Dom Cobley, Dave Stevenson, nouveau, intel-gfx,
	linux-kernel, dri-devel, linux-sunxi, Hans de Goede,
	Geert Uytterhoeven, Mateusz Kwiatkowski, Phil Elwell,
	linux-arm-kernel

Hi,

On Tue, Aug 30, 2022 at 10:01:11AM -0300, Maíra Canal wrote:
> On 8/29/22 10:11, Maxime Ripard wrote:
> > Multiple drivers (meson, vc4, sun4i) define analog TV 525-lines and
> > 625-lines modes in their drivers.
> > 
> > Since those modes are fairly standard, and that we'll need to use them
> > in more places in the future, it makes sense to move their definition
> > into the core framework.
> > 
> > However, analog display usually have fairly loose timings requirements,
> > the only discrete parameters being the total number of lines and pixel
> > clock frequency. Thus, we created a function that will create a display
> > mode from the standard, the pixel frequency and the active area.
> > 
> > Signed-off-by: Maxime Ripard <maxime@cerno.tech>
> > 
> > diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
> > index 304004fb80aa..ee581ee17171 100644
> > --- a/drivers/gpu/drm/drm_modes.c
> > +++ b/drivers/gpu/drm/drm_modes.c
> > @@ -116,6 +116,459 @@ void drm_mode_probed_add(struct drm_connector *connector,
> >  }
> >  EXPORT_SYMBOL(drm_mode_probed_add);
> >  
> > +enum drm_mode_analog {
> > +	DRM_MODE_ANALOG_NTSC,
> > +	DRM_MODE_ANALOG_PAL,
> > +};
> > +
> > +/*
> > + * The timings come from:
> > + * - https://web.archive.org/web/20220406232708/http://www.kolumbus.fi/pami1/video/pal_ntsc.html
> > + * - https://web.archive.org/web/20220406124914/http://martin.hinner.info/vga/pal.html
> > + * - https://web.archive.org/web/20220609202433/http://www.batsocks.co.uk/readme/video_timing.htm
> > + */
> > +#define NTSC_LINE_DURATION_NS		63556U
> > +#define NTSC_LINES_NUMBER		525
> > +
> > +#define NTSC_HBLK_DURATION_TYP_NS	10900U
> > +#define NTSC_HBLK_DURATION_MIN_NS	(NTSC_HBLK_DURATION_TYP_NS - 200)
> > +#define NTSC_HBLK_DURATION_MAX_NS	(NTSC_HBLK_DURATION_TYP_NS + 200)
> > +
> > +#define NTSC_HACT_DURATION_TYP_NS	(NTSC_LINE_DURATION_NS - NTSC_HBLK_DURATION_TYP_NS)
> > +#define NTSC_HACT_DURATION_MIN_NS	(NTSC_LINE_DURATION_NS - NTSC_HBLK_DURATION_MAX_NS)
> > +#define NTSC_HACT_DURATION_MAX_NS	(NTSC_LINE_DURATION_NS - NTSC_HBLK_DURATION_MIN_NS)
> > +
> > +#define NTSC_HFP_DURATION_TYP_NS	1500
> > +#define NTSC_HFP_DURATION_MIN_NS	1270
> > +#define NTSC_HFP_DURATION_MAX_NS	2220
> > +
> > +#define NTSC_HSLEN_DURATION_TYP_NS	4700
> > +#define NTSC_HSLEN_DURATION_MIN_NS	(NTSC_HSLEN_DURATION_TYP_NS - 100)
> > +#define NTSC_HSLEN_DURATION_MAX_NS	(NTSC_HSLEN_DURATION_TYP_NS + 100)
> > +
> > +#define NTSC_HBP_DURATION_TYP_NS	4700
> > +
> > +/*
> > + * I couldn't find the actual tolerance for the back porch, so let's
> > + * just reuse the sync length ones.
> > + */
> > +#define NTSC_HBP_DURATION_MIN_NS	(NTSC_HBP_DURATION_TYP_NS - 100)
> > +#define NTSC_HBP_DURATION_MAX_NS	(NTSC_HBP_DURATION_TYP_NS + 100)
> > +
> > +#define PAL_LINE_DURATION_NS		64000U
> > +#define PAL_LINES_NUMBER		625
> > +
> > +#define PAL_HACT_DURATION_TYP_NS	51950U
> > +#define PAL_HACT_DURATION_MIN_NS	(PAL_HACT_DURATION_TYP_NS - 100)
> > +#define PAL_HACT_DURATION_MAX_NS	(PAL_HACT_DURATION_TYP_NS + 400)
> > +
> > +#define PAL_HBLK_DURATION_TYP_NS	(PAL_LINE_DURATION_NS - PAL_HACT_DURATION_TYP_NS)
> > +#define PAL_HBLK_DURATION_MIN_NS	(PAL_LINE_DURATION_NS - PAL_HACT_DURATION_MAX_NS)
> > +#define PAL_HBLK_DURATION_MAX_NS	(PAL_LINE_DURATION_NS - PAL_HACT_DURATION_MIN_NS)
> > +
> > +#define PAL_HFP_DURATION_TYP_NS		1650
> > +#define PAL_HFP_DURATION_MIN_NS		(PAL_HFP_DURATION_TYP_NS - 100)
> > +#define PAL_HFP_DURATION_MAX_NS		(PAL_HFP_DURATION_TYP_NS + 400)
> > +
> > +#define PAL_HSLEN_DURATION_TYP_NS	4700
> > +#define PAL_HSLEN_DURATION_MIN_NS	(PAL_HSLEN_DURATION_TYP_NS - 200)
> > +#define PAL_HSLEN_DURATION_MAX_NS	(PAL_HSLEN_DURATION_TYP_NS + 200)
> > +
> > +#define PAL_HBP_DURATION_TYP_NS		5700
> > +#define PAL_HBP_DURATION_MIN_NS		(PAL_HBP_DURATION_TYP_NS - 200)
> > +#define PAL_HBP_DURATION_MAX_NS		(PAL_HBP_DURATION_TYP_NS + 200)
> > +
> > +#define PAL_VFP_INTERLACE_LINES		5
> > +#define PAL_VSLEN_INTERLACE_LINES	5
> > +
> > +#define PAL_SHORT_SYNC_DURATION_NS	((2 + 30) * NSEC_PER_USEC)
> > +#define PAL_LONG_SYNC_DURATION_NS	((30 + 2) * NSEC_PER_USEC)
> > +
> > +struct analog_param_field {
> > +	unsigned int even, odd;
> > +};
> > +
> > +#define PARAM_FIELD(_odd, _even)		\
> > +	{ .even = _even, .odd = _odd }
> > +
> > +struct analog_param_range {
> > +	unsigned int	min, typ, max;
> > +};
> > +
> > +#define PARAM_RANGE(_min, _typ, _max)		\
> > +	{ .min = _min, .typ = _typ, .max = _max }
> > +
> > +struct analog_parameters {
> > +	unsigned int			num_lines;
> > +	unsigned int			line_duration_ns;
> > +
> > +	struct analog_param_range	hact_ns;
> > +	struct analog_param_range	hfp_ns;
> > +	struct analog_param_range	hslen_ns;
> > +	struct analog_param_range	hbp_ns;
> > +	struct analog_param_range	hblk_ns;
> > +
> > +	struct analog_param_field	vfp_lines;
> > +	struct analog_param_field	vslen_lines;
> > +	struct analog_param_field	vbp_lines;
> > +};
> > +
> > +#define TV_MODE_PARAMETER(_mode, _lines, _line_dur, _hact, _hfp, _hslen, _hbp, _hblk, _vfp, _vslen, _vbp) \
> > +	[_mode] = {							\
> > +		.num_lines = _lines,					\
> > +		.line_duration_ns = _line_dur,				\
> > +		.hact_ns = _hact,					\
> > +		.hfp_ns = _hfp,						\
> > +		.hslen_ns = _hslen,					\
> > +		.hbp_ns = _hbp,						\
> > +		.hblk_ns = _hblk,					\
> > +		.vfp_lines = _vfp,					\
> > +		.vslen_lines = _vslen,					\
> > +		.vbp_lines = _vbp,					\
> > +	}
> > +
> > +const static struct analog_parameters tv_modes_parameters[] = {
> > +	TV_MODE_PARAMETER(DRM_MODE_ANALOG_NTSC,
> > +			  NTSC_LINES_NUMBER,
> > +			  NTSC_LINE_DURATION_NS,
> > +			  PARAM_RANGE(NTSC_HACT_DURATION_MIN_NS,
> > +				      NTSC_HACT_DURATION_TYP_NS,
> > +				      NTSC_HACT_DURATION_MAX_NS),
> > +			  PARAM_RANGE(NTSC_HFP_DURATION_MIN_NS,
> > +				      NTSC_HFP_DURATION_TYP_NS,
> > +				      NTSC_HFP_DURATION_MAX_NS),
> > +			  PARAM_RANGE(NTSC_HSLEN_DURATION_MIN_NS,
> > +				      NTSC_HSLEN_DURATION_TYP_NS,
> > +				      NTSC_HSLEN_DURATION_MAX_NS),
> > +			  PARAM_RANGE(NTSC_HBP_DURATION_MIN_NS,
> > +				      NTSC_HBP_DURATION_TYP_NS,
> > +				      NTSC_HBP_DURATION_MAX_NS),
> > +			  PARAM_RANGE(NTSC_HBLK_DURATION_MIN_NS,
> > +				      NTSC_HBLK_DURATION_TYP_NS,
> > +				      NTSC_HBLK_DURATION_MAX_NS),
> > +			  PARAM_FIELD(3, 3),
> > +			  PARAM_FIELD(3, 3),
> > +			  PARAM_FIELD(3, 3)),
> > +	TV_MODE_PARAMETER(DRM_MODE_ANALOG_PAL,
> > +			  PAL_LINES_NUMBER,
> > +			  PAL_LINE_DURATION_NS,
> > +			  PARAM_RANGE(PAL_HACT_DURATION_MIN_NS,
> > +				      PAL_HACT_DURATION_TYP_NS,
> > +				      PAL_HACT_DURATION_MAX_NS),
> > +			  PARAM_RANGE(PAL_HFP_DURATION_MIN_NS,
> > +				      PAL_HFP_DURATION_TYP_NS,
> > +				      PAL_HFP_DURATION_MAX_NS),
> > +			  PARAM_RANGE(PAL_HSLEN_DURATION_MIN_NS,
> > +				      PAL_HSLEN_DURATION_TYP_NS,
> > +				      PAL_HSLEN_DURATION_MAX_NS),
> > +			  PARAM_RANGE(PAL_HBP_DURATION_MIN_NS,
> > +				      PAL_HBP_DURATION_TYP_NS,
> > +				      PAL_HBP_DURATION_MAX_NS),
> > +			  PARAM_RANGE(PAL_HBLK_DURATION_MIN_NS,
> > +				      PAL_HBLK_DURATION_TYP_NS,
> > +				      PAL_HBLK_DURATION_MAX_NS),
> > +
> > +			  /*
> > +			   * The front porch is actually 6 short sync
> > +			   * pulses for the even field, and 5 for the
> > +			   * odd field. Each sync takes half a life so
> > +			   * the odd field front porch is shorter by
> > +			   * half a line.
> > +			   *
> > +			   * In progressive, we're supposed to use 6
> > +			   * pulses, so we're fine there
> > +			   */
> > +			  PARAM_FIELD(3, 2),
> > +
> > +			  /*
> > +			   * The vsync length is 5 long sync pulses,
> > +			   * each field taking half a line. We're
> > +			   * shorter for both fields by half a line.
> > +			   *
> > +			   * In progressive, we're supposed to use 5
> > +			   * pulses, so we're off by half
> > +			   * a line.
> > +			   *
> > +			   * In interlace, we're now off by half a line
> > +			   * for the even field and one line for the odd
> > +			   * field.
> > +			   */
> > +			  PARAM_FIELD(3, 3),
> > +
> > +			  /*
> > +			   * The back porch is actually 5 short sync
> > +			   * pulses for the even field, 4 for the odd
> > +			   * field. In progressive, it's 5 short syncs.
> > +			   *
> > +			   * In progressive, we thus have 2.5 lines,
> > +			   * plus the 0.5 line we were missing
> > +			   * previously, so we should use 3 lines.
> > +			   *
> > +			   * In interlace, the even field is in the
> > +			   * exact same case than progressive. For the
> > +			   * odd field, we should be using 2 lines but
> > +			   * we're one line short, so we'll make up for
> > +			   * it here by using 3.
> > +			   */
> > +			  PARAM_FIELD(3, 3)),
> > +};
> > +
> > +static int fill_analog_mode(struct drm_display_mode *mode,
> > +			    const struct analog_parameters *params,
> > +			    unsigned long pixel_clock_hz,
> > +			    unsigned int hactive,
> > +			    unsigned int vactive,
> > +			    bool interlace)
> > +{
> > +	unsigned long pixel_duration_ns = NSEC_PER_SEC / pixel_clock_hz;
> > +	unsigned long long htotal;
> > +	unsigned int vtotal;
> > +	unsigned int max_hact, hact_duration_ns;
> > +	unsigned int hblk, hblk_duration_ns;
> > +	unsigned int hfp, hfp_min, hfp_duration_ns;
> > +	unsigned int hslen, hslen_duration_ns;
> > +	unsigned int hbp, hbp_min, hbp_duration_ns;
> > +	unsigned int porches, porches_duration_ns;
> > +	unsigned int vfp, vfp_min;
> > +	unsigned int vbp, vbp_min;
> > +	unsigned int vslen;
> > +	int porches_rem;
> > +	bool strict = true;
> > +
> > +	max_hact = params->hact_ns.max / pixel_duration_ns;
> > +	if (pixel_clock_hz == 13500000 && hactive > max_hact && hactive <= 720)
> > +		strict = false;
> > +
> > +	/*
> > +	 * Our pixel duration is going to be round down by the division,
> > +	 * so rounding up is probably going to introduce even more
> > +	 * deviation.
> > +	 */
> > +	htotal = params->line_duration_ns * pixel_clock_hz / NSEC_PER_SEC;
> > +
> > +	hact_duration_ns = hactive * pixel_duration_ns;
> > +	if (strict &&
> > +	    (hact_duration_ns < params->hact_ns.min ||
> > +	     hact_duration_ns > params->hact_ns.max)) {
> > +		DRM_ERROR("Invalid horizontal active area duration: %uns (min: %u, max %u)\n",
> > +			  hact_duration_ns, params->hact_ns.min, params->hact_ns.max);
> > +		return -EINVAL;
> > +	}
> > +
> > +	hblk = htotal - hactive;
> > +	hblk_duration_ns = hblk * pixel_duration_ns;
> > +	if (strict &&
> > +	    (hblk_duration_ns < params->hblk_ns.min ||
> > +	     hblk_duration_ns > params->hblk_ns.max)) {
> > +		DRM_ERROR("Invalid horizontal blanking duration: %uns (min: %u, max %u)\n",
> > +			  hblk_duration_ns, params->hblk_ns.min, params->hblk_ns.max);
> > +		return -EINVAL;
> > +	}
> > +
> > +	hslen = DIV_ROUND_UP(params->hslen_ns.typ, pixel_duration_ns);
> > +	hslen_duration_ns = hslen * pixel_duration_ns;
> > +	if (strict &&
> > +	    (hslen_duration_ns < params->hslen_ns.min ||
> > +	     hslen_duration_ns > params->hslen_ns.max)) {
> > +		DRM_ERROR("Invalid horizontal sync duration: %uns (min: %u, max %u)\n",
> > +			  hslen_duration_ns, params->hslen_ns.min, params->hslen_ns.max);
> > +		return -EINVAL;
> > +	}
> > +
> > +	porches = hblk - hslen;
> > +	porches_duration_ns = porches * pixel_duration_ns;
> > +	if (strict &&
> > +	    (porches_duration_ns > (params->hfp_ns.max + params->hbp_ns.max) ||
> > +	     porches_duration_ns < (params->hfp_ns.min + params->hbp_ns.min))) {
> > +		DRM_ERROR("Invalid horizontal porches duration: %uns\n", porches_duration_ns);
> > +		return -EINVAL;
> > +	}
> > +
> > +	hfp_min = DIV_ROUND_UP(params->hfp_ns.min, pixel_duration_ns);
> > +	hbp_min = DIV_ROUND_UP(params->hbp_ns.min, pixel_duration_ns);
> > +	porches_rem = porches - hfp_min - hbp_min;
> > +
> > +	hfp = hfp_min + DIV_ROUND_UP(porches_rem, 2);
> > +	hfp_duration_ns = hfp * pixel_duration_ns;
> > +	if (strict &&
> > +	    (hfp_duration_ns < params->hfp_ns.min ||
> > +	     hfp_duration_ns > params->hfp_ns.max)) {
> > +		DRM_ERROR("Invalid horizontal front porch duration: %uns (min: %u, max %u)\n",
> > +			  hfp_duration_ns, params->hfp_ns.min, params->hfp_ns.max);
> > +		return -EINVAL;
> > +	}
> > +
> > +	hbp = porches - hfp;
> > +	hbp_duration_ns = hbp * pixel_duration_ns;
> > +	if (strict &&
> > +	    (hbp_duration_ns < params->hbp_ns.min ||
> > +	     hbp_duration_ns > params->hbp_ns.max)) {
> > +		DRM_ERROR("Invalid horizontal back porch duration: %uns (min: %u, max %u)\n",
> > +			  hbp_duration_ns, params->hbp_ns.min, params->hbp_ns.max);
> > +		return -EINVAL;
> > +	}
> > +
> > +	if (htotal != (hactive + hfp + hslen + hbp))
> > +		return -EINVAL;
> > +
> > +	mode->clock = pixel_clock_hz / 1000;
> > +	mode->hdisplay = hactive;
> > +	mode->hsync_start = hactive + hfp;
> > +	mode->hsync_end = hactive + hfp + hslen;
> > +	mode->htotal = hactive + hfp + hslen + hbp;
> > +
> > +	if (interlace) {
> > +		vfp_min = params->vfp_lines.even + params->vfp_lines.odd;
> > +		vbp_min = params->vbp_lines.even + params->vbp_lines.odd;
> > +		vslen = params->vslen_lines.even + params->vslen_lines.odd;
> > +	} else {
> > +		/*
> > +		 * By convention, NSTC (aka 525/60) systems start with
> > +		 * the even field, but PAL (aka 625/50) systems start
> > +		 * with the odd one.
> > +		 *
> > +		 * PAL systems also have asymetric timings between the
> > +		 * even and odd field, while NTSC is symetric.
> > +		 *
> > +		 * Moreover, if we want to create a progressive mode for
> > +		 * PAL, we need to use the odd field timings.
> > +		 *
> > +		 * Since odd == even for NTSC, we can just use the odd
> > +		 * one all the time to simplify the code a bit.
> > +		 */
> > +		vfp_min = params->vfp_lines.odd;
> > +		vbp_min = params->vbp_lines.odd;
> > +		vslen = params->vslen_lines.odd;
> > +	}
> > +
> > +	porches = params->num_lines - vactive - vslen;
> > +	porches_rem = porches - vfp_min - vbp_min;
> > +
> > +	vfp = vfp_min + (porches_rem / 2);
> > +	vbp = porches - vfp;
> > +
> > +	vtotal = vactive + vfp + vslen + vbp;
> > +	if (params->num_lines != vtotal) {
> > +		DRM_ERROR("Invalid vertical total: %upx (expected %upx)\n",
> > +			  vtotal, params->num_lines);
> > +		return -EINVAL;
> > +	}
> > +
> > +	mode->vdisplay = vactive;
> > +	mode->vsync_start = vactive + vfp;
> > +	mode->vsync_end = vactive + vfp + vslen;
> > +	mode->vtotal = vactive + vfp + vslen + vbp;
> > +
> > +	mode->type = DRM_MODE_TYPE_DRIVER;
> > +	mode->flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC;
> > +	if (interlace)
> > +		mode->flags |= DRM_MODE_FLAG_INTERLACE;
> > +
> > +	drm_mode_set_name(mode);
> > +
> > +	if (mode->vtotal != params->num_lines)
> > +		return -EINVAL;
> > +
> > +	return 0;
> > +}
> > +
> > +/**
> > + * drm_analog_tv_mode - create a display mode for an analog TV
> > + * @dev: drm device
> > + * @tv_mode: TV Mode standard to create a mode for. See DRM_MODE_TV_MODE_*.
> > + * @pixel_clock_hz: Pixel Clock Frequency, in Hertz
> > + * @hdisplay: hdisplay size
> > + * @vdisplay: vdisplay size
> > + * @interlace: whether to compute an interlaced mode
> > + *
> > + * This function creates a struct drm_display_mode instance suited for
> > + * an analog TV output, for one of the usual analog TV mode.
> > + *
> > + * Note that @hdisplay is larger than the usual constraints for the PAL
> > + * and NTSC timings, and we'll choose to ignore most timings constraints
> > + * to reach those resolutions.
> > + *
> > + * Returns:
> > + *
> > + * A pointer to the mode, allocated with drm_mode_create(). Returns NULL
> > + * on error.
> > + */
> > +struct drm_display_mode *drm_analog_tv_mode(struct drm_device *dev,
> > +					    enum drm_connector_tv_mode tv_mode,
> > +					    unsigned long pixel_clock_hz,
> > +					    unsigned int hdisplay,
> > +					    unsigned int vdisplay,
> > +					    bool interlace)
> > +{
> > +	struct drm_display_mode *mode;
> > +	enum drm_mode_analog analog;
> > +	int ret;
> > +
> > +	switch (tv_mode) {
> > +	case DRM_MODE_TV_MODE_NTSC_443:
> > +		fallthrough;
> > +	case DRM_MODE_TV_MODE_NTSC_J:
> > +		fallthrough;
> > +	case DRM_MODE_TV_MODE_NTSC_M:
> > +		fallthrough;
> > +	case DRM_MODE_TV_MODE_PAL_60:
> > +		fallthrough;
> > +	case DRM_MODE_TV_MODE_PAL_M:
> > +		fallthrough;
> > +	case DRM_MODE_TV_MODE_SECAM_60:
> > +		analog = DRM_MODE_ANALOG_NTSC;
> > +		break;
> > +
> > +	case DRM_MODE_TV_MODE_PAL_B:
> > +		fallthrough;
> > +	case DRM_MODE_TV_MODE_PAL_D:
> > +		fallthrough;
> > +	case DRM_MODE_TV_MODE_PAL_G:
> > +		fallthrough;
> > +	case DRM_MODE_TV_MODE_PAL_H:
> > +		fallthrough;
> > +	case DRM_MODE_TV_MODE_PAL_I:
> > +		fallthrough;
> > +	case DRM_MODE_TV_MODE_PAL_N:
> > +		fallthrough;
> > +	case DRM_MODE_TV_MODE_PAL_NC:
> > +		fallthrough;
> > +	case DRM_MODE_TV_MODE_SECAM_B:
> > +		fallthrough;
> > +	case DRM_MODE_TV_MODE_SECAM_D:
> > +		fallthrough;
> > +	case DRM_MODE_TV_MODE_SECAM_G:
> > +		fallthrough;
> > +	case DRM_MODE_TV_MODE_SECAM_K:
> > +		fallthrough;
> > +	case DRM_MODE_TV_MODE_SECAM_K1:
> > +		fallthrough;
> > +	case DRM_MODE_TV_MODE_SECAM_L:
> > +		analog = DRM_MODE_ANALOG_PAL;
> > +		break;
> > +
> > +	default:
> > +		return NULL;
> > +	}
> > +
> > +	mode = drm_mode_create(dev);
> > +	if (!mode)
> > +		return NULL;
> > +
> > +	ret = fill_analog_mode(mode,
> > +			       &tv_modes_parameters[analog],
> > +			       pixel_clock_hz, hdisplay, vdisplay, interlace);
> > +	if (ret)
> > +		goto err_free_mode;
> > +
> > +	return mode;
> > +
> > +err_free_mode:
> > +	drm_mode_destroy(dev, mode);
> > +	return NULL;
> > +}
> > +EXPORT_SYMBOL(drm_analog_tv_mode);
> > +
> >  /**
> >   * drm_cvt_mode -create a modeline based on the CVT algorithm
> >   * @dev: drm device
> > diff --git a/drivers/gpu/drm/tests/Makefile b/drivers/gpu/drm/tests/Makefile
> > index b29ef1085cad..b22ac96fdd65 100644
> > --- a/drivers/gpu/drm/tests/Makefile
> > +++ b/drivers/gpu/drm/tests/Makefile
> > @@ -10,5 +10,6 @@ obj-$(CONFIG_DRM_KUNIT_TEST) += \
> >  	drm_framebuffer_test.o \
> >  	drm_kunit_helpers.o \
> >  	drm_mm_test.o \
> > +	drm_modes_test.o \
> >  	drm_plane_helper_test.o \
> >  	drm_rect_test.o
> > diff --git a/drivers/gpu/drm/tests/drm_modes_test.c b/drivers/gpu/drm/tests/drm_modes_test.c
> > new file mode 100644
> > index 000000000000..87d398fcb99e
> > --- /dev/null
> > +++ b/drivers/gpu/drm/tests/drm_modes_test.c
> > @@ -0,0 +1,131 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Kunit test for drm_modes functions
> > + */
> > +
> > +#include <kunit/test.h>
> > +
> > +#include <drm/drm_modes.h>
> > +
> > +#include "drm_kunit_helpers.h"
> > +
> > +struct drm_modes_test_priv {
> > +	struct drm_device *drm;
> > +};
> > +
> > +static int drm_modes_test_init(struct kunit *test)
> > +{
> > +	struct drm_modes_test_priv *priv;
> > +
> > +	priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
> > +	if (!priv)
> > +		return -ENOMEM;
> 
> I believe it would be nicer to use KUNIT_ASSERT_NOT_NULL here, instead
> of returning a error.
> 
> > +	test->priv = priv;
> > +
> > +	priv->drm = drm_kunit_device_init("drm-modes-test");
> > +	if (IS_ERR(priv->drm))
> > +		return PTR_ERR(priv->drm);
> 
> Here you could use KUNIT_ASSERT_NOT_ERR_OR_NULL.
> 
> > +
> > +	return 0;
> > +}
> > +
> > +static void drm_modes_test_exit(struct kunit *test)
> > +{
> > +	struct drm_modes_test_priv *priv = test->priv;
> > +
> > +	drm_kunit_device_exit(priv->drm);
> > +}
> > +
> > +static void drm_modes_analog_tv_ntsc_480i(struct kunit *test)
> > +{
> > +	struct drm_modes_test_priv *priv = test->priv;
> > +	struct drm_display_mode *mode;
> > +
> > +	mode = drm_analog_tv_mode(priv->drm,
> > +				  DRM_MODE_TV_MODE_NTSC_M,
> > +				  13500 * 1000, 720, 480,
> > +				  true);
> > +	KUNIT_ASSERT_NOT_NULL(test, mode);
> > +
> > +	KUNIT_EXPECT_EQ(test, drm_mode_vrefresh(mode), 60);
> > +	KUNIT_EXPECT_EQ(test, mode->hdisplay, 720);
> > +
> > +	/* 63.556us * 13.5MHz = 858 pixels */
> > +	KUNIT_EXPECT_EQ(test, mode->htotal, 858);
> > +	KUNIT_EXPECT_EQ(test, mode->vdisplay, 480);
> > +	KUNIT_EXPECT_EQ(test, mode->vtotal, 525);
> > +}
> 
> I would be nice to see this test and drm_modes_analog_tv_pal_576i
> parametrized.

I'm not sure it's that useful here, the tests are trivial and there's
not much to share between the two tests, since pretty much all the data
are different.

I've changed the command line parsing to use a parameterized test though

Thanks!
Maxime

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

* Re: [PATCH v2 32/41] drm/vc4: vec: Convert to the new TV mode property
  2022-08-30 19:01   ` Noralf Trønnes
@ 2022-09-08 11:23     ` Maxime Ripard
  2022-09-08 11:31       ` Mateusz Kwiatkowski
  2022-09-08 11:34       ` Noralf Trønnes
  0 siblings, 2 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-09-08 11:23 UTC (permalink / raw)
  To: Noralf Trønnes
  Cc: Ben Skeggs, David Airlie, Chen-Yu Tsai, Thomas Zimmermann,
	Jani Nikula, Lyude Paul, Philipp Zabel, Maarten Lankhorst,
	Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec, Samuel Holland,
	Karol Herbst, Emma Anholt, Daniel Vetter, Joonas Lahtinen,
	Hans de Goede, linux-arm-kernel, Phil Elwell, intel-gfx,
	Dave Stevenson, dri-devel, Dom Cobley, linux-kernel, nouveau,
	linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

Hi Noralf,

On Tue, Aug 30, 2022 at 09:01:08PM +0200, Noralf Trønnes wrote:
> > +static const struct drm_prop_enum_list tv_mode_names[] = {
> 
> Maybe call it legacy_tv_mode_enums?
> 
> > 
> > +	{ VC4_VEC_TV_MODE_NTSC, "NTSC", },
> > 
> > +	{ VC4_VEC_TV_MODE_NTSC_J, "NTSC-J", },
> > 
> > +	{ VC4_VEC_TV_MODE_PAL, "PAL", },
> > 
> > +	{ VC4_VEC_TV_MODE_PAL_M, "PAL-M", },
> 
> If you use DRM_MODE_TV_MODE_* here you don't need to translate the value
> using the switch statement in get/set property, you can use the value
> directly to get/set tv.mode.

I'm sorry, I'm not quite sure what you mean by that. If we expose the
DRM_MODE_TV_MODE_* properties there, won't that change the values the
userspace will need to use to set that property?

Maxime

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

* Re: [PATCH v2 32/41] drm/vc4: vec: Convert to the new TV mode property
  2022-09-08 11:23     ` Maxime Ripard
@ 2022-09-08 11:31       ` Mateusz Kwiatkowski
  2022-09-08 12:16         ` Maxime Ripard
  2022-09-08 11:34       ` Noralf Trønnes
  1 sibling, 1 reply; 128+ messages in thread
From: Mateusz Kwiatkowski @ 2022-09-08 11:31 UTC (permalink / raw)
  To: Maxime Ripard, Noralf Trønnes
  Cc: Ben Skeggs, David Airlie, Chen-Yu Tsai, Thomas Zimmermann,
	Jani Nikula, Lyude Paul, Philipp Zabel, Maarten Lankhorst,
	Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec, Samuel Holland,
	Karol Herbst, Emma Anholt, Daniel Vetter, Joonas Lahtinen,
	Hans de Goede, linux-arm-kernel, Phil Elwell, intel-gfx,
	Dave Stevenson, dri-devel, Dom Cobley, linux-kernel, nouveau,
	linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

Hi Maxime,

W dniu 08.09.2022 o 13:23, Maxime Ripard pisze:
> Hi Noralf,
>
> On Tue, Aug 30, 2022 at 09:01:08PM +0200, Noralf Trønnes wrote:
>>> +static const struct drm_prop_enum_list tv_mode_names[] = {
>>
>> Maybe call it legacy_tv_mode_enums?
>>
>>>
>>> +    { VC4_VEC_TV_MODE_NTSC, "NTSC", },
>>>
>>> +    { VC4_VEC_TV_MODE_NTSC_J, "NTSC-J", },
>>>
>>> +    { VC4_VEC_TV_MODE_PAL, "PAL", },
>>>
>>> +    { VC4_VEC_TV_MODE_PAL_M, "PAL-M", },
>>
>> If you use DRM_MODE_TV_MODE_* here you don't need to translate the value
>> using the switch statement in get/set property, you can use the value
>> directly to get/set tv.mode.
>
> I'm sorry, I'm not quite sure what you mean by that. If we expose the
> DRM_MODE_TV_MODE_* properties there, won't that change the values the
> userspace will need to use to set that property?

I'd just like to point out that if numerical values of these enums are your
concern, then you're (or perhaps I am ;) already breaking this by adding new
modes in patch 33/41 in this series.

And the values (and names!) added by that patch (33/41) don't match those
currently used by the downstream version
(https://github.com/raspberrypi/linux/blob/rpi-5.15.y/drivers/gpu/drm/vc4/vc4_vec.c).
If any userspace software is manipulating this property, it's most likely
targeting the downstream code. But since you're not aiming for consistency with
that, I was under the impression that compatibility isn't a concern.

Best regards,
Mateusz Kwiatkowski

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

* Re: [PATCH v2 32/41] drm/vc4: vec: Convert to the new TV mode property
  2022-09-08 11:23     ` Maxime Ripard
  2022-09-08 11:31       ` Mateusz Kwiatkowski
@ 2022-09-08 11:34       ` Noralf Trønnes
  1 sibling, 0 replies; 128+ messages in thread
From: Noralf Trønnes @ 2022-09-08 11:34 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Ben Skeggs, David Airlie, Chen-Yu Tsai, Thomas Zimmermann,
	Jani Nikula, Lyude Paul, Philipp Zabel, Maarten Lankhorst,
	Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec, Samuel Holland,
	Karol Herbst, Emma Anholt, Daniel Vetter, Joonas Lahtinen,
	Hans de Goede, linux-arm-kernel, Phil Elwell, intel-gfx,
	Dave Stevenson, dri-devel, Dom Cobley, linux-kernel, nouveau,
	linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven,
	Noralf Trønnes



Den 08.09.2022 13.23, skrev Maxime Ripard:
> Hi Noralf,
> 
> On Tue, Aug 30, 2022 at 09:01:08PM +0200, Noralf Trønnes wrote:
>>> +static const struct drm_prop_enum_list tv_mode_names[] = {
>>
>> Maybe call it legacy_tv_mode_enums?
>>
>>>
>>> +	{ VC4_VEC_TV_MODE_NTSC, "NTSC", },
>>>
>>> +	{ VC4_VEC_TV_MODE_NTSC_J, "NTSC-J", },
>>>
>>> +	{ VC4_VEC_TV_MODE_PAL, "PAL", },
>>>
>>> +	{ VC4_VEC_TV_MODE_PAL_M, "PAL-M", },
>>
>> If you use DRM_MODE_TV_MODE_* here you don't need to translate the value
>> using the switch statement in get/set property, you can use the value
>> directly to get/set tv.mode.
> 
> I'm sorry, I'm not quite sure what you mean by that. If we expose the
> DRM_MODE_TV_MODE_* properties there, won't that change the values the
> userspace will need to use to set that property?
> 

You're right ofc, I forgot that the enum values are also UABI.

Noralf.

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

* Re: [PATCH v2 32/41] drm/vc4: vec: Convert to the new TV mode property
  2022-09-08 11:31       ` Mateusz Kwiatkowski
@ 2022-09-08 12:16         ` Maxime Ripard
  0 siblings, 0 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-09-08 12:16 UTC (permalink / raw)
  To: Mateusz Kwiatkowski
  Cc: Noralf Trønnes, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec,
	Samuel Holland, Karol Herbst, Emma Anholt, Daniel Vetter,
	Joonas Lahtinen, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

[-- Attachment #1: Type: text/plain, Size: 1852 bytes --]

On Thu, Sep 08, 2022 at 01:31:34PM +0200, Mateusz Kwiatkowski wrote:
> W dniu 08.09.2022 o 13:23, Maxime Ripard pisze:
> > Hi Noralf,
> >
> > On Tue, Aug 30, 2022 at 09:01:08PM +0200, Noralf Trønnes wrote:
> >>> +static const struct drm_prop_enum_list tv_mode_names[] = {
> >>
> >> Maybe call it legacy_tv_mode_enums?
> >>
> >>>
> >>> +    { VC4_VEC_TV_MODE_NTSC, "NTSC", },
> >>>
> >>> +    { VC4_VEC_TV_MODE_NTSC_J, "NTSC-J", },
> >>>
> >>> +    { VC4_VEC_TV_MODE_PAL, "PAL", },
> >>>
> >>> +    { VC4_VEC_TV_MODE_PAL_M, "PAL-M", },
> >>
> >> If you use DRM_MODE_TV_MODE_* here you don't need to translate the value
> >> using the switch statement in get/set property, you can use the value
> >> directly to get/set tv.mode.
> >
> > I'm sorry, I'm not quite sure what you mean by that. If we expose the
> > DRM_MODE_TV_MODE_* properties there, won't that change the values the
> > userspace will need to use to set that property?
> 
> I'd just like to point out that if numerical values of these enums are your
> concern, then you're (or perhaps I am ;) already breaking this by adding new
> modes in patch 33/41 in this series.
> 
> And the values (and names!) added by that patch (33/41) don't match those
> currently used by the downstream version
> (https://github.com/raspberrypi/linux/blob/rpi-5.15.y/drivers/gpu/drm/vc4/vc4_vec.c).
> If any userspace software is manipulating this property, it's most likely
> targeting the downstream code. But since you're not aiming for consistency with
> that, I was under the impression that compatibility isn't a concern.

I'm not really concerned about the compatibility with the downstream
tree, if only because you already broke that compatibility with your
patch :)

So you're right, I'll reorganize that patch to keep the backward
compatibility.

Maxime

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

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

* Re: [PATCH v2 32/41] drm/vc4: vec: Convert to the new TV mode property
  2022-08-31  2:23   ` Mateusz Kwiatkowski
@ 2022-09-08 13:18     ` Maxime Ripard
  0 siblings, 0 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-09-08 13:18 UTC (permalink / raw)
  To: Mateusz Kwiatkowski
  Cc: Ben Skeggs, David Airlie, Chen-Yu Tsai, Thomas Zimmermann,
	Jani Nikula, Lyude Paul, Philipp Zabel, Maarten Lankhorst,
	Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec, Samuel Holland,
	Karol Herbst, Noralf Trønnes, Emma Anholt, Daniel Vetter,
	Joonas Lahtinen, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Geert Uytterhoeven

[-- Attachment #1: Type: text/plain, Size: 4271 bytes --]

On Wed, Aug 31, 2022 at 04:23:21AM +0200, Mateusz Kwiatkowski wrote:
> I tested your patchset on my Pi and it mostly works. Good work! However,
> I noticed a couple of issues.
> 
> > -static int vc4_vec_encoder_atomic_check(struct drm_encoder *encoder,
> > -                    struct drm_crtc_state *crtc_state,
> > -                    struct drm_connector_state *conn_state)
> > -{
> > -    const struct vc4_vec_tv_mode *vec_mode;
> > -
> > -    vec_mode = &vc4_vec_tv_modes[conn_state->tv.mode];
> > -
> > -    if (conn_state->crtc &&
> > -        !drm_mode_equal(vec_mode->mode, &crtc_state->adjusted_mode))
> > -        return -EINVAL;
> > -
> > -    return 0;
> > -}
> 
> I may have said it myself that we should allow custom modelines without too
> much validation. The VC4 and VEC, however, have some considerable limitations
> when it comes to the modelines that they can reliably output.
> 
> In particular, attempting to use "50 Hz" timings in NTSC/PAL-M modes (or
> "60 Hz" in PAL/SECAM modes) results in a weirdly skewed image. Here's how it
> may look like:
> https://user-images.githubusercontent.com/4499762/187575940-736e7262-c82d-42f3-a2d8-f309cbd51139.png
> 
> This is because if the CRTC does not trigger the sync pulses within an
> acceptable time window, the VEC apparently generates them itself. This causes
> the VEC sync pulses (which go onto the wire) not quite line up with the ones
> from the modeline, which results in what you see on the screenshot.
> 
> I once wrote a validation function based on extensive testing of what
> produces a sensible output and what doesn't. You can find it here:
> https://github.com/raspberrypi/linux/pull/4406/commits/15c0c51. I think it
> might be a good idea to include something like that - even though I know it's
> somewhat ugly.

I've reworked that code a bit, and it will be part of my next version.

> (BTW, those %2 checks on vertical timings in that linked commit can be ignored;
> those values are divided by 2 for interlaced modes anyway. Those checks were
> intended to ensure proper odd-first or even-first timings; I'm not sure if your
> code calculates those in the same way)

Ack, I've removed them.

> >  static int vc4_vec_connector_get_modes(struct drm_connector *connector)
> >  {
> > -    struct drm_connector_state *state = connector->state;
> >      struct drm_display_mode *mode;
> > +    int count = 0;
> >  
> > -    mode = drm_mode_duplicate(connector->dev,
> > -                  vc4_vec_tv_modes[state->tv.mode].mode);
> > +    mode = drm_mode_analog_ntsc_480i(connector->dev);
> >      if (!mode) {
> >          DRM_ERROR("Failed to create a new display mode\n");
> >          return -ENOMEM;
> >      }
> >  
> >      drm_mode_probed_add(connector, mode);
> > +    count += 1;
> >  
> > -    return 1;
> > +    mode = drm_mode_analog_pal_576i(connector->dev);
> > +    if (!mode) {
> > +        DRM_ERROR("Failed to create a new display mode\n");
> > +        return -ENOMEM;
> > +    }
> > +
> > +    drm_mode_probed_add(connector, mode);
> > +    count += 1;
> > +
> > +    return count;
> > +}
> 
> Xorg is pretty confused by these modes being reported like that. The 576i mode
> is *always* preferred, presumably because of the higher resolution. If the NTSC
> mode is set (via the kernel cmdline or just due to it being the default), this
> results in a mess on the screen - exactly the same thing as on the screenshot
> linked above.
> 
> Note that drm_helper_probe_add_cmdline_mode() *does* add the
> DRM_MODE_TYPE_USERDEF flag to the 480i mode, having detected it as preferred
> on the command line - but Xorg does not seem to care about that.

I'm not quite sure why that would be the case. The usual logic to pick
the preferred mode is to use either the mode with the flag or the first
one.

> I remember Noralf suggesting setting DRM_MODE_TYPE_PREFERRED for the mode that
> corresponds to the currently chosen tv_mode - that would fix the problem.
> An alternative would be to _not_ add the "opposite" mode at all, like the
> current default Raspberry Pi OS kernel behaves.

I'll add it the PREFERRED flag then, switching the modes have other
challenges.

Maxime

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

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

* Re: (subset) [PATCH v2 36/41] drm/sun4i: tv: Merge mode_set into atomic_enable
  2022-08-29 13:11 ` [PATCH v2 36/41] drm/sun4i: tv: Merge mode_set into atomic_enable Maxime Ripard
  2022-09-06 20:04   ` Jernej Škrabec
@ 2022-09-08 14:02   ` Maxime Ripard
  1 sibling, 0 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-09-08 14:02 UTC (permalink / raw)
  To: Noralf Trønnes, Jernej Skrabec, Karol Herbst,
	Samuel Holland, Maxime Ripard, David Airlie, Daniel Vetter,
	Chen-Yu Tsai, Joonas Lahtinen, Rodrigo Vivi, Emma Anholt,
	Philipp Zabel, Maarten Lankhorst, Maxime Ripard, Tvrtko Ursulin,
	Ben Skeggs, Jani Nikula, Lyude Paul, Thomas Zimmermann
  Cc: Geert Uytterhoeven, Dom Cobley, linux-sunxi, Hans de Goede,
	linux-arm-kernel, intel-gfx, Dave Stevenson, dri-devel,
	Phil Elwell, nouveau, linux-kernel, Mateusz Kwiatkowski

On Mon, 29 Aug 2022 15:11:50 +0200, Maxime Ripard wrote:
> Our mode_set implementation can be merged into our atomic_enable
> implementation to simplify things, so let's do this.
> 
> 

Applied to drm/drm-misc (drm-misc-next).

Thanks!
Maxime

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

* Re: [PATCH v2 09/41] drm/connector: Add TV standard property
  2022-09-07 19:52       ` Mateusz Kwiatkowski
@ 2022-09-09  9:46         ` Maxime Ripard
  2022-09-11  4:32           ` Mateusz Kwiatkowski
  0 siblings, 1 reply; 128+ messages in thread
From: Maxime Ripard @ 2022-09-09  9:46 UTC (permalink / raw)
  To: Mateusz Kwiatkowski
  Cc: Ben Skeggs, David Airlie, Chen-Yu Tsai, Thomas Zimmermann,
	Jani Nikula, Lyude Paul, Philipp Zabel, Maarten Lankhorst,
	Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec, Samuel Holland,
	Karol Herbst, Noralf Trønnes, Emma Anholt, Daniel Vetter,
	Joonas Lahtinen, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Geert Uytterhoeven

[-- Attachment #1: Type: text/plain, Size: 6272 bytes --]

On Wed, Sep 07, 2022 at 09:52:09PM +0200, Mateusz Kwiatkowski wrote:
> W dniu 7.09.2022 o 14:10, Maxime Ripard pisze:
> > Hi,
> >
> > On Fri, Sep 02, 2022 at 12:00:33AM +0200, Mateusz Kwiatkowski wrote:
> >> W dniu 29.08.2022 o 15:11, Maxime Ripard pisze:
> >>> The TV mode property has been around for a while now to select and get the
> >>> current TV mode output on an analog TV connector.
> >>>
> >>> Despite that property name being generic, its content isn't and has been
> >>> driver-specific which makes it hard to build any generic behaviour on top
> >>> of it, both in kernel and user-space.
> >>>
> >>> Let's create a new bitmask tv norm property, that can contain any of the
> >>> analog TV standards currently supported by kernel drivers. Each driver can
> >>> then pass in a bitmask of the modes it supports.
> >>
> >> This is not a bitmask property anymore, you've just changed it to an enum.
> >> The commit message is now misleading.
> >>
> >>> +static const struct drm_prop_enum_list drm_tv_mode_enum_list[] = {
> >>> +    { DRM_MODE_TV_MODE_NTSC_443, "NTSC-443" },
> >>> +    { DRM_MODE_TV_MODE_NTSC_J, "NTSC-J" },
> >>> +    { DRM_MODE_TV_MODE_NTSC_M, "NTSC-M" },
> >>> +    { DRM_MODE_TV_MODE_PAL_60, "PAL-60" },
> >>> +    { DRM_MODE_TV_MODE_PAL_B, "PAL-B" },
> >>> +    { DRM_MODE_TV_MODE_PAL_D, "PAL-D" },
> >>> +    { DRM_MODE_TV_MODE_PAL_G, "PAL-G" },
> >>> +    { DRM_MODE_TV_MODE_PAL_H, "PAL-H" },
> >>> +    { DRM_MODE_TV_MODE_PAL_I, "PAL-I" },
> >>> +    { DRM_MODE_TV_MODE_PAL_M, "PAL-M" },
> >>> +    { DRM_MODE_TV_MODE_PAL_N, "PAL-N" },
> >>> +    { DRM_MODE_TV_MODE_PAL_NC, "PAL-Nc" },
> >>> +    { DRM_MODE_TV_MODE_SECAM_60, "SECAM-60" },
> >>> +    { DRM_MODE_TV_MODE_SECAM_B, "SECAM-B" },
> >>> +    { DRM_MODE_TV_MODE_SECAM_D, "SECAM-D" },
> >>> +    { DRM_MODE_TV_MODE_SECAM_G, "SECAM-G" },
> >>> +    { DRM_MODE_TV_MODE_SECAM_K, "SECAM-K" },
> >>> +    { DRM_MODE_TV_MODE_SECAM_K1, "SECAM-K1" },
> >>> +    { DRM_MODE_TV_MODE_SECAM_L, "SECAM-L" },
> >>> +};
> >>
> >> I did not comment on it the last time, but this list looks a little bit random.
> >>
> >> Compared to the standards defined by V4L2, you also define SECAM-60 (a good
> >> thing to define, because why not), but don't define PAL-B1, PAL-D1, PAL-K,
> >> SECAM-H, SECAM-LC (whatever that is - probably just another name for SECAM-L,
> >> see my comment about PAL-Nc below), or NTSC-M-KR (a Korean variant of NTSC).
> >>
> >> Like I mentioned previously, I'm personally not a fan of including all those
> >> CCIR/ITU system variants, as they don't mean any difference to the output unless
> >> there is an RF modulator involved. But I get it that they have already been used
> >> and regressing probably wouldn't be a very good idea. But in that case keeping
> >> it consistent with the set of values used by V4L2 would be wise, I think.
> >
> > Ack. What would be the list of standards we'd absolutely need? NSTC-M,
> > NTSC-J, PAL-60, PAL-B, PAL-M, SECAM-60 and SECAM-B?
> 
> The "essential list" IMO is NTSC, NTSC-J, NTSC-443, PAL, PAL-M, PAL-N and SECAM.
> Note that:
> 
> - I intentionally propose "NTSC", "PAL" and "SECAM" without an ITU system
>   designation. If we only consider composite signals, there's no difference
>   between e.g. PAL-B, PAL-D and PAL-I, so it's better to label it as a generic
>   mode, IMO.
> 
>   * PAL-M and PAL-N are different, because those unique color encodings were
>     only ever used with Systems M and N, respectively.
> 
>   * NTSC-J is also different, because "System J" doesn't exist anywhere in ITU
>     documents. Japan technically uses System M with a non-standard black level.
>     But "NTSC-J" stuck as a universally recognized name for that variant.
> 
> - I intentionally did not list PAL-60 or SECAM-60. TBH... PAL-60 is just
>   regular PAL paired with 480i60 modeline. Most if not all displays that
>   accept PAL-60 input will just label it as "PAL". If we are not introducing
>   strict modeline validation, then maybe separating PAL and PAL-60 isn't really
>   necessary? Same goes for SECAM vs. SECAM-60.
>  
>   ...and same goes for NTSC vs. NTSC-50 a.k.a NTSC-N, which is a very exotic
>   mode, but known to exist at least in the Atari ST world, see also:
>   https://en.wikipedia.org/wiki/NTSC#NTSC-N/NTSC50
> 
> Combining PAL and PAL-60 into a single setting would complicate the vc4 driver
> a little bit, though, as the registers need to be set up differently for those.
> 
> My feelings about the PAL-60 issue are not that strong, though. Merging PAL
> and PAL-60 in this context is just a loose suggestion, I won't even try to
> argue if you disagree.

Ack

> >>> +/**
> >>> + * drm_mode_create_tv_properties - create TV specific connector properties
> >>> + * @dev: DRM device
> >>> + * @supported_tv_modes: Bitmask of TV modes supported (See DRM_MODE_TV_MODE_*)
> >>> +
> >>> + * Called by a driver's TV initialization routine, this function creates
> >>> + * the TV specific connector properties for a given device.  Caller is
> >>> + * responsible for allocating a list of format names and passing them to
> >>> + * this routine.
> >>> + *
> >>> + * Returns:
> >>> + * 0 on success or a negative error code on failure.
> >>> + */
> >>> +int drm_mode_create_tv_properties(struct drm_device *dev,
> >>> +                  unsigned int supported_tv_modes)
> >>
> >> supported_tv_modes is supposed to be a bitmask of BIT(DRM_MODE_TV_MODE_*)
> >> (or (1<<DRM_MODE_TV_MODE_*)) rather than DRM_MODE_TV_MODE_* directly, but this
> >> is not said explicitly anywhere in this doc comment.
> >
> > The argument doc mentions that it's a "Bitmask of TV modes supported
> > (See DRM_MODE_TV_MODE_*)", how would you improve it?
> 
> Maybe something like "Bitwise OR of BIT(DRM_MODE_TV_MODE_*) values"? Or maybe
> just add a little usage example?

This is the way we're usually documenting it in DRM:
https://elixir.bootlin.com/linux/latest/source/drivers/gpu/drm/drm_plane.c#L357
https://elixir.bootlin.com/linux/latest/source/drivers/gpu/drm/drm_crtc.c#L861
https://elixir.bootlin.com/linux/latest/source/drivers/gpu/drm/drm_blend.c#L546

So I'd rather keep it consistent

Maxime

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

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

* Re: [PATCH v2 10/41] drm/modes: Add a function to generate analog display modes
  2022-09-07 21:31           ` Mateusz Kwiatkowski
@ 2022-09-09 13:54             ` Maxime Ripard
  2022-09-11  4:48               ` Mateusz Kwiatkowski
  2022-09-09 14:00             ` Maxime Ripard
  1 sibling, 1 reply; 128+ messages in thread
From: Maxime Ripard @ 2022-09-09 13:54 UTC (permalink / raw)
  To: Mateusz Kwiatkowski
  Cc: Ben Skeggs, David Airlie, Chen-Yu Tsai, Thomas Zimmermann,
	Jani Nikula, Lyude Paul, Philipp Zabel, Maarten Lankhorst,
	Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec, Samuel Holland,
	Karol Herbst, Noralf Trønnes, Emma Anholt, Daniel Vetter,
	Joonas Lahtinen, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Geert Uytterhoeven

[-- Attachment #1: Type: text/plain, Size: 7126 bytes --]

Hi,

On Wed, Sep 07, 2022 at 11:31:21PM +0200, Mateusz Kwiatkowski wrote:
> W dniu 7.09.2022 o 16:34, Maxime Ripard pisze:
> > On Mon, Sep 05, 2022 at 06:44:42PM +0200, Mateusz Kwiatkowski wrote:
> >> Hi Maxime,
> >>
> >> W dniu 5.09.2022 o 15:37, Maxime Ripard pisze:
> >>>>> +    vfp = vfp_min + (porches_rem / 2);
> >>>>> +    vbp = porches - vfp;
> >>>>
> >>>> Relative position of the vertical sync within the VBI effectively moves the
> >>>> image up and down. Adding that (porches_rem / 2) moves the image up off center
> >>>> by that many pixels. I'd keep the VFP always at minimum to keep the image
> >>>> centered.
> >>>
> >>> And you would increase the back porch only then?
> >>
> >> Well, increasing vbp only gives a centered image with the default 480i/576i
> >> resolutions. However, only ever changing vbp will cause the image to be always
> >> at the bottom of the screen when the active line count is decreased (e.g.
> >> setting the resolution to 720x480 but for 50Hz "PAL" - like many game consoles
> >> did back in the day).
> >>
> >> I believe that the perfect solution would:
> >>
> >> - Use the canonical / standard-defined blanking line counts for the standard
> >>   vertical resolutions (480/486/576)
> >> - Increase vfp and vbp from there by the same number if a smaller number of
> >>   active lines is specified, so that the resulting image is centered
> >> - Likewise, decrease vfp and vbp by the same number if the active line number
> >>   is larger and there is still leeway (this should allow for seamless handling
> >>   of 480i vs. 486i for 60 Hz "NTSC")
> >
> > I'm not sure I understand how that's any different than the code you
> > initially commented on.
> >
> > I would start by taking the entire blanking area, remove the sync
> > period. We only have the two porches now, and I'm starting from the
> > minimum, adding as many pixels in both (unless it's not an even number,
> > in which case the backporch will have the extra pixel).
> >
> > Isn't it the same thing?
> > [...]
> > Unless you only want me to consider the front porch maximum?
> 
> I think you're confusing the "post-equalizing pulses" with the "vertical back
> porch" a little bit. The "vertical back porch" includes both the post-equalizing
> pulses and the entire rest of the VBI period, for the standard resolutions at
> least.
> 
> The "canonical" modelines (at least for vc4's VEC, see the notes below):
> 
> - (vfp==4, vsync==6, vbp==39) for 576i
> - (vfp==7, vsync==6, vbp==32) for 480i
> - (vfp==5, vsync==6, vbp==28) for 486i (full frame NTSC as originally specified)
> 
> The numbers for vfp don't exactly match the theoretical values, because:
> 
> - VEC actually adds a half-line pulse on top of VFP_ODD, and in the 625-line
>   mode also on top of VFP_EVEN (not always, but let's not dwell too much)
> - Conversely, VEC subtracts the half-line pulse from VSYNC_ODD and VSYNC_EVEN
>   in the 625-line mode
> - SMPTE S170M (see https://www.itu.int/rec/R-REC-BT.1700-0-200502-I/en) defines
>   that active picture for NTSC is on lines 21-263 and 283-525; 263 and 283 are
>   half-lines that are represented as full lines in the "486i" spec

It's going to be a bit difficult to match that into a drm_display_mode,
since as far I understand it, all the timings are the sum of the timings
of both fields in interlaced. I guess we'll have to be close enough.

> - SMPTE 314M, which is the spec for DV, defines the 480 active lines as lines
>   23-262 and 285-524; see Table 20 on page 26 in
>   https://last.hit.bme.hu/download/firtha/video/SMPTE/SMPTE-314M%20DV25-50.pdf;
>   this means that the standard 480i frame shaves off four topmost and two
>   bottommost lines (2 and 1 per field) of the 486i full frame

I'm still struggling a bit to match that into front porch, sync period
and back porch. I guess the sync period is easy since it's pretty much
fixed. That line 0-23 is the entire blanking area though, right?

> Note that the half-line pulses in vfp/vsync may be generated in a different way
> on encoders other than vc4's VEC. Maybe we should define some concrete
> semantics for vfp/vsync in analog TV modes, and compensate for that in the
> drivers. But anyway, that's a separate issue.
> 
> My point is that, to get a centered image, you can then proportionately add
> values to those "canonical" vfp/vbp values. For example if someone specifies
> 720x480 frame, but 50 Hz PAL, you should set (vfp==52, vsync==6, vbp==87).

In this case, you add 48 both front porches, right? How is that
proportionate?

> Those extra vbp lines will be treated as a black bar at the top of the frame,
> and extra vfp lines will be at the bottom of the frame.
> 
> However if someone specifies e.g. 720x604, there's nothing more you could
> remove from vfp, so your only option is to reduce vbp compared to the standard
> mode, so you'll end up with (vfp==4, vsync==6, vbp==11). The image will not be
> centered, the topmost lines will get cropped out, but that's the best we can do
> and if someone is requesting such resolution, they most likely want to actually
> access the VBI to e.g. emit teletext.
> 
> Your current code always starts at (vfp==5 or 6, vsync=6, vbp==6) and then
> increases both vfp and vbp proportionately. This puts vsync dead center in the
> VBI, which is not how it's supposed to be - and that in turn causes the image
> to be significantly shifted upwards.
> 
> I hope this makes more sense to you now.

I'm really struggling with this, so thanks for explaining this further
(and patiently ;))

If I get this right, what you'd like to change is this part of the
calculus (simplified a bit, and using PAL, 576i):

  vfp_min = params->vfp_lines.even + params->vfp_lines.odd; // 5
  vbp_min = params->vbp_lines.even + params->vbp_lines.odd; // 6
  vslen = params->vslen_lines.even + params->vslen_lines.odd; // 6

  porches = params->num_lines - vactive - vslen; // 43
  porches_rem = porches - vfp_min - vbp_min; // 32

  vfp = vfp_min + (porches_rem / 2); // 21
  vbp = porches - vfp; // 22

Which is indeed having sync centered.

I initially changed it to:

  vfp = vfp_min; // 6
  vbp = num_lines - vactive - vslen - vfp; // 38

Which is close enough for 576i, but at 480i/50Hz would end up with 134,
so still fairly far off.

I guess your suggestion would be along the line of:

  vfp_min = params->vfp_lines.even + params->vfp_lines.odd; // 5
  vbp_min = params->vbp_lines.even + params->vbp_lines.odd; // 38
  vslen = params->vslen_lines.even + params->vslen_lines.odd; // 6

  porches = params->num_lines - vactive - vslen; // 0
  porches_rem = porches - vfp_min - vbp_min; // 0

  vfp = vfp_min + (porches_rem / 2); // 5
  vbp = porches - vfp; // 38

Which is still close enough for 576i, but for 480i would end up with:

  porches = params->num_lines - vactive - vslen; // 139
  porches_rem = porches - vfp_min - vbp_min; // 96

  vfp = vfp_min + (porches_rem / 2); // 53
  vbp = porches - vfp; // 86

Right?

Maxime

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

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

* Re: [PATCH v2 10/41] drm/modes: Add a function to generate analog display modes
  2022-09-07 21:31           ` Mateusz Kwiatkowski
  2022-09-09 13:54             ` Maxime Ripard
@ 2022-09-09 14:00             ` Maxime Ripard
  2022-09-11  4:30               ` kFYatek
  1 sibling, 1 reply; 128+ messages in thread
From: Maxime Ripard @ 2022-09-09 14:00 UTC (permalink / raw)
  To: Mateusz Kwiatkowski
  Cc: Ben Skeggs, David Airlie, Chen-Yu Tsai, Thomas Zimmermann,
	Jani Nikula, Lyude Paul, Philipp Zabel, Maarten Lankhorst,
	Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec, Samuel Holland,
	Karol Herbst, Noralf Trønnes, Emma Anholt, Daniel Vetter,
	Joonas Lahtinen, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Geert Uytterhoeven

[-- Attachment #1: Type: text/plain, Size: 395 bytes --]

On Wed, Sep 07, 2022 at 11:31:21PM +0200, Mateusz Kwiatkowski wrote:
> The "canonical" modelines (at least for vc4's VEC, see the notes below):
> 
> - (vfp==4, vsync==6, vbp==39) for 576i
> - (vfp==7, vsync==6, vbp==32) for 480i
> - (vfp==5, vsync==6, vbp==28) for 486i (full frame NTSC as originally specified)

It's not clear to me either how you come up with those timings?

Maxime

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

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

* Re: [PATCH v2 00/41] drm: Analog TV Improvements
  2022-09-07 16:44         ` Noralf Trønnes
@ 2022-09-10 15:34           ` Noralf Trønnes
  2022-09-21 14:03           ` Maxime Ripard
  1 sibling, 0 replies; 128+ messages in thread
From: Noralf Trønnes @ 2022-09-10 15:34 UTC (permalink / raw)
  To: Stefan Wahren, Maxime Ripard, Dom Cobley
  Cc: Ben Skeggs, David Airlie, Chen-Yu Tsai, Thomas Zimmermann,
	Jani Nikula, Lyude Paul, Philipp Zabel, Maarten Lankhorst,
	Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec, Samuel Holland,
	Karol Herbst, Emma Anholt, Daniel Vetter, Joonas Lahtinen,
	Hans de Goede, linux-arm-kernel, Phil Elwell, intel-gfx,
	Dave Stevenson, dri-devel, linux-kernel, nouveau, linux-sunxi,
	Mateusz Kwiatkowski, Geert Uytterhoeven



Den 07.09.2022 18.44, skrev Noralf Trønnes:
> 
> 
> Den 07.09.2022 12.36, skrev Stefan Wahren:
>> Hi Maxime,
>>
>> Am 05.09.22 um 16:57 schrieb Maxime Ripard:
>>> On Fri, Sep 02, 2022 at 01:28:16PM +0200, Noralf Trønnes wrote:
>>>>
>>>> Den 01.09.2022 21.35, skrev Noralf Trønnes:
>>>>>
>>>>> I have finally found a workaround for my kernel hangs.
>>>>>
>>>>> Dom had a look at my kernel and found that the VideoCore was fine, and
>>>>> he said this:
>>>>>
>>>>>> That suggests cause of lockup was on arm side rather than VC side.
>>>>>>
>>>>>> But it's hard to diagnose further. Once you've had a peripheral not
>>>>>> respond, the AXI bus locks up and no further operations are possible.
>>>>>> Usual causes of this are required clocks being stopped or domains
>>>>>> disabled and then trying to access the hardware.
>>>>>>
>>>>> So when I got this on my 64-bit build:
>>>>>
>>>>> [  166.702171] SError Interrupt on CPU1, code 0x00000000bf000002 --
>>>>> SError
>>>>> [  166.702187] CPU: 1 PID: 8 Comm: kworker/u8:0 Tainted: G        W
>>>>>      5.19.0-rc6-00096-gba7973977976-dirty #1
>>>>> [  166.702200] Hardware name: Raspberry Pi 4 Model B Rev 1.1 (DT)
>>>>> [  166.702206] Workqueue: events_freezable_power_
>>>>> thermal_zone_device_check
>>>>> [  166.702231] pstate: 200000c5 (nzCv daIF -PAN -UAO -TCO -DIT -SSBS
>>>>> BTYPE=--)
>>>>> [  166.702242] pc : regmap_mmio_read32le+0x10/0x28
>>>>> [  166.702261] lr : regmap_mmio_read+0x44/0x70
>>>>> ...
>>>>> [  166.702606]  bcm2711_get_temp+0x58/0xb0 [bcm2711_thermal]
>>>>>
>>>>> I wondered if that reg read was stalled due to a clock being stopped.
>>>>>
>>>>> Lo and behold, disabling runtime pm and keeping the vec clock running
>>>>> all the time fixed it[1].
>>>>>
>>>>> I don't know what the problem is, but at least I can now test this
>>>>> patchset.
>>>>>
>>>>> [1] https://gist.github.com/notro/23b984e7fa05cfbda2db50a421cac065
>>>>>
>>>> It turns out I didn't have to disable runtime pm:
>>>> https://gist.github.com/notro/0adcfcb12460b54e54458afe11dc8ea2
>>> If the bcm2711_thermal IP needs that clock to be enabled, it should grab
>>> a reference itself, but it looks like even the device tree binding
>>> doesn't ask for one.
>> The missing clock in the device tree binding is expected, because
>> despite of the code there is not much information about the BCM2711
>> clock tree. But i'm skeptical that the AVS IP actually needs the VEC
>> clock, i think it's more likely that the VEC clock parent is changed and
>> that cause this issue. I could take care of the bcm2711 binding & driver
>> if i know which clock is really necessary.
> 
> Seems you're right, keeping the parent always enabled is enough:
> 
> 	clk_prepare_enable(clk_get_parent(vec->clock)); // pllc_per
> 
> I tried enabling just the grandparent clock as well, but that didn't help.
> 
> Without the clock hack it seems the hang occurs when switching between
> NTSC and PAL, at most I've been able to do that 4-5 times before it hangs.
> 
> For a while it looked like fbdev/fbcon had a play in this, but then I
> realised that it just gave me a NTSC mode to start from and to go back
> to when qutting modetest.
> 

I've looked some more into this problem and I see that downstream is
using a firmware clock for vec:

clk: Move vec clock to clk-raspberrypi
https://github.com/raspberrypi/linux/pull/4639

If I do the same my problem goes away.

It's interesting to note that on downstream 5.10.103-v7l+ #1530,
pllc_per is enabled even if tvout is not enabled:

$ sudo cat /sys/kernel/debug/clk/pllc_per/regdump
cm = 0x00000000
a2w = 0x00000004 (disable bit(8) is not set)

It's when mainline vc4_vec disables this vec parent clock that the crash
occurs.

Sidenote: Another downstream fw clock change with a vec reference[1]:


Another issue not related to the clock crash problem:

I assumed that unloading the vc4 module would release the clocks, but
this didn't happen.

When I looked at it I remembered that there's a catch in the DRM unplug
machinery when it comes to unloading a driver and the DRM disable hooks.

static void vc4_drm_unbind(struct device *dev)
{
	struct drm_device *drm = dev_get_drvdata(dev);

	drm_dev_unplug(drm);
	drm_atomic_helper_shutdown(drm);
}

Here the drm_device is first marked as unplugged and then the pipeline
is disabled. Since vc4_vec_encoder_disable() is protected by
drm_dev_enter() the VEC is not disabled, clocks are not released and PM
is left on.

In the drivers that I have written where the hardware is not expected to
have gone away on device unbind (SPI), I've just left out the
drm_dev_enter() check in the disable hook.

Noralf.

[1] https://github.com/raspberrypi/linux/pull/4706

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

* Re: [PATCH v2 10/41] drm/modes: Add a function to generate analog display modes
  2022-09-09 14:00             ` Maxime Ripard
@ 2022-09-11  4:30               ` kFYatek
  2022-09-21 14:26                 ` Maxime Ripard
  0 siblings, 1 reply; 128+ messages in thread
From: kFYatek @ 2022-09-11  4:30 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Ben Skeggs, David Airlie, Chen-Yu Tsai, Thomas Zimmermann,
	Jani Nikula, Lyude Paul, Philipp Zabel, Maarten Lankhorst,
	Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec, Samuel Holland,
	Karol Herbst, Noralf Trønnes, Emma Anholt, Daniel Vetter,
	Joonas Lahtinen, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Geert Uytterhoeven

Hi Maxime,

W dniu 9.09.2022 o 16:00, Maxime Ripard pisze:
> On Wed, Sep 07, 2022 at 11:31:21PM +0200, Mateusz Kwiatkowski wrote:
>> The "canonical" modelines (at least for vc4's VEC, see the notes below):
>>
>> - (vfp==4, vsync==6, vbp==39) for 576i
>> - (vfp==7, vsync==6, vbp==32) for 480i
>> - (vfp==5, vsync==6, vbp==28) for 486i (full frame NTSC as originally specified)
>
> It's not clear to me either how you come up with those timings?

Well, experimentally ;)

The values for 480i and 576i are the values currently used by the downstream
kernel, and those in turn has been copied from the firmware (or more precisely,
I chose them so that the PV registers end up the same as the values set by the
firmware).

I also checked with an oscilloscope that the waveforms look as they should.
VEC doesn't exactly handle the half-lines at the start and end of the odd field
right, but otherwise, the blanking and sync pulses are where they should be.

The 486i values has been constructed from the 480i ones according to the
calculations from cross-referencing SMPTE documents, see my previous e-mail.

I know this is perhaps unsatisfactory ;) I don't have access to the VC4
documentation, so this was _almost_ reverse engineering for me.

Best regards,
Mateusz Kwiatkowski

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

* Re: [PATCH v2 09/41] drm/connector: Add TV standard property
  2022-09-09  9:46         ` Maxime Ripard
@ 2022-09-11  4:32           ` Mateusz Kwiatkowski
  0 siblings, 0 replies; 128+ messages in thread
From: Mateusz Kwiatkowski @ 2022-09-11  4:32 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Ben Skeggs, David Airlie, Chen-Yu Tsai, Thomas Zimmermann,
	Jani Nikula, Lyude Paul, Philipp Zabel, Maarten Lankhorst,
	Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec, Samuel Holland,
	Karol Herbst, Noralf Trønnes, Emma Anholt, Daniel Vetter,
	Joonas Lahtinen, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Geert Uytterhoeven

W dniu 9.09.2022 o 11:46, Maxime Ripard pisze:
> On Wed, Sep 07, 2022 at 09:52:09PM +0200, Mateusz Kwiatkowski wrote:
>> W dniu 7.09.2022 o 14:10, Maxime Ripard pisze:
>>> Hi,
>>>
>>> On Fri, Sep 02, 2022 at 12:00:33AM +0200, Mateusz Kwiatkowski wrote:
>>>> W dniu 29.08.2022 o 15:11, Maxime Ripard pisze:
>>>>> The TV mode property has been around for a while now to select and get the
>>>>> current TV mode output on an analog TV connector.
>>>>>
>>>>> Despite that property name being generic, its content isn't and has been
>>>>> driver-specific which makes it hard to build any generic behaviour on top
>>>>> of it, both in kernel and user-space.
>>>>>
>>>>> Let's create a new bitmask tv norm property, that can contain any of the
>>>>> analog TV standards currently supported by kernel drivers. Each driver can
>>>>> then pass in a bitmask of the modes it supports.
>>>>
>>>> This is not a bitmask property anymore, you've just changed it to an enum.
>>>> The commit message is now misleading.
>>>>
>>>>> +static const struct drm_prop_enum_list drm_tv_mode_enum_list[] = {
>>>>> +    { DRM_MODE_TV_MODE_NTSC_443, "NTSC-443" },
>>>>> +    { DRM_MODE_TV_MODE_NTSC_J, "NTSC-J" },
>>>>> +    { DRM_MODE_TV_MODE_NTSC_M, "NTSC-M" },
>>>>> +    { DRM_MODE_TV_MODE_PAL_60, "PAL-60" },
>>>>> +    { DRM_MODE_TV_MODE_PAL_B, "PAL-B" },
>>>>> +    { DRM_MODE_TV_MODE_PAL_D, "PAL-D" },
>>>>> +    { DRM_MODE_TV_MODE_PAL_G, "PAL-G" },
>>>>> +    { DRM_MODE_TV_MODE_PAL_H, "PAL-H" },
>>>>> +    { DRM_MODE_TV_MODE_PAL_I, "PAL-I" },
>>>>> +    { DRM_MODE_TV_MODE_PAL_M, "PAL-M" },
>>>>> +    { DRM_MODE_TV_MODE_PAL_N, "PAL-N" },
>>>>> +    { DRM_MODE_TV_MODE_PAL_NC, "PAL-Nc" },
>>>>> +    { DRM_MODE_TV_MODE_SECAM_60, "SECAM-60" },
>>>>> +    { DRM_MODE_TV_MODE_SECAM_B, "SECAM-B" },
>>>>> +    { DRM_MODE_TV_MODE_SECAM_D, "SECAM-D" },
>>>>> +    { DRM_MODE_TV_MODE_SECAM_G, "SECAM-G" },
>>>>> +    { DRM_MODE_TV_MODE_SECAM_K, "SECAM-K" },
>>>>> +    { DRM_MODE_TV_MODE_SECAM_K1, "SECAM-K1" },
>>>>> +    { DRM_MODE_TV_MODE_SECAM_L, "SECAM-L" },
>>>>> +};
>>>>
>>>> I did not comment on it the last time, but this list looks a little bit random.
>>>>
>>>> Compared to the standards defined by V4L2, you also define SECAM-60 (a good
>>>> thing to define, because why not), but don't define PAL-B1, PAL-D1, PAL-K,
>>>> SECAM-H, SECAM-LC (whatever that is - probably just another name for SECAM-L,
>>>> see my comment about PAL-Nc below), or NTSC-M-KR (a Korean variant of NTSC).
>>>>
>>>> Like I mentioned previously, I'm personally not a fan of including all those
>>>> CCIR/ITU system variants, as they don't mean any difference to the output unless
>>>> there is an RF modulator involved. But I get it that they have already been used
>>>> and regressing probably wouldn't be a very good idea. But in that case keeping
>>>> it consistent with the set of values used by V4L2 would be wise, I think.
>>>
>>> Ack. What would be the list of standards we'd absolutely need? NSTC-M,
>>> NTSC-J, PAL-60, PAL-B, PAL-M, SECAM-60 and SECAM-B?
>>
>> The "essential list" IMO is NTSC, NTSC-J, NTSC-443, PAL, PAL-M, PAL-N and SECAM.
>> Note that:
>>
>> - I intentionally propose "NTSC", "PAL" and "SECAM" without an ITU system
>>   designation. If we only consider composite signals, there's no difference
>>   between e.g. PAL-B, PAL-D and PAL-I, so it's better to label it as a generic
>>   mode, IMO.
>>
>>   * PAL-M and PAL-N are different, because those unique color encodings were
>>     only ever used with Systems M and N, respectively.
>>
>>   * NTSC-J is also different, because "System J" doesn't exist anywhere in ITU
>>     documents. Japan technically uses System M with a non-standard black level.
>>     But "NTSC-J" stuck as a universally recognized name for that variant.
>>
>> - I intentionally did not list PAL-60 or SECAM-60. TBH... PAL-60 is just
>>   regular PAL paired with 480i60 modeline. Most if not all displays that
>>   accept PAL-60 input will just label it as "PAL". If we are not introducing
>>   strict modeline validation, then maybe separating PAL and PAL-60 isn't really
>>   necessary? Same goes for SECAM vs. SECAM-60.
>>  
>>   ...and same goes for NTSC vs. NTSC-50 a.k.a NTSC-N, which is a very exotic
>>   mode, but known to exist at least in the Atari ST world, see also:
>>   https://en.wikipedia.org/wiki/NTSC#NTSC-N/NTSC50
>>
>> Combining PAL and PAL-60 into a single setting would complicate the vc4 driver
>> a little bit, though, as the registers need to be set up differently for those.
>>
>> My feelings about the PAL-60 issue are not that strong, though. Merging PAL
>> and PAL-60 in this context is just a loose suggestion, I won't even try to
>> argue if you disagree.
>
> Ack
>
>>>>> +/**
>>>>> + * drm_mode_create_tv_properties - create TV specific connector properties
>>>>> + * @dev: DRM device
>>>>> + * @supported_tv_modes: Bitmask of TV modes supported (See DRM_MODE_TV_MODE_*)
>>>>> +
>>>>> + * Called by a driver's TV initialization routine, this function creates
>>>>> + * the TV specific connector properties for a given device.  Caller is
>>>>> + * responsible for allocating a list of format names and passing them to
>>>>> + * this routine.
>>>>> + *
>>>>> + * Returns:
>>>>> + * 0 on success or a negative error code on failure.
>>>>> + */
>>>>> +int drm_mode_create_tv_properties(struct drm_device *dev,
>>>>> +                  unsigned int supported_tv_modes)
>>>>
>>>> supported_tv_modes is supposed to be a bitmask of BIT(DRM_MODE_TV_MODE_*)
>>>> (or (1<<DRM_MODE_TV_MODE_*)) rather than DRM_MODE_TV_MODE_* directly, but this
>>>> is not said explicitly anywhere in this doc comment.
>>>
>>> The argument doc mentions that it's a "Bitmask of TV modes supported
>>> (See DRM_MODE_TV_MODE_*)", how would you improve it?
>>
>> Maybe something like "Bitwise OR of BIT(DRM_MODE_TV_MODE_*) values"? Or maybe
>> just add a little usage example?
>
> This is the way we're usually documenting it in DRM:
> https://elixir.bootlin.com/linux/latest/source/drivers/gpu/drm/drm_plane.c#L357
> https://elixir.bootlin.com/linux/latest/source/drivers/gpu/drm/drm_crtc.c#L861
> https://elixir.bootlin.com/linux/latest/source/drivers/gpu/drm/drm_blend.c#L546
>
> So I'd rather keep it consistent
>
> Maxime

Ack, OK then.

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

* Re: [PATCH v2 10/41] drm/modes: Add a function to generate analog display modes
  2022-09-09 13:54             ` Maxime Ripard
@ 2022-09-11  4:48               ` Mateusz Kwiatkowski
  2022-09-11  4:51                 ` Mateusz Kwiatkowski
  2022-09-21 15:05                 ` Maxime Ripard
  0 siblings, 2 replies; 128+ messages in thread
From: Mateusz Kwiatkowski @ 2022-09-11  4:48 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Ben Skeggs, David Airlie, Chen-Yu Tsai, Thomas Zimmermann,
	Jani Nikula, Lyude Paul, Philipp Zabel, Maarten Lankhorst,
	Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec, Samuel Holland,
	Karol Herbst, Noralf Trønnes, Emma Anholt, Daniel Vetter,
	Joonas Lahtinen, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Geert Uytterhoeven

Hi Maxime,

W dniu 9.09.2022 o 15:54, Maxime Ripard pisze:
> Hi,
>
> On Wed, Sep 07, 2022 at 11:31:21PM +0200, Mateusz Kwiatkowski wrote:
> [...]
>> I think you're confusing the "post-equalizing pulses" with the "vertical back
>> porch" a little bit. The "vertical back porch" includes both the post-equalizing
>> pulses and the entire rest of the VBI period, for the standard resolutions at
>> least.
>>
>> The "canonical" modelines (at least for vc4's VEC, see the notes below):
>>
>> - (vfp==4, vsync==6, vbp==39) for 576i
>> - (vfp==7, vsync==6, vbp==32) for 480i
>> - (vfp==5, vsync==6, vbp==28) for 486i (full frame NTSC as originally specified)
>>
>> The numbers for vfp don't exactly match the theoretical values, because:
>>
>> - VEC actually adds a half-line pulse on top of VFP_ODD, and in the 625-line
>>   mode also on top of VFP_EVEN (not always, but let's not dwell too much)
>> - Conversely, VEC subtracts the half-line pulse from VSYNC_ODD and VSYNC_EVEN
>>   in the 625-line mode
>> - SMPTE S170M (see https://www.itu.int/rec/R-REC-BT.1700-0-200502-I/en) defines
>>   that active picture for NTSC is on lines 21-263 and 283-525; 263 and 283 are
>>   half-lines that are represented as full lines in the "486i" spec
>
> It's going to be a bit difficult to match that into a drm_display_mode,
> since as far I understand it, all the timings are the sum of the timings
> of both fields in interlaced. I guess we'll have to be close enough.

Well, it's probably the job of the CRTC driver to split the values from
drm_display_mode back into separate values for odd and even fields. That's how
it's done in the vc4 driver, anyway.

>
>> - SMPTE 314M, which is the spec for DV, defines the 480 active lines as lines
>>   23-262 and 285-524; see Table 20 on page 26 in
>>   https://last.hit.bme.hu/download/firtha/video/SMPTE/SMPTE-314M%20DV25-50.pdf;
>>   this means that the standard 480i frame shaves off four topmost and two
>>   bottommost lines (2 and 1 per field) of the 486i full frame
>
> I'm still struggling a bit to match that into front porch, sync period
> and back porch. I guess the sync period is easy since it's pretty much
> fixed. That line 0-23 is the entire blanking area though, right?

Yes, lines 0-23 is the entire blanking area. And the "back porch" in this
context is everything from the start of the sync pulse to the start of active
video. It's not just the equalizing pulses.

The equalizing pulses have no equivalent in DRM terms. VC4/VEC inserts those
automatically and there's no direct control over them, I'm not sure about other
encoders.

The equalizing pulses are also not essential for the composite video to work.
The spec requires them, but most TVs will tolerate them not being there (and
early systems like the British 405-line system didn't have any).

>> Note that the half-line pulses in vfp/vsync may be generated in a different way
>> on encoders other than vc4's VEC. Maybe we should define some concrete
>> semantics for vfp/vsync in analog TV modes, and compensate for that in the
>> drivers. But anyway, that's a separate issue.
>>
>> My point is that, to get a centered image, you can then proportionately add
>> values to those "canonical" vfp/vbp values. For example if someone specifies
>> 720x480 frame, but 50 Hz PAL, you should set (vfp==52, vsync==6, vbp==87).
>
> In this case, you add 48 both front porches, right? How is that
> proportionate?

Yes, I meant adding 48 lines to both porches, and I meant "proportionately" as
"split equally". Maybe that was an unfortunate choice of words.

>> Those extra vbp lines will be treated as a black bar at the top of the frame,
>> and extra vfp lines will be at the bottom of the frame.
>>
>> However if someone specifies e.g. 720x604, there's nothing more you could
>> remove from vfp, so your only option is to reduce vbp compared to the standard
>> mode, so you'll end up with (vfp==4, vsync==6, vbp==11). The image will not be
>> centered, the topmost lines will get cropped out, but that's the best we can do
>> and if someone is requesting such resolution, they most likely want to actually
>> access the VBI to e.g. emit teletext.
>>
>> Your current code always starts at (vfp==5 or 6, vsync=6, vbp==6) and then
>> increases both vfp and vbp proportionately. This puts vsync dead center in the
>> VBI, which is not how it's supposed to be - and that in turn causes the image
>> to be significantly shifted upwards.
>>
>> I hope this makes more sense to you now.
>
> I'm really struggling with this, so thanks for explaining this further
> (and patiently ;))
>
> If I get this right, what you'd like to change is this part of the
> calculus (simplified a bit, and using PAL, 576i):
>
>   vfp_min = params->vfp_lines.even + params->vfp_lines.odd; // 5
>   vbp_min = params->vbp_lines.even + params->vbp_lines.odd; // 6
>   vslen = params->vslen_lines.even + params->vslen_lines.odd; // 6
>
>   porches = params->num_lines - vactive - vslen; // 43
>   porches_rem = porches - vfp_min - vbp_min; // 32
>
>   vfp = vfp_min + (porches_rem / 2); // 21
>   vbp = porches - vfp; // 22
>
> Which is indeed having sync centered.
>
> I initially changed it to:
>
>   vfp = vfp_min; // 6
>   vbp = num_lines - vactive - vslen - vfp; // 38
>
> Which is close enough for 576i, but at 480i/50Hz would end up with 134,
> so still fairly far off.
>
> I guess your suggestion would be along the line of:
>
>   vfp_min = params->vfp_lines.even + params->vfp_lines.odd; // 5
>   vbp_min = params->vbp_lines.even + params->vbp_lines.odd; // 38
>   vslen = params->vslen_lines.even + params->vslen_lines.odd; // 6
>
>   porches = params->num_lines - vactive - vslen; // 0
>   porches_rem = porches - vfp_min - vbp_min; // 0
>
>   vfp = vfp_min + (porches_rem / 2); // 5
>   vbp = porches - vfp; // 38
>
> Which is still close enough for 576i, but for 480i would end up with:
>
>   porches = params->num_lines - vactive - vslen; // 139
>   porches_rem = porches - vfp_min - vbp_min; // 96
>
>   vfp = vfp_min + (porches_rem / 2); // 53
>   vbp = porches - vfp; // 86
>
> Right?

Yes. And if that's supposed to mean 480i in 50 Hz "PAL" mode, that's also
"close enough" to the values I suggested above.

If you substitute values for true 60 Hz "NTSC" 480i, you should also get values
that are "close enough" to the official spec.

The only thing I'd conceptually change is that the 38 lines is not really
"vbp_min". It's more like "vbp_typ". As I mentioned above, we may want to lower
this value if someone wants more active lines than the official 486/576.
If they're doing that, they probably want to have vbp in the framebuffer,
like VBIT2.

Best regards,
Mateusz Kwiatkowski

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

* Re: [PATCH v2 10/41] drm/modes: Add a function to generate analog display modes
  2022-09-11  4:48               ` Mateusz Kwiatkowski
@ 2022-09-11  4:51                 ` Mateusz Kwiatkowski
  2022-09-21 15:05                 ` Maxime Ripard
  1 sibling, 0 replies; 128+ messages in thread
From: Mateusz Kwiatkowski @ 2022-09-11  4:51 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Ben Skeggs, David Airlie, Chen-Yu Tsai, Thomas Zimmermann,
	Jani Nikula, Lyude Paul, Philipp Zabel, Maarten Lankhorst,
	Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec, Samuel Holland,
	Karol Herbst, Noralf Trønnes, Emma Anholt, Daniel Vetter,
	Joonas Lahtinen, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Geert Uytterhoeven

> Yes, lines 0-23 is the entire blanking area. And the "back porch" in this
> context is everything from the start of the sync pulse to the start of active
> video. It's not just the equalizing pulses.

I meant "from the end of the sync pulse", obviously. Sorry about the slipup.

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

* Re: [PATCH v2 00/41] drm: Analog TV Improvements
  2022-09-07 16:44         ` Noralf Trønnes
  2022-09-10 15:34           ` Noralf Trønnes
@ 2022-09-21 14:03           ` Maxime Ripard
  2022-09-24 15:33             ` Noralf Trønnes
  1 sibling, 1 reply; 128+ messages in thread
From: Maxime Ripard @ 2022-09-21 14:03 UTC (permalink / raw)
  To: Noralf Trønnes
  Cc: Stefan Wahren, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec,
	Samuel Holland, Karol Herbst, Emma Anholt, Daniel Vetter,
	Joonas Lahtinen, Dom Cobley, Hans de Goede, linux-arm-kernel,
	Phil Elwell, intel-gfx, Dave Stevenson, dri-devel, linux-kernel,
	nouveau, linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven

[-- Attachment #1: Type: text/plain, Size: 4536 bytes --]

On Wed, Sep 07, 2022 at 06:44:53PM +0200, Noralf Trønnes wrote:
> 
> 
> Den 07.09.2022 12.36, skrev Stefan Wahren:
> > Hi Maxime,
> > 
> > Am 05.09.22 um 16:57 schrieb Maxime Ripard:
> >> On Fri, Sep 02, 2022 at 01:28:16PM +0200, Noralf Trønnes wrote:
> >>>
> >>> Den 01.09.2022 21.35, skrev Noralf Trønnes:
> >>>>
> >>>> I have finally found a workaround for my kernel hangs.
> >>>>
> >>>> Dom had a look at my kernel and found that the VideoCore was fine, and
> >>>> he said this:
> >>>>
> >>>>> That suggests cause of lockup was on arm side rather than VC side.
> >>>>>
> >>>>> But it's hard to diagnose further. Once you've had a peripheral not
> >>>>> respond, the AXI bus locks up and no further operations are possible.
> >>>>> Usual causes of this are required clocks being stopped or domains
> >>>>> disabled and then trying to access the hardware.
> >>>>>
> >>>> So when I got this on my 64-bit build:
> >>>>
> >>>> [  166.702171] SError Interrupt on CPU1, code 0x00000000bf000002 --
> >>>> SError
> >>>> [  166.702187] CPU: 1 PID: 8 Comm: kworker/u8:0 Tainted: G        W
> >>>>      5.19.0-rc6-00096-gba7973977976-dirty #1
> >>>> [  166.702200] Hardware name: Raspberry Pi 4 Model B Rev 1.1 (DT)
> >>>> [  166.702206] Workqueue: events_freezable_power_
> >>>> thermal_zone_device_check
> >>>> [  166.702231] pstate: 200000c5 (nzCv daIF -PAN -UAO -TCO -DIT -SSBS
> >>>> BTYPE=--)
> >>>> [  166.702242] pc : regmap_mmio_read32le+0x10/0x28
> >>>> [  166.702261] lr : regmap_mmio_read+0x44/0x70
> >>>> ...
> >>>> [  166.702606]  bcm2711_get_temp+0x58/0xb0 [bcm2711_thermal]
> >>>>
> >>>> I wondered if that reg read was stalled due to a clock being stopped.
> >>>>
> >>>> Lo and behold, disabling runtime pm and keeping the vec clock running
> >>>> all the time fixed it[1].
> >>>>
> >>>> I don't know what the problem is, but at least I can now test this
> >>>> patchset.
> >>>>
> >>>> [1] https://gist.github.com/notro/23b984e7fa05cfbda2db50a421cac065
> >>>>
> >>> It turns out I didn't have to disable runtime pm:
> >>> https://gist.github.com/notro/0adcfcb12460b54e54458afe11dc8ea2
> >> If the bcm2711_thermal IP needs that clock to be enabled, it should grab
> >> a reference itself, but it looks like even the device tree binding
> >> doesn't ask for one.
> > The missing clock in the device tree binding is expected, because
> > despite of the code there is not much information about the BCM2711
> > clock tree. But i'm skeptical that the AVS IP actually needs the VEC
> > clock, i think it's more likely that the VEC clock parent is changed and
> > that cause this issue. I could take care of the bcm2711 binding & driver
> > if i know which clock is really necessary.
> 
> Seems you're right, keeping the parent always enabled is enough:
> 
> 	clk_prepare_enable(clk_get_parent(vec->clock)); // pllc_per
> 
> I tried enabling just the grandparent clock as well, but that didn't help.

Yeah, adding tracing to the clock framework shows that it indeed
disables PLLC_PER. So there's probably some other device that depends on
it but doesn't take a reference to it.

I had a look, but it's not really obvious what that might be.

This patch makes sure that the PLL*_PER are never disabled, could you
test it? It seems to work for me.


diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
index 48a1eb9f2d55..3839261ee419 100644
--- a/drivers/clk/bcm/clk-bcm2835.c
+++ b/drivers/clk/bcm/clk-bcm2835.c
@@ -1675,7 +1675,7 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
 		.load_mask = CM_PLLA_LOADPER,
 		.hold_mask = CM_PLLA_HOLDPER,
 		.fixed_divider = 1,
-		.flags = CLK_SET_RATE_PARENT),
+		.flags = CLK_IS_CRITICAL | CLK_SET_RATE_PARENT),
 	[BCM2835_PLLA_DSI0]	= REGISTER_PLL_DIV(
 		SOC_ALL,
 		.name = "plla_dsi0",
@@ -1784,7 +1784,7 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
 		.load_mask = CM_PLLC_LOADPER,
 		.hold_mask = CM_PLLC_HOLDPER,
 		.fixed_divider = 1,
-		.flags = CLK_SET_RATE_PARENT),
+		.flags = CLK_IS_CRITICAL | CLK_SET_RATE_PARENT),

 	/*
 	 * PLLD is the display PLL, used to drive DSI display panels.
@@ -1891,7 +1891,7 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
 		.load_mask = CM_PLLH_LOADAUX,
 		.hold_mask = 0,
 		.fixed_divider = 1,
-		.flags = CLK_SET_RATE_PARENT),
+		.flags = CLK_IS_CRITICAL | CLK_SET_RATE_PARENT),
 	[BCM2835_PLLH_PIX]	= REGISTER_PLL_DIV(
 		SOC_BCM2835,
 		.name = "pllh_pix",


Maxime

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

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

* Re: [PATCH v2 10/41] drm/modes: Add a function to generate analog display modes
  2022-09-11  4:30               ` kFYatek
@ 2022-09-21 14:26                 ` Maxime Ripard
  0 siblings, 0 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-09-21 14:26 UTC (permalink / raw)
  To: kFYatek
  Cc: Ben Skeggs, David Airlie, Chen-Yu Tsai, Thomas Zimmermann,
	Jani Nikula, Lyude Paul, Philipp Zabel, Maarten Lankhorst,
	Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec, Samuel Holland,
	Karol Herbst, Noralf Trønnes, Emma Anholt, Daniel Vetter,
	Joonas Lahtinen, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Geert Uytterhoeven

[-- Attachment #1: Type: text/plain, Size: 1975 bytes --]

Hi,

Thanks again for your help

On Sun, Sep 11, 2022 at 06:30:39AM +0200, kFYatek wrote:
> W dniu 9.09.2022 o 16:00, Maxime Ripard pisze:
> > On Wed, Sep 07, 2022 at 11:31:21PM +0200, Mateusz Kwiatkowski wrote:
> >> The "canonical" modelines (at least for vc4's VEC, see the notes below):
> >>
> >> - (vfp==4, vsync==6, vbp==39) for 576i
> >> - (vfp==7, vsync==6, vbp==32) for 480i
> >> - (vfp==5, vsync==6, vbp==28) for 486i (full frame NTSC as originally specified)
> >
> > It's not clear to me either how you come up with those timings?
> 
> Well, experimentally ;)
> 
> The values for 480i and 576i are the values currently used by the downstream
> kernel, and those in turn has been copied from the firmware (or more precisely,
> I chose them so that the PV registers end up the same as the values set by the
> firmware).
> 
> I also checked with an oscilloscope that the waveforms look as they should.
> VEC doesn't exactly handle the half-lines at the start and end of the odd field
> right, but otherwise, the blanking and sync pulses are where they should be.
> 
> The 486i values has been constructed from the 480i ones according to the
> calculations from cross-referencing SMPTE documents, see my previous e-mail.
> 
> I know this is perhaps unsatisfactory ;) I don't have access to the VC4
> documentation, so this was _almost_ reverse engineering for me.

It's not really that it's unsatisfactory, but the function here is
supposed to be generic and thus generate a mode that is supposed to be a
somewhat reasonable for a given set of parameters.

If the vc4 driver needs some adjustments, then it needs to be out of
that function and into the vc4 driver. And this is pretty much what I
struggle with: I have a hard time (on top of everything else) figuring
out what is supposed to be specific to vc4, and what isn't.

I guess your 480i example, since it follows the spec, is fine, but I'm
not sure for 576i.
Maxime

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

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

* Re: [PATCH v2 10/41] drm/modes: Add a function to generate analog display modes
  2022-09-11  4:48               ` Mateusz Kwiatkowski
  2022-09-11  4:51                 ` Mateusz Kwiatkowski
@ 2022-09-21 15:05                 ` Maxime Ripard
  1 sibling, 0 replies; 128+ messages in thread
From: Maxime Ripard @ 2022-09-21 15:05 UTC (permalink / raw)
  To: Mateusz Kwiatkowski
  Cc: Ben Skeggs, David Airlie, Chen-Yu Tsai, Thomas Zimmermann,
	Jani Nikula, Lyude Paul, Philipp Zabel, Maarten Lankhorst,
	Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec, Samuel Holland,
	Karol Herbst, Noralf Trønnes, Emma Anholt, Daniel Vetter,
	Joonas Lahtinen, Hans de Goede, linux-arm-kernel, Phil Elwell,
	intel-gfx, Dave Stevenson, dri-devel, Dom Cobley, linux-kernel,
	nouveau, linux-sunxi, Geert Uytterhoeven

[-- Attachment #1: Type: text/plain, Size: 3533 bytes --]

Hi,

On Sun, Sep 11, 2022 at 06:48:50AM +0200, Mateusz Kwiatkowski wrote:
> >> Those extra vbp lines will be treated as a black bar at the top of the frame,
> >> and extra vfp lines will be at the bottom of the frame.
> >>
> >> However if someone specifies e.g. 720x604, there's nothing more you could
> >> remove from vfp, so your only option is to reduce vbp compared to the standard
> >> mode, so you'll end up with (vfp==4, vsync==6, vbp==11). The image will not be
> >> centered, the topmost lines will get cropped out, but that's the best we can do
> >> and if someone is requesting such resolution, they most likely want to actually
> >> access the VBI to e.g. emit teletext.
> >>
> >> Your current code always starts at (vfp==5 or 6, vsync=6, vbp==6) and then
> >> increases both vfp and vbp proportionately. This puts vsync dead center in the
> >> VBI, which is not how it's supposed to be - and that in turn causes the image
> >> to be significantly shifted upwards.
> >>
> >> I hope this makes more sense to you now.
> >
> > I'm really struggling with this, so thanks for explaining this further
> > (and patiently ;))
> >
> > If I get this right, what you'd like to change is this part of the
> > calculus (simplified a bit, and using PAL, 576i):
> >
> >   vfp_min = params->vfp_lines.even + params->vfp_lines.odd; // 5
> >   vbp_min = params->vbp_lines.even + params->vbp_lines.odd; // 6
> >   vslen = params->vslen_lines.even + params->vslen_lines.odd; // 6
> >
> >   porches = params->num_lines - vactive - vslen; // 43
> >   porches_rem = porches - vfp_min - vbp_min; // 32
> >
> >   vfp = vfp_min + (porches_rem / 2); // 21
> >   vbp = porches - vfp; // 22
> >
> > Which is indeed having sync centered.
> >
> > I initially changed it to:
> >
> >   vfp = vfp_min; // 6
> >   vbp = num_lines - vactive - vslen - vfp; // 38
> >
> > Which is close enough for 576i, but at 480i/50Hz would end up with 134,
> > so still fairly far off.
> >
> > I guess your suggestion would be along the line of:
> >
> >   vfp_min = params->vfp_lines.even + params->vfp_lines.odd; // 5
> >   vbp_min = params->vbp_lines.even + params->vbp_lines.odd; // 38
> >   vslen = params->vslen_lines.even + params->vslen_lines.odd; // 6
> >
> >   porches = params->num_lines - vactive - vslen; // 0
> >   porches_rem = porches - vfp_min - vbp_min; // 0
> >
> >   vfp = vfp_min + (porches_rem / 2); // 5
> >   vbp = porches - vfp; // 38
> >
> > Which is still close enough for 576i, but for 480i would end up with:
> >
> >   porches = params->num_lines - vactive - vslen; // 139
> >   porches_rem = porches - vfp_min - vbp_min; // 96
> >
> >   vfp = vfp_min + (porches_rem / 2); // 53
> >   vbp = porches - vfp; // 86
> >
> > Right?
> 
> Yes. And if that's supposed to mean 480i in 50 Hz "PAL" mode, that's also
> "close enough" to the values I suggested above.
> 
> If you substitute values for true 60 Hz "NTSC" 480i, you should also get values
> that are "close enough" to the official spec.
> 
> The only thing I'd conceptually change is that the 38 lines is not really
> "vbp_min". It's more like "vbp_typ". As I mentioned above, we may want to lower
> this value if someone wants more active lines than the official 486/576.

porches_rem is an int, so if vactive > (num_lines + vslen + vfp_min +
vbp_min), porches_rem is going to be negative and we'll remove equally
between vfp and vbp to match what's been asked

So I believe this should work fine?

Maxime

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

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

* Re: [PATCH v2 00/41] drm: Analog TV Improvements
  2022-09-21 14:03           ` Maxime Ripard
@ 2022-09-24 15:33             ` Noralf Trønnes
  0 siblings, 0 replies; 128+ messages in thread
From: Noralf Trønnes @ 2022-09-24 15:33 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Stefan Wahren, Ben Skeggs, David Airlie, Chen-Yu Tsai,
	Thomas Zimmermann, Jani Nikula, Lyude Paul, Philipp Zabel,
	Maarten Lankhorst, Rodrigo Vivi, Tvrtko Ursulin, Jernej Skrabec,
	Samuel Holland, Karol Herbst, Emma Anholt, Daniel Vetter,
	Joonas Lahtinen, Dom Cobley, Hans de Goede, linux-arm-kernel,
	Phil Elwell, intel-gfx, Dave Stevenson, dri-devel, linux-kernel,
	nouveau, linux-sunxi, Mateusz Kwiatkowski, Geert Uytterhoeven,
	Noralf Trønnes



Den 21.09.2022 16.03, skrev Maxime Ripard:
> On Wed, Sep 07, 2022 at 06:44:53PM +0200, Noralf Trønnes wrote:
>>
>>
>> Den 07.09.2022 12.36, skrev Stefan Wahren:
>>> Hi Maxime,
>>>
>>> Am 05.09.22 um 16:57 schrieb Maxime Ripard:
>>>> On Fri, Sep 02, 2022 at 01:28:16PM +0200, Noralf Trønnes wrote:
>>>>>
>>>>> Den 01.09.2022 21.35, skrev Noralf Trønnes:
>>>>>>
>>>>>> I have finally found a workaround for my kernel hangs.
>>>>>>
>>>>>> Dom had a look at my kernel and found that the VideoCore was fine, and
>>>>>> he said this:
>>>>>>
>>>>>>> That suggests cause of lockup was on arm side rather than VC side.
>>>>>>>
>>>>>>> But it's hard to diagnose further. Once you've had a peripheral not
>>>>>>> respond, the AXI bus locks up and no further operations are possible.
>>>>>>> Usual causes of this are required clocks being stopped or domains
>>>>>>> disabled and then trying to access the hardware.
>>>>>>>
>>>>>> So when I got this on my 64-bit build:
>>>>>>
>>>>>> [  166.702171] SError Interrupt on CPU1, code 0x00000000bf000002 --
>>>>>> SError
>>>>>> [  166.702187] CPU: 1 PID: 8 Comm: kworker/u8:0 Tainted: G        W
>>>>>>      5.19.0-rc6-00096-gba7973977976-dirty #1
>>>>>> [  166.702200] Hardware name: Raspberry Pi 4 Model B Rev 1.1 (DT)
>>>>>> [  166.702206] Workqueue: events_freezable_power_
>>>>>> thermal_zone_device_check
>>>>>> [  166.702231] pstate: 200000c5 (nzCv daIF -PAN -UAO -TCO -DIT -SSBS
>>>>>> BTYPE=--)
>>>>>> [  166.702242] pc : regmap_mmio_read32le+0x10/0x28
>>>>>> [  166.702261] lr : regmap_mmio_read+0x44/0x70
>>>>>> ...
>>>>>> [  166.702606]  bcm2711_get_temp+0x58/0xb0 [bcm2711_thermal]
>>>>>>
>>>>>> I wondered if that reg read was stalled due to a clock being stopped.
>>>>>>
>>>>>> Lo and behold, disabling runtime pm and keeping the vec clock running
>>>>>> all the time fixed it[1].
>>>>>>
>>>>>> I don't know what the problem is, but at least I can now test this
>>>>>> patchset.
>>>>>>
>>>>>> [1] https://gist.github.com/notro/23b984e7fa05cfbda2db50a421cac065
>>>>>>
>>>>> It turns out I didn't have to disable runtime pm:
>>>>> https://gist.github.com/notro/0adcfcb12460b54e54458afe11dc8ea2
>>>> If the bcm2711_thermal IP needs that clock to be enabled, it should grab
>>>> a reference itself, but it looks like even the device tree binding
>>>> doesn't ask for one.
>>> The missing clock in the device tree binding is expected, because
>>> despite of the code there is not much information about the BCM2711
>>> clock tree. But i'm skeptical that the AVS IP actually needs the VEC
>>> clock, i think it's more likely that the VEC clock parent is changed and
>>> that cause this issue. I could take care of the bcm2711 binding & driver
>>> if i know which clock is really necessary.
>>
>> Seems you're right, keeping the parent always enabled is enough:
>>
>> 	clk_prepare_enable(clk_get_parent(vec->clock)); // pllc_per
>>
>> I tried enabling just the grandparent clock as well, but that didn't help.
> 
> Yeah, adding tracing to the clock framework shows that it indeed
> disables PLLC_PER. So there's probably some other device that depends on
> it but doesn't take a reference to it.
> 
> I had a look, but it's not really obvious what that might be.
> 
> This patch makes sure that the PLL*_PER are never disabled, could you
> test it? It seems to work for me.
> 
> 
> diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
> index 48a1eb9f2d55..3839261ee419 100644
> --- a/drivers/clk/bcm/clk-bcm2835.c
> +++ b/drivers/clk/bcm/clk-bcm2835.c
> @@ -1675,7 +1675,7 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
>  		.load_mask = CM_PLLA_LOADPER,
>  		.hold_mask = CM_PLLA_HOLDPER,
>  		.fixed_divider = 1,
> -		.flags = CLK_SET_RATE_PARENT),
> +		.flags = CLK_IS_CRITICAL | CLK_SET_RATE_PARENT),
>  	[BCM2835_PLLA_DSI0]	= REGISTER_PLL_DIV(
>  		SOC_ALL,
>  		.name = "plla_dsi0",
> @@ -1784,7 +1784,7 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
>  		.load_mask = CM_PLLC_LOADPER,
>  		.hold_mask = CM_PLLC_HOLDPER,
>  		.fixed_divider = 1,
> -		.flags = CLK_SET_RATE_PARENT),
> +		.flags = CLK_IS_CRITICAL | CLK_SET_RATE_PARENT),
> 

Yes, this worked, but it's enough to mark pllc_per as critical.

Noralf.

>  	/*
>  	 * PLLD is the display PLL, used to drive DSI display panels.
> @@ -1891,7 +1891,7 @@ static const struct bcm2835_clk_desc clk_desc_array[] = {
>  		.load_mask = CM_PLLH_LOADAUX,
>  		.hold_mask = 0,
>  		.fixed_divider = 1,
> -		.flags = CLK_SET_RATE_PARENT),
> +		.flags = CLK_IS_CRITICAL | CLK_SET_RATE_PARENT),
>  	[BCM2835_PLLH_PIX]	= REGISTER_PLL_DIV(
>  		SOC_BCM2835,
>  		.name = "pllh_pix",
> 
> 
> Maxime

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

end of thread, other threads:[~2022-09-24 15:36 UTC | newest]

Thread overview: 128+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-08-29 13:11 [PATCH v2 00/41] drm: Analog TV Improvements Maxime Ripard
2022-08-29 13:11 ` [PATCH v2 01/41] drm/tests: Order Kunit tests in Makefile Maxime Ripard
2022-08-29 18:46   ` Noralf Trønnes
2022-08-29 19:02     ` Konstantin Ryabitsev
2022-08-30  8:30       ` Maxime Ripard
2022-08-29 13:11 ` [PATCH v2 02/41] drm/tests: Add Kunit Helpers Maxime Ripard
2022-08-29 13:11 ` [PATCH v2 03/41] drm/atomic-helper: Rename drm_atomic_helper_connector_tv_reset to avoid ambiguity Maxime Ripard
2022-08-29 13:11 ` [PATCH v2 04/41] drm/connector: Rename subconnector state variable Maxime Ripard
2022-08-29 13:11 ` [PATCH v2 05/41] drm/atomic: Add TV subconnector property to get/set_property Maxime Ripard
2022-08-29 13:11 ` [PATCH v2 06/41] drm/connector: Rename legacy TV property Maxime Ripard
2022-08-30 19:27   ` Noralf Trønnes
2022-08-29 13:11 ` [PATCH v2 07/41] drm/connector: Only register TV mode property if present Maxime Ripard
2022-08-29 13:11 ` [PATCH v2 08/41] drm/connector: Rename drm_mode_create_tv_properties Maxime Ripard
2022-08-29 13:11 ` [PATCH v2 09/41] drm/connector: Add TV standard property Maxime Ripard
2022-09-01 22:00   ` Mateusz Kwiatkowski
2022-09-02  7:35     ` Geert Uytterhoeven
2022-09-07 12:11       ` Maxime Ripard
2022-09-07 12:10     ` Maxime Ripard
2022-09-07 19:52       ` Mateusz Kwiatkowski
2022-09-09  9:46         ` Maxime Ripard
2022-09-11  4:32           ` Mateusz Kwiatkowski
2022-09-05 10:18   ` Noralf Trønnes
2022-08-29 13:11 ` [PATCH v2 10/41] drm/modes: Add a function to generate analog display modes Maxime Ripard
2022-08-30 13:01   ` Maíra Canal
2022-09-08 11:10     ` Maxime Ripard
2022-08-31  1:44   ` Mateusz Kwiatkowski
2022-08-31  8:14     ` Geert Uytterhoeven
2022-09-05 13:32       ` Maxime Ripard
2022-09-05 16:32         ` Mateusz Kwiatkowski
2022-09-07 14:38           ` Maxime Ripard
2022-09-05 13:37     ` Maxime Ripard
2022-09-05 16:44       ` Mateusz Kwiatkowski
2022-09-07 14:34         ` Maxime Ripard
2022-09-07 21:31           ` Mateusz Kwiatkowski
2022-09-09 13:54             ` Maxime Ripard
2022-09-11  4:48               ` Mateusz Kwiatkowski
2022-09-11  4:51                 ` Mateusz Kwiatkowski
2022-09-21 15:05                 ` Maxime Ripard
2022-09-09 14:00             ` Maxime Ripard
2022-09-11  4:30               ` kFYatek
2022-09-21 14:26                 ` Maxime Ripard
2022-09-01 19:09   ` Noralf Trønnes
2022-08-29 13:11 ` [PATCH v2 11/41] drm/modes: Only consider bpp and refresh before options Maxime Ripard
2022-08-29 13:11 ` [PATCH v2 12/41] drm/modes: parse_cmdline: Add support for named modes containing dashes Maxime Ripard
2022-08-29 13:11 ` [PATCH v2 13/41] drm/client: Add some tests for drm_connector_pick_cmdline_mode() Maxime Ripard
2022-08-29 13:11 ` [PATCH v2 14/41] drm/modes: Move named modes parsing to a separate function Maxime Ripard
2022-08-30 10:06   ` Geert Uytterhoeven
2022-08-30 10:43     ` Jani Nikula
2022-08-30 12:03       ` Maxime Ripard
2022-08-30 13:36         ` Jani Nikula
2022-09-07  8:39           ` Maxime Ripard
2022-08-29 13:11 ` [PATCH v2 15/41] drm/modes: Switch to named mode descriptors Maxime Ripard
2022-08-29 13:11 ` [PATCH v2 16/41] drm/modes: Fill drm_cmdline mode from named modes Maxime Ripard
2022-08-29 13:11 ` [PATCH v2 17/41] drm/connector: Add pixel clock to cmdline mode Maxime Ripard
2022-08-29 13:11 ` [PATCH v2 18/41] drm/connector: Add a function to lookup a TV mode by its name Maxime Ripard
2022-08-31 19:14   ` Noralf Trønnes
2022-08-29 13:11 ` [PATCH v2 19/41] drm/modes: Introduce the tv_mode property as a command-line option Maxime Ripard
2022-08-30 12:34   ` Maíra Canal
2022-08-30 12:44   ` Maíra Canal
2022-09-01 22:46   ` Mateusz Kwiatkowski
2022-09-05 14:28     ` Maxime Ripard
2022-08-29 13:11 ` [PATCH v2 20/41] drm/modes: Properly generate a drm_display_mode from a named mode Maxime Ripard
2022-09-01 22:52   ` Mateusz Kwiatkowski
2022-08-29 13:11 ` [PATCH v2 21/41] drm/modes: Introduce more named modes Maxime Ripard
2022-08-29 13:11 ` [PATCH v2 22/41] drm/atomic-helper: Add a TV properties reset helper Maxime Ripard
2022-08-30 18:40   ` Noralf Trønnes
2022-08-29 13:11 ` [PATCH v2 23/41] drm/atomic-helper: Add an analog TV atomic_check implementation Maxime Ripard
2022-08-30 18:49   ` Noralf Trønnes
2022-08-29 13:11 ` [PATCH v2 24/41] drm/vc4: vec: Remove empty mode_fixup Maxime Ripard
2022-08-30 15:23   ` Noralf Trønnes
2022-09-07  8:34   ` (subset) " Maxime Ripard
2022-08-29 13:11 ` [PATCH v2 25/41] drm/vc4: vec: Convert to atomic helpers Maxime Ripard
2022-08-30 15:24   ` Noralf Trønnes
2022-09-07  8:35   ` (subset) " Maxime Ripard
2022-08-29 13:11 ` [PATCH v2 26/41] drm/vc4: vec: Refactor VEC TV mode setting Maxime Ripard
2022-08-30 15:29   ` Noralf Trønnes
2022-09-07  8:35   ` (subset) " Maxime Ripard
2022-08-29 13:11 ` [PATCH v2 27/41] drm/vc4: vec: Remove redundant atomic_mode_set Maxime Ripard
2022-08-30 15:45   ` Noralf Trønnes
2022-09-07  8:35   ` (subset) " Maxime Ripard
2022-08-29 13:11 ` [PATCH v2 28/41] drm/vc4: vec: Fix timings for VEC modes Maxime Ripard
2022-08-30 18:20   ` Noralf Trønnes
2022-09-07  8:35   ` (subset) " Maxime Ripard
2022-08-29 13:11 ` [PATCH v2 29/41] drm/vc4: vec: Switch for common modes Maxime Ripard
2022-08-30 18:36   ` Noralf Trønnes
2022-08-29 13:11 ` [PATCH v2 30/41] drm/vc4: vec: Fix definition of PAL-M mode Maxime Ripard
2022-08-29 13:11 ` [PATCH v2 31/41] drm/vc4: vec: Use TV Reset implementation Maxime Ripard
2022-08-30 18:51   ` Noralf Trønnes
2022-08-29 13:11 ` [PATCH v2 32/41] drm/vc4: vec: Convert to the new TV mode property Maxime Ripard
2022-08-30 19:01   ` Noralf Trønnes
2022-09-08 11:23     ` Maxime Ripard
2022-09-08 11:31       ` Mateusz Kwiatkowski
2022-09-08 12:16         ` Maxime Ripard
2022-09-08 11:34       ` Noralf Trønnes
2022-08-31  2:23   ` Mateusz Kwiatkowski
2022-09-08 13:18     ` Maxime Ripard
2022-08-29 13:11 ` [PATCH v2 33/41] drm/vc4: vec: Add support for more analog TV standards Maxime Ripard
2022-08-29 13:11 ` [PATCH v2 34/41] drm/sun4i: tv: Remove unused mode_valid Maxime Ripard
2022-09-07  8:35   ` (subset) " Maxime Ripard
2022-08-29 13:11 ` [PATCH v2 35/41] drm/sun4i: tv: Convert to atomic hooks Maxime Ripard
2022-09-06 20:02   ` Jernej Škrabec
2022-09-07  8:35   ` (subset) " Maxime Ripard
2022-08-29 13:11 ` [PATCH v2 36/41] drm/sun4i: tv: Merge mode_set into atomic_enable Maxime Ripard
2022-09-06 20:04   ` Jernej Škrabec
2022-09-07  7:41     ` Maxime Ripard
2022-09-07 15:09       ` Jernej Škrabec
2022-09-08 14:02   ` (subset) " Maxime Ripard
2022-08-29 13:11 ` [PATCH v2 37/41] drm/sun4i: tv: Remove useless function Maxime Ripard
2022-09-06 20:06   ` Jernej Škrabec
2022-09-07  8:35   ` (subset) " Maxime Ripard
2022-08-29 13:11 ` [PATCH v2 38/41] drm/sun4i: tv: Remove useless destroy function Maxime Ripard
2022-09-07  8:35   ` (subset) " Maxime Ripard
2022-08-29 13:11 ` [PATCH v2 39/41] drm/sun4i: tv: Rename error label Maxime Ripard
2022-09-07  8:35   ` (subset) " Maxime Ripard
2022-08-29 13:11 ` [PATCH v2 40/41] drm/sun4i: tv: Add missing reset assertion Maxime Ripard
2022-09-07  8:35   ` (subset) " Maxime Ripard
2022-08-29 13:11 ` [PATCH v2 41/41] drm/sun4i: tv: Convert to the new TV mode property Maxime Ripard
2022-09-01 19:35 ` [PATCH v2 00/41] drm: Analog TV Improvements Noralf Trønnes
2022-09-02 11:28   ` Noralf Trønnes
2022-09-05 14:57     ` Maxime Ripard
2022-09-05 15:17       ` Noralf Trønnes
2022-09-07  9:58         ` Maxime Ripard
2022-09-07 10:56           ` Noralf Trønnes
2022-09-07 10:36       ` Stefan Wahren
2022-09-07 16:44         ` Noralf Trønnes
2022-09-10 15:34           ` Noralf Trønnes
2022-09-21 14:03           ` Maxime Ripard
2022-09-24 15:33             ` Noralf Trønnes

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).