mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* Re: [PATCH v7 14/23] drm/modes: Properly generate a drm_display_mode from a named mode
       [not found] ` <20220728-rpi-analog-tv-properties-v7-14-7072a478c6b3@cerno.tech>
@ 2022-11-07 17:49   ` Noralf Trønnes
  2022-11-08  9:40     ` Noralf Trønnes
  2022-11-10  9:31     ` Maxime Ripard
  0 siblings, 2 replies; 17+ messages in thread
From: Noralf Trønnes @ 2022-11-07 17:49 UTC (permalink / raw)
  To: Maxime Ripard, Jani Nikula, Joonas Lahtinen, Tvrtko Ursulin,
	Ben Skeggs, Rodrigo Vivi, Maxime Ripard, Samuel Holland,
	Jernej Skrabec, Maarten Lankhorst, Emma Anholt, Karol Herbst,
	Daniel Vetter, Chen-Yu Tsai, Lyude Paul, Thomas Zimmermann,
	David Airlie
  Cc: Phil Elwell, Hans de Goede, linux-sunxi, linux-kernel,
	Geert Uytterhoeven, Dave Stevenson, linux-arm-kernel, Dom Cobley,
	Mateusz Kwiatkowski, dri-devel, intel-gfx, nouveau,
	Noralf Trønnes



Den 07.11.2022 15.16, skrev Maxime Ripard:
> 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>
> 
> ---
> Changes in v7:
> - Use tv_mode_specified in drm_mode_parse_command_line_for_connector
> 
> Changes in v6:
> - Fix get_modes to return 0 instead of an error code
> - Rename the tests to follow the DRM test naming convention
> 
> Changes in v5:
> - Switched to KUNIT_ASSERT_NOT_NULL
> ---
>  drivers/gpu/drm/drm_modes.c                     | 34 ++++++++++-
>  drivers/gpu/drm/tests/drm_client_modeset_test.c | 77 ++++++++++++++++++++++++-
>  2 files changed, 109 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
> index dc037f7ceb37..49441cabdd9d 100644
> --- a/drivers/gpu/drm/drm_modes.c
> +++ b/drivers/gpu/drm/drm_modes.c
> @@ -2497,6 +2497,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 (!cmd->tv_mode_specified)
> +			continue;

Only a named mode will set cmd->name, so is this check necessary?

> +
> +		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;

You can just return the result from drm_analog_tv_mode() directly.

With those considered:

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

> +	}
> +
> +	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
> @@ -2514,7 +2544,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 3aa1acfe75df..fdfe9e20702e 100644
> --- a/drivers/gpu/drm/tests/drm_client_modeset_test.c
> +++ b/drivers/gpu/drm/tests/drm_client_modeset_test.c
> @@ -21,7 +21,26 @@ struct drm_client_modeset_test_priv {
>  
>  static int drm_client_modeset_connector_get_modes(struct drm_connector *connector)
>  {
> -	return drm_add_modes_noedid(connector, 1920, 1200);
> +	struct drm_display_mode *mode;
> +	int count;
> +
> +	count = drm_add_modes_noedid(connector, 1920, 1200);
> +
> +	mode = drm_mode_analog_ntsc_480i(connector->dev);
> +	if (!mode)
> +		return count;
> +
> +	drm_mode_probed_add(connector, mode);
> +	count += 1;
> +
> +	mode = drm_mode_analog_pal_576i(connector->dev);
> +	if (!mode)
> +		return count;
> +
> +	drm_mode_probed_add(connector, mode);
> +	count += 1;
> +
> +	return count;
>  }
>  
>  static const struct drm_connector_helper_funcs drm_client_modeset_connector_helper_funcs = {
> @@ -52,6 +71,9 @@ static int drm_client_modeset_test_init(struct kunit *test)
>  
>  	drm_connector_helper_add(&priv->connector, &drm_client_modeset_connector_helper_funcs);
>  
> +	priv->connector.interlace_allowed = true;
> +	priv->connector.doublescan_allowed = true;
> +
>  	return 0;
>  
>  }
> @@ -85,9 +107,62 @@ static void drm_test_pick_cmdline_res_1920_1080_60(struct kunit *test)
>  	KUNIT_EXPECT_TRUE(test, drm_mode_equal(expected_mode, mode));
>  }
>  
> +static void drm_test_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_NOT_NULL(test, mode);
> +
> +	KUNIT_EXPECT_TRUE(test, drm_mode_equal(drm_mode_analog_ntsc_480i(drm), mode));
> +}
> +
> +static void drm_test_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_NOT_NULL(test, mode);
> +
> +	KUNIT_EXPECT_TRUE(test, drm_mode_equal(drm_mode_analog_pal_576i(drm), mode));
> +}
>  
>  static struct kunit_case drm_test_pick_cmdline_tests[] = {
>  	KUNIT_CASE(drm_test_pick_cmdline_res_1920_1080_60),
> +	KUNIT_CASE(drm_test_pick_cmdline_named_ntsc),
> +	KUNIT_CASE(drm_test_pick_cmdline_named_pal),
>  	{}
>  };
>  
> 

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

* Re: [PATCH v7 15/23] drm/modes: Introduce more named modes
       [not found] ` <20220728-rpi-analog-tv-properties-v7-15-7072a478c6b3@cerno.tech>
@ 2022-11-07 18:03   ` Noralf Trønnes
  2022-11-08  9:38     ` Noralf Trønnes
  2022-11-09 14:09   ` Noralf Trønnes
  1 sibling, 1 reply; 17+ messages in thread
From: Noralf Trønnes @ 2022-11-07 18:03 UTC (permalink / raw)
  To: Maxime Ripard, Jani Nikula, Joonas Lahtinen, Tvrtko Ursulin,
	Ben Skeggs, Rodrigo Vivi, Maxime Ripard, Samuel Holland,
	Jernej Skrabec, Maarten Lankhorst, Emma Anholt, Karol Herbst,
	Daniel Vetter, Chen-Yu Tsai, Lyude Paul, Thomas Zimmermann,
	David Airlie
  Cc: Phil Elwell, Hans de Goede, linux-sunxi, linux-kernel,
	Geert Uytterhoeven, Dave Stevenson, linux-arm-kernel, Dom Cobley,
	Mateusz Kwiatkowski, dri-devel, intel-gfx, nouveau,
	Noralf Trønnes



Den 07.11.2022 15.16, skrev Maxime Ripard:
> 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>
> 
> ---
> Changes in v6:
> - Renamed the tests to follow DRM test naming convention
> 
> Changes in v5:
> - Switched to KUNIT_ASSERT_NOT_NULL
> ---
>  drivers/gpu/drm/drm_modes.c                     |  2 +
>  drivers/gpu/drm/tests/drm_client_modeset_test.c | 54 +++++++++++++++++++++++++
>  2 files changed, 56 insertions(+)
> 
> diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
> index 49441cabdd9d..17c5b6108103 100644
> --- a/drivers/gpu/drm/drm_modes.c
> +++ b/drivers/gpu/drm/drm_modes.c
> @@ -2272,7 +2272,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),
> +	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),
> +	NAMED_MODE("PAL-M", 13500, 720, 480, DRM_MODE_FLAG_INTERLACE, DRM_MODE_TV_MODE_PAL_M),
>  };

I'm now having second thoughts about the tv_mode commandline option. Can
we just add all the variants to this table and drop the tv_mode option?
IMO this will be more user friendly and less confusing.

The named modes needs to be documented in modedb.rst.

Noralf.

>  
>  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 fdfe9e20702e..b3820d25beca 100644
> --- a/drivers/gpu/drm/tests/drm_client_modeset_test.c
> +++ b/drivers/gpu/drm/tests/drm_client_modeset_test.c
> @@ -133,6 +133,32 @@ static void drm_test_pick_cmdline_named_ntsc(struct kunit *test)
>  	KUNIT_EXPECT_TRUE(test, drm_mode_equal(drm_mode_analog_ntsc_480i(drm), mode));
>  }
>  
> +static void drm_test_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_NOT_NULL(test, mode);
> +
> +	KUNIT_EXPECT_TRUE(test, drm_mode_equal(drm_mode_analog_ntsc_480i(drm), mode));
> +}
> +
>  static void drm_test_pick_cmdline_named_pal(struct kunit *test)
>  {
>  	struct drm_client_modeset_test_priv *priv = test->priv;
> @@ -159,10 +185,38 @@ static void drm_test_pick_cmdline_named_pal(struct kunit *test)
>  	KUNIT_EXPECT_TRUE(test, drm_mode_equal(drm_mode_analog_pal_576i(drm), mode));
>  }
>  
> +static void drm_test_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_NOT_NULL(test, mode);
> +
> +	KUNIT_EXPECT_TRUE(test, drm_mode_equal(drm_mode_analog_ntsc_480i(drm), mode));
> +}
> +
>  static struct kunit_case drm_test_pick_cmdline_tests[] = {
>  	KUNIT_CASE(drm_test_pick_cmdline_res_1920_1080_60),
>  	KUNIT_CASE(drm_test_pick_cmdline_named_ntsc),
> +	KUNIT_CASE(drm_test_pick_cmdline_named_ntsc_j),
>  	KUNIT_CASE(drm_test_pick_cmdline_named_pal),
> +	KUNIT_CASE(drm_test_pick_cmdline_named_pal_m),
>  	{}
>  };
>  
> 

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

* Re: [PATCH v7 16/23] drm/probe-helper: Provide a TV get_modes helper
       [not found] ` <20220728-rpi-analog-tv-properties-v7-16-7072a478c6b3@cerno.tech>
@ 2022-11-07 18:11   ` Noralf Trønnes
  2022-11-09 15:41     ` Maxime Ripard
  0 siblings, 1 reply; 17+ messages in thread
From: Noralf Trønnes @ 2022-11-07 18:11 UTC (permalink / raw)
  To: Maxime Ripard, Jani Nikula, Joonas Lahtinen, Tvrtko Ursulin,
	Ben Skeggs, Rodrigo Vivi, Maxime Ripard, Samuel Holland,
	Jernej Skrabec, Maarten Lankhorst, Emma Anholt, Karol Herbst,
	Daniel Vetter, Chen-Yu Tsai, Lyude Paul, Thomas Zimmermann,
	David Airlie
  Cc: Phil Elwell, Hans de Goede, linux-sunxi, linux-kernel,
	Geert Uytterhoeven, Dave Stevenson, linux-arm-kernel, Dom Cobley,
	Mateusz Kwiatkowski, dri-devel, intel-gfx, nouveau



Den 07.11.2022 15.16, skrev Maxime Ripard:
> From: Noralf Trønnes <noralf@tronnes.org>
> 
> Most of the TV connectors will need a similar get_modes implementation
> that will, depending on the drivers' capabilities, register the 480i and
> 576i modes.
> 
> That implementation will also need to set the preferred flag and order
> the modes based on the driver and users preferrence.
> 
> This is especially important to guarantee that a userspace stack such as
> Xorg can start and pick up the preferred mode while maintaining a
> working output.
> 
> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
> Signed-off-by: Maxime Ripard <maxime@cerno.tech>
> 
> ---
> Changes in v7:
> - Used Noralf's implementation
> 
> Changes in v6:
> - New patch
> ---
>  drivers/gpu/drm/drm_probe_helper.c | 97 ++++++++++++++++++++++++++++++++++++++
>  include/drm/drm_probe_helper.h     |  1 +
>  2 files changed, 98 insertions(+)
> 
> diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c
> index 2fc21df709bc..edb2e4c4530a 100644
> --- a/drivers/gpu/drm/drm_probe_helper.c
> +++ b/drivers/gpu/drm/drm_probe_helper.c
> @@ -1147,3 +1147,100 @@ int drm_connector_helper_get_modes(struct drm_connector *connector)
>  	return count;
>  }
>  EXPORT_SYMBOL(drm_connector_helper_get_modes);
> +
> +static bool tv_mode_supported(struct drm_connector *connector,
> +			      enum drm_connector_tv_mode mode)
> +{
> +	struct drm_device *dev = connector->dev;
> +	struct drm_property *property = dev->mode_config.tv_mode_property;
> +
> +	unsigned int i;
> +
> +	for (i = 0; i < property->num_values; i++)
> +		if (property->values[i] == mode)
> +			return true;
> +
> +	return false;
> +}

This function is not used in the new implementation.

I hope you have tested this patch since I didn't even compile test my
implementation (probably should have said so...)

Noralf.

> +
> +/**
> + * drm_connector_helper_tv_get_modes - Fills the modes availables to a TV connector
> + * @connector: The connector
> + *
> + * Fills the available modes for a TV connector based on the supported
> + * TV modes, and the default mode expressed by the kernel command line.
> + *
> + * This can be used as the default TV connector helper .get_modes() hook
> + * if the driver does not need any special processing.
> + *
> + * Returns:
> + * The number of modes added to the connector.
> + */
> +int drm_connector_helper_tv_get_modes(struct drm_connector *connector)
> +{
> +	struct drm_device *dev = connector->dev;
> +	struct drm_property *tv_mode_property =
> +		dev->mode_config.tv_mode_property;
> +	struct drm_cmdline_mode *cmdline = &connector->cmdline_mode;
> +	unsigned int ntsc_modes = BIT(DRM_MODE_TV_MODE_NTSC) |
> +		BIT(DRM_MODE_TV_MODE_NTSC_443) |
> +		BIT(DRM_MODE_TV_MODE_NTSC_J) |
> +		BIT(DRM_MODE_TV_MODE_PAL_M);
> +	unsigned int pal_modes = BIT(DRM_MODE_TV_MODE_PAL) |
> +		BIT(DRM_MODE_TV_MODE_PAL_N) |
> +		BIT(DRM_MODE_TV_MODE_SECAM);
> +	unsigned int tv_modes[2] = { UINT_MAX, UINT_MAX };
> +	unsigned int i, supported_tv_modes = 0;
> +
> +	if (!tv_mode_property)
> +		return 0;
> +
> +	for (i = 0; i < tv_mode_property->num_values; i++)
> +		supported_tv_modes |= BIT(tv_mode_property->values[i]);
> +
> +	if ((supported_tv_modes & ntsc_modes) &&
> +	    (supported_tv_modes & pal_modes)) {
> +		uint64_t default_mode;
> +
> +		if (drm_object_property_get_default_value(&connector->base,
> +							  tv_mode_property,
> +							  &default_mode))
> +			return 0;
> +
> +		if (cmdline->tv_mode_specified)
> +			default_mode = cmdline->tv_mode;
> +
> +		if (BIT(default_mode) & ntsc_modes) {
> +			tv_modes[0] = DRM_MODE_TV_MODE_NTSC;
> +			tv_modes[1] = DRM_MODE_TV_MODE_PAL;
> +		} else {
> +			tv_modes[0] = DRM_MODE_TV_MODE_PAL;
> +			tv_modes[1] = DRM_MODE_TV_MODE_NTSC;
> +		}
> +	} else if (supported_tv_modes & ntsc_modes) {
> +		tv_modes[0] = DRM_MODE_TV_MODE_NTSC;
> +	} else if (supported_tv_modes & pal_modes) {
> +		tv_modes[0] = DRM_MODE_TV_MODE_PAL;
> +	} else {
> +		return 0;
> +	}
> +
> +	for (i = 0; i < ARRAY_SIZE(tv_modes); i++) {
> +		struct drm_display_mode *mode;
> +
> +		if (tv_modes[i] == DRM_MODE_TV_MODE_NTSC)
> +			mode = drm_mode_analog_ntsc_480i(dev);
> +		else if (tv_modes[i] == DRM_MODE_TV_MODE_PAL)
> +			mode = drm_mode_analog_pal_576i(dev);
> +		else
> +			break;
> +		if (!mode)
> +			return i;
> +		if (!i)
> +			mode->type |= DRM_MODE_TYPE_PREFERRED;
> +		drm_mode_probed_add(connector, mode);
> +	}
> +
> +	return i;
> +}
> +EXPORT_SYMBOL(drm_connector_helper_tv_get_modes);
> diff --git a/include/drm/drm_probe_helper.h b/include/drm/drm_probe_helper.h
> index 5880daa14624..4977e0ab72db 100644
> --- a/include/drm/drm_probe_helper.h
> +++ b/include/drm/drm_probe_helper.h
> @@ -35,5 +35,6 @@ int drm_connector_helper_get_modes_from_ddc(struct drm_connector *connector);
>  int drm_connector_helper_get_modes_fixed(struct drm_connector *connector,
>  					 const struct drm_display_mode *fixed_mode);
>  int drm_connector_helper_get_modes(struct drm_connector *connector);
> +int drm_connector_helper_tv_get_modes(struct drm_connector *connector);
>  
>  #endif
> 

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

* Re: [PATCH v7 15/23] drm/modes: Introduce more named modes
  2022-11-07 18:03   ` [PATCH v7 15/23] drm/modes: Introduce more named modes Noralf Trønnes
@ 2022-11-08  9:38     ` Noralf Trønnes
  2022-11-08 21:27       ` Mateusz Kwiatkowski
  0 siblings, 1 reply; 17+ messages in thread
From: Noralf Trønnes @ 2022-11-08  9:38 UTC (permalink / raw)
  To: Maxime Ripard, Jani Nikula, Joonas Lahtinen, Tvrtko Ursulin,
	Ben Skeggs, Rodrigo Vivi, Maxime Ripard, Samuel Holland,
	Jernej Skrabec, Maarten Lankhorst, Emma Anholt, Karol Herbst,
	Daniel Vetter, Chen-Yu Tsai, Lyude Paul, Thomas Zimmermann,
	David Airlie
  Cc: Phil Elwell, Hans de Goede, linux-sunxi, linux-kernel,
	Geert Uytterhoeven, Dave Stevenson, linux-arm-kernel, Dom Cobley,
	Mateusz Kwiatkowski, dri-devel, intel-gfx, nouveau,
	Noralf Trønnes



Den 07.11.2022 19.03, skrev Noralf Trønnes:
> 
> 
> Den 07.11.2022 15.16, skrev Maxime Ripard:
>> 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>
>>
>> ---
>> Changes in v6:
>> - Renamed the tests to follow DRM test naming convention
>>
>> Changes in v5:
>> - Switched to KUNIT_ASSERT_NOT_NULL
>> ---
>>  drivers/gpu/drm/drm_modes.c                     |  2 +
>>  drivers/gpu/drm/tests/drm_client_modeset_test.c | 54 +++++++++++++++++++++++++
>>  2 files changed, 56 insertions(+)
>>
>> diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
>> index 49441cabdd9d..17c5b6108103 100644
>> --- a/drivers/gpu/drm/drm_modes.c
>> +++ b/drivers/gpu/drm/drm_modes.c
>> @@ -2272,7 +2272,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),
>> +	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),
>> +	NAMED_MODE("PAL-M", 13500, 720, 480, DRM_MODE_FLAG_INTERLACE, DRM_MODE_TV_MODE_PAL_M),
>>  };
> 
> I'm now having second thoughts about the tv_mode commandline option. Can
> we just add all the variants to this table and drop the tv_mode option?
> IMO this will be more user friendly and less confusing.
> 

One downside of this is that it's not possible to force connector status
when using named modes, but I think it would be better to have a force
option than a tv_mode option. A lot of userspace treats unknown status
as disconnected.

Anyone know if it's possible to set the connector status sysfs file
using a udev rule?

Noralf.

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

* Re: [PATCH v7 14/23] drm/modes: Properly generate a drm_display_mode from a named mode
  2022-11-07 17:49   ` [PATCH v7 14/23] drm/modes: Properly generate a drm_display_mode from a named mode Noralf Trønnes
@ 2022-11-08  9:40     ` Noralf Trønnes
  2022-11-10 10:36       ` Maxime Ripard
  2022-11-10  9:31     ` Maxime Ripard
  1 sibling, 1 reply; 17+ messages in thread
From: Noralf Trønnes @ 2022-11-08  9:40 UTC (permalink / raw)
  To: Maxime Ripard, Jani Nikula, Joonas Lahtinen, Tvrtko Ursulin,
	Ben Skeggs, Rodrigo Vivi, Maxime Ripard, Samuel Holland,
	Jernej Skrabec, Maarten Lankhorst, Emma Anholt, Karol Herbst,
	Daniel Vetter, Chen-Yu Tsai, Lyude Paul, Thomas Zimmermann,
	David Airlie
  Cc: Phil Elwell, Hans de Goede, linux-sunxi, linux-kernel,
	Geert Uytterhoeven, Dave Stevenson, linux-arm-kernel, Dom Cobley,
	Mateusz Kwiatkowski, dri-devel, intel-gfx, nouveau,
	Noralf Trønnes



Den 07.11.2022 18.49, skrev Noralf Trønnes:
> 
> 
> Den 07.11.2022 15.16, skrev Maxime Ripard:
>> 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>
>>
>> ---
>> Changes in v7:
>> - Use tv_mode_specified in drm_mode_parse_command_line_for_connector
>>
>> Changes in v6:
>> - Fix get_modes to return 0 instead of an error code
>> - Rename the tests to follow the DRM test naming convention
>>
>> Changes in v5:
>> - Switched to KUNIT_ASSERT_NOT_NULL
>> ---
>>  drivers/gpu/drm/drm_modes.c                     | 34 ++++++++++-
>>  drivers/gpu/drm/tests/drm_client_modeset_test.c | 77 ++++++++++++++++++++++++-
>>  2 files changed, 109 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
>> index dc037f7ceb37..49441cabdd9d 100644
>> --- a/drivers/gpu/drm/drm_modes.c
>> +++ b/drivers/gpu/drm/drm_modes.c
>> @@ -2497,6 +2497,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 (!cmd->tv_mode_specified)
>> +			continue;
> 
> Only a named mode will set cmd->name, so is this check necessary?
> 
>> +
>> +		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;
> 
> You can just return the result from drm_analog_tv_mode() directly.
> 
> With those considered:
> 
> Reviewed-by: Noralf Trønnes <noralf@tronnes.org>
> 

I forgot one thing, shouldn't the named mode test in
drm_connector_pick_cmdline_mode() be removed now that we have proper modes?

Noralf.

>> +	}
>> +
>> +	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
>> @@ -2514,7 +2544,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 3aa1acfe75df..fdfe9e20702e 100644
>> --- a/drivers/gpu/drm/tests/drm_client_modeset_test.c
>> +++ b/drivers/gpu/drm/tests/drm_client_modeset_test.c
>> @@ -21,7 +21,26 @@ struct drm_client_modeset_test_priv {
>>  
>>  static int drm_client_modeset_connector_get_modes(struct drm_connector *connector)
>>  {
>> -	return drm_add_modes_noedid(connector, 1920, 1200);
>> +	struct drm_display_mode *mode;
>> +	int count;
>> +
>> +	count = drm_add_modes_noedid(connector, 1920, 1200);
>> +
>> +	mode = drm_mode_analog_ntsc_480i(connector->dev);
>> +	if (!mode)
>> +		return count;
>> +
>> +	drm_mode_probed_add(connector, mode);
>> +	count += 1;
>> +
>> +	mode = drm_mode_analog_pal_576i(connector->dev);
>> +	if (!mode)
>> +		return count;
>> +
>> +	drm_mode_probed_add(connector, mode);
>> +	count += 1;
>> +
>> +	return count;
>>  }
>>  
>>  static const struct drm_connector_helper_funcs drm_client_modeset_connector_helper_funcs = {
>> @@ -52,6 +71,9 @@ static int drm_client_modeset_test_init(struct kunit *test)
>>  
>>  	drm_connector_helper_add(&priv->connector, &drm_client_modeset_connector_helper_funcs);
>>  
>> +	priv->connector.interlace_allowed = true;
>> +	priv->connector.doublescan_allowed = true;
>> +
>>  	return 0;
>>  
>>  }
>> @@ -85,9 +107,62 @@ static void drm_test_pick_cmdline_res_1920_1080_60(struct kunit *test)
>>  	KUNIT_EXPECT_TRUE(test, drm_mode_equal(expected_mode, mode));
>>  }
>>  
>> +static void drm_test_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_NOT_NULL(test, mode);
>> +
>> +	KUNIT_EXPECT_TRUE(test, drm_mode_equal(drm_mode_analog_ntsc_480i(drm), mode));
>> +}
>> +
>> +static void drm_test_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_NOT_NULL(test, mode);
>> +
>> +	KUNIT_EXPECT_TRUE(test, drm_mode_equal(drm_mode_analog_pal_576i(drm), mode));
>> +}
>>  
>>  static struct kunit_case drm_test_pick_cmdline_tests[] = {
>>  	KUNIT_CASE(drm_test_pick_cmdline_res_1920_1080_60),
>> +	KUNIT_CASE(drm_test_pick_cmdline_named_ntsc),
>> +	KUNIT_CASE(drm_test_pick_cmdline_named_pal),
>>  	{}
>>  };
>>  
>>

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

* Re: [Nouveau] [PATCH v7 00/23] drm: Analog TV Improvements
       [not found] ` <CAEFVmOKCTc_ZrFyCxiSwCmhtjJj_fzr6n99cWtb9aECFzzYVXg@mail.gmail.com>
@ 2022-11-08 13:42   ` Geert Uytterhoeven
  0 siblings, 0 replies; 17+ messages in thread
From: Geert Uytterhoeven @ 2022-11-08 13:42 UTC (permalink / raw)
  To: Lukas Satin
  Cc: Maxime Ripard, Jani Nikula, Joonas Lahtinen, Tvrtko Ursulin,
	Ben Skeggs, Rodrigo Vivi, Maxime Ripard, Samuel Holland,
	Jernej Skrabec, Maarten Lankhorst, Emma Anholt, Karol Herbst,
	Daniel Vetter, Chen-Yu Tsai, Lyude Paul, Thomas Zimmermann,
	David Airlie, Dom Cobley, nouveau, intel-gfx, linux-kernel,
	dri-devel, Phil Elwell, Hans de Goede, Noralf Trønnes,
	Mateusz Kwiatkowski, linux-sunxi, linux-arm-kernel

Hi Lukas,

On Tue, Nov 8, 2022 at 2:20 PM Lukas Satin <luke.satin@gmail.com> wrote:
> One can switch from NTSC to PAL now using (on vc4)
>
> modetest -M vc4  -s 53:720x480i -w 53:'TV mode':1 # NTSC
> modetest -M vc4  -s 53:720x576i -w 53:'TV mode':4 # PAL
>
> NTSC should be 640x480i, not 720. It will probably work on most TV's, but NTSC by the spec is 640x480i.

The above are actually the digital ("DVD Video") variants, which have 720
horizontal pixels (incl. overscan).
The analog variants do not have a fixed horizontal resolution, except
for bandwidth limitations.

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] 17+ messages in thread

* Re: [PATCH v7 15/23] drm/modes: Introduce more named modes
  2022-11-08  9:38     ` Noralf Trønnes
@ 2022-11-08 21:27       ` Mateusz Kwiatkowski
  2022-11-09 11:18         ` Maxime Ripard
  0 siblings, 1 reply; 17+ messages in thread
From: Mateusz Kwiatkowski @ 2022-11-08 21:27 UTC (permalink / raw)
  To: Noralf Trønnes, Maxime Ripard, Jani Nikula, Joonas Lahtinen,
	Tvrtko Ursulin, Ben Skeggs, Rodrigo Vivi, Maxime Ripard,
	Samuel Holland, Jernej Skrabec, Maarten Lankhorst, Emma Anholt,
	Karol Herbst, Daniel Vetter, Chen-Yu Tsai, Lyude Paul,
	Thomas Zimmermann, David Airlie
  Cc: Phil Elwell, Hans de Goede, linux-sunxi, linux-kernel,
	Geert Uytterhoeven, Dave Stevenson, linux-arm-kernel, Dom Cobley,
	dri-devel, intel-gfx, nouveau

Hi Noralf,

W dniu 8.11.2022 o 10:38, Noralf Trønnes pisze:
>
> Den 07.11.2022 19.03, skrev Noralf Trønnes:
>>
>> Den 07.11.2022 15.16, skrev Maxime Ripard:
>>> 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>
>>>
>>> ---
>>> Changes in v6:
>>> - Renamed the tests to follow DRM test naming convention
>>>
>>> Changes in v5:
>>> - Switched to KUNIT_ASSERT_NOT_NULL
>>> ---
>>>  drivers/gpu/drm/drm_modes.c                     |  2 +
>>>  drivers/gpu/drm/tests/drm_client_modeset_test.c | 54 +++++++++++++++++++++++++
>>>  2 files changed, 56 insertions(+)
>>>
>>> diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
>>> index 49441cabdd9d..17c5b6108103 100644
>>> --- a/drivers/gpu/drm/drm_modes.c
>>> +++ b/drivers/gpu/drm/drm_modes.c
>>> @@ -2272,7 +2272,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),
>>> +	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),
>>> +	NAMED_MODE("PAL-M", 13500, 720, 480, DRM_MODE_FLAG_INTERLACE, DRM_MODE_TV_MODE_PAL_M),
>>>  };
>> I'm now having second thoughts about the tv_mode commandline option. Can
>> we just add all the variants to this table and drop the tv_mode option?
>> IMO this will be more user friendly and less confusing.
>>
> One downside of this is that it's not possible to force connector status
> when using named modes, but I think it would be better to have a force
> option than a tv_mode option. A lot of userspace treats unknown status
> as disconnected.
>
> Anyone know if it's possible to set the connector status sysfs file
> using a udev rule?
>
> Noralf.

I think that leaving named modes only would be a bit limiting. There are use
cases for custom modes, e.g. we might want progressive 240p "NTSC" (like 80s/90s
home computers and video game consoles) or the modes with non-13.5MHz pixel
clock that Geert requested with Amiga in mind.

I'm not sure if the current cmdline-to-drm_mode conversion is flexible enough
to meaningfully facilitate those, but we're at least getting the syntax down.

Best regards,
Mateusz Kwiatkowski


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

* Re: [Nouveau] [PATCH v7 06/23] drm/modes: Add a function to generate analog display modes
       [not found]   ` <CAEFVmOJbjK2iug+UsxD8w7W0RTc0AGD=wxB5bX-es=Qc-Mcgrw@mail.gmail.com>
@ 2022-11-08 21:51     ` Mateusz Kwiatkowski
  0 siblings, 0 replies; 17+ messages in thread
From: Mateusz Kwiatkowski @ 2022-11-08 21:51 UTC (permalink / raw)
  To: Lukas Satin, Maxime Ripard
  Cc: Jani Nikula, Joonas Lahtinen, Tvrtko Ursulin, Ben Skeggs,
	Rodrigo Vivi, Maxime Ripard, Samuel Holland, Jernej Skrabec,
	Maarten Lankhorst, Emma Anholt, Karol Herbst, Daniel Vetter,
	Chen-Yu Tsai, Lyude Paul, Thomas Zimmermann, David Airlie,
	Dom Cobley, nouveau, intel-gfx, linux-kernel, dri-devel,
	Phil Elwell, Hans de Goede, Noralf Trønnes,
	Geert Uytterhoeven, linux-sunxi, linux-arm-kernel

Hi Lukas,

W dniu 8.11.2022 o 14:28, Lukas Satin pisze:
> Hi, your statement:
>
> "However, analog display usually have fairly loose timings requirements,
> the only discrete parameters being the total number of lines and pixel
> clock frequency."
>
> Please do not make it as a rule. You said yourself: "usually". Arcade CRT
> have more loose timings, but professional broadcast TV's such as Sony PVM,
> Sony BVM, JVC. These cost tens of thousand dollars back in the day. Now they
> are affordable for gamers. I just solved issue in Retroarch, CRT Switchres
> library here: https://github.com/antonioginer/switchres/issues/96

I think I'm partially to blame for this wording.
See this message and the surrounding thread:
https://lore.kernel.org/dri-devel/6d1dfaad-7310-a596-34dd-4a6d9aa95f65@gmail.com/

A lot of composite video equipment routinely violated the reference spec.
For example, CGA and Apple II output singal that had 15699.76 Hz horizontal
sync and 59.92 Hz vertical sync instead of the regular 15734.26 Hz / 59.94 Hz.
Values for Famicom/NES are 15745.98 Hz / 60.10 Hz (and the last line is slightly
shorter than all other ones at that). And I'm pretty sure these will display
just fine on a PVM.

Of course you can't just output 14 kHz / 70 Hz and expect it to work, there are
constraints of display capabilities. But the point of that discussion, which
culminated in the wording you see in the code, was that it does not need to be
precise down to every clock cycle as you would normally expect in the digital
world.

> This model is quite common among retrogamers and on Reddit.
>
> Some developers do not test it properly.
>
> This model requires exact number of lines.
>
> For Switchres we came up with these ranges:
>         crt_range0 15625-15750, 49.50-65.00, 2.000, 4.700, 8.000, 0.064, 0.192, 1.024, 1, 1, 192, 288, 0, 0
>         crt_range1 15625.00-15625.00, 50.00-50.00, 1.500, 4.700, 5.800, 0.064, 0.160, 1.056, 1, 1, 0, 0, 448, 576
>         crt_range2 15734.26-15734.26, 59.94-59.94, 1.500, 4.700, 4.700, 0.191, 0.191, 0.953, 1, 1, 0, 0, 448, 480
> crt_range0 is default, more loose definition for MAME emulators. crt_range1 is PAL and crt_range2 is NTSC.
>
> Yes, this model does support both NTSC and PAL.
>
> Does your driver or library support that?
>
> For example old driver in Windows 7 with NVIDIA 2007 driver on Geforce 7600
> can support both NTSC and PAL and these are being switched automatically by
> the resolution you choose. So in desktop properties, you change to 640x480
> and it will switch TV chipset to NTSC 480i. Then you change to 720x576 and it
> will switch TV chipset to PAL 576i.
>
> It would be preferred if advanced users could set up these numbers from a
> commandline during a runtime, so it would depend on the app being used.

As far as I understand the patch, this is exactly how it works right now. The
function you're commenting on is only used for generating the "default" modes.

> Lukas

Best regards,
Mateusz Kwiatkowski

> On Mon, Nov 7, 2022 at 3:17 PM Maxime Ripard <maxime@cerno.tech> 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>
>
>     ---
>     Changes in v6:
>     - Fix typo
>
>     Changes in v4:
>     - Reworded the line length check comment
>     - Switch to HZ_PER_KHZ in tests
>     - Use previous timing to fill our mode
>     - Move the number of lines check earlier
>     ---
>      drivers/gpu/drm/drm_modes.c            | 474 +++++++++++++++++++++++++++++++++
>      drivers/gpu/drm/tests/Makefile         |   1 +
>      drivers/gpu/drm/tests/drm_modes_test.c | 144 ++++++++++
>      include/drm/drm_modes.h                |  17 ++
>      4 files changed, 636 insertions(+)
>
>     diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
>     index 5d4ac79381c4..71c050c3ee6b 100644
>     --- a/drivers/gpu/drm/drm_modes.c
>     +++ b/drivers/gpu/drm/drm_modes.c
>     @@ -116,6 +116,480 @@ void drm_mode_probed_add(struct drm_connector *connector,
>      }
>      EXPORT_SYMBOL(drm_mode_probed_add);
>
>     +enum drm_mode_analog {
>     +       DRM_MODE_ANALOG_NTSC, /* 525 lines, 60Hz */
>     +       DRM_MODE_ANALOG_PAL, /* 625 lines, 50Hz */
>     +};
>     +
>     +/*
>     + * 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)
>     +
>     +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;
>     +
>     +       unsigned int                    bt601_hfp;
>     +
>     +       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, _bt601_hfp, _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,                                       \
>     +               .bt601_hfp = _bt601_hfp,                                \
>     +               .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),
>     +                         16,
>     +                         PARAM_FIELD(3, 3),
>     +                         PARAM_FIELD(3, 3),
>     +                         PARAM_FIELD(16, 17)),
>     +       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),
>     +                         12,
>     +
>     +                         /*
>     +                          * 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 starts with post-equalizing
>     +                          * pulses, consisting in 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.
>     +                          *
>     +                          * The entire blanking area is supposed to
>     +                          * take 25 lines, so we also need to account
>     +                          * for the rest of the blanking area that
>     +                          * can't be in either the front porch or sync
>     +                          * period.
>     +                          */
>     +                         PARAM_FIELD(19, 20)),
>     +};
>     +
>     +static int fill_analog_mode(struct drm_device *dev,
>     +                           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 int htotal, vtotal;
>     +       unsigned int max_hact, hact_duration_ns;
>     +       unsigned int hblk, hblk_duration_ns;
>     +       unsigned int hfp, hfp_duration_ns;
>     +       unsigned int hslen, hslen_duration_ns;
>     +       unsigned int hbp, hbp_duration_ns;
>     +       unsigned int porches, porches_duration_ns;
>     +       unsigned int vfp, vfp_min;
>     +       unsigned int vbp, vbp_min;
>     +       unsigned int vslen;
>     +       bool bt601 = false;
>     +       int porches_rem;
>     +       u64 result;
>     +
>     +       drm_dbg_kms(dev,
>     +                   "Generating a %ux%u%c, %u-line mode with a %lu kHz clock\n",
>     +                   hactive, vactive,
>     +                   interlace ? 'i' : 'p',
>     +                   params->num_lines,
>     +                   pixel_clock_hz / 1000);
>     +
>     +       max_hact = params->hact_ns.max / pixel_duration_ns;
>     +       if (pixel_clock_hz == 13500000 && hactive > max_hact && hactive <= 720) {
>     +               drm_dbg_kms(dev, "Trying to generate a BT.601 mode. Disabling checks.\n");
>     +               bt601 = true;
>     +       }
>     +
>     +       /*
>     +        * Our pixel duration is going to be round down by the division,
>     +        * so rounding up is probably going to introduce even more
>     +        * deviation.
>     +        */
>     +       result = (u64)params->line_duration_ns * pixel_clock_hz;
>     +       do_div(result, NSEC_PER_SEC);
>     +       htotal = result;
>     +
>     +       drm_dbg_kms(dev, "Total Horizontal Number of Pixels: %u\n", htotal);
>     +
>     +       hact_duration_ns = hactive * pixel_duration_ns;
>     +       if (!bt601 &&
>     +           (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;
>     +       drm_dbg_kms(dev, "Horizontal Blanking Period: %u\n", hblk);
>     +
>     +       hblk_duration_ns = hblk * pixel_duration_ns;
>     +       if (!bt601 &&
>     +           (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);
>     +       drm_dbg_kms(dev, "Horizontal Sync Period: %u\n", hslen);
>     +
>     +       hslen_duration_ns = hslen * pixel_duration_ns;
>     +       if (!bt601 &&
>     +           (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;
>     +       drm_dbg_kms(dev, "Remaining horizontal pixels for both porches: %u\n", porches);
>     +
>     +       porches_duration_ns = porches * pixel_duration_ns;
>     +       if (!bt601 &&
>     +           (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;
>     +       }
>     +
>     +       if (bt601) {
>     +               hfp = params->bt601_hfp;
>     +       } else {
>     +               unsigned int hfp_min = DIV_ROUND_UP(params->hfp_ns.min,
>     +                                                   pixel_duration_ns);
>     +               unsigned int hbp_min = DIV_ROUND_UP(params->hbp_ns.min,
>     +                                                   pixel_duration_ns);
>     +                int porches_rem = porches - hfp_min - hbp_min;
>     +
>     +               hfp = hfp_min + DIV_ROUND_UP(porches_rem, 2);
>     +       }
>     +
>     +       drm_dbg_kms(dev, "Horizontal Front Porch: %u\n", hfp);
>     +
>     +       hfp_duration_ns = hfp * pixel_duration_ns;
>     +       if (!bt601 &&
>     +           (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;
>     +       drm_dbg_kms(dev, "Horizontal Back Porch: %u\n", hbp);
>     +
>     +       hbp_duration_ns = hbp * pixel_duration_ns;
>     +       if (!bt601 &&
>     +           (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 = mode->hdisplay + hfp;
>     +       mode->hsync_end = mode->hsync_start + hslen;
>     +       mode->htotal = mode->hsync_end + 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, NTSC (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;
>     +       }
>     +
>     +       drm_dbg_kms(dev, "Vertical Sync Period: %u\n", vslen);
>     +
>     +       porches = params->num_lines - vactive - vslen;
>     +       drm_dbg_kms(dev, "Remaining vertical pixels for both porches: %u\n", porches);
>     +
>     +       porches_rem = porches - vfp_min - vbp_min;
>     +       vfp = vfp_min + (porches_rem / 2);
>     +       drm_dbg_kms(dev, "Vertical Front Porch: %u\n", vfp);
>     +
>     +       vbp = porches - vfp;
>     +       drm_dbg_kms(dev, "Vertical Back Porch: %u\n", vbp);
>     +
>     +       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 = mode->vdisplay + vfp;
>     +       mode->vsync_end = mode->vsync_start + vslen;
>     +       mode->vtotal = mode->vsync_end + vbp;
>     +
>     +       if (mode->vtotal != params->num_lines)
>     +               return -EINVAL;
>     +
>     +       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);
>     +
>     +       drm_dbg_kms(dev, "Generated mode " DRM_MODE_FMT "\n", DRM_MODE_ARG(mode));
>     +
>     +       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:
>     +               fallthrough;
>     +       case DRM_MODE_TV_MODE_NTSC_443:
>     +               fallthrough;
>     +       case DRM_MODE_TV_MODE_NTSC_J:
>     +               fallthrough;
>     +       case DRM_MODE_TV_MODE_PAL_M:
>     +               analog = DRM_MODE_ANALOG_NTSC;
>     +               break;
>     +
>     +       case DRM_MODE_TV_MODE_PAL:
>     +               fallthrough;
>     +       case DRM_MODE_TV_MODE_PAL_N:
>     +               fallthrough;
>     +       case DRM_MODE_TV_MODE_SECAM:
>     +               analog = DRM_MODE_ANALOG_PAL;
>     +               break;
>     +
>     +       default:
>     +               return NULL;
>     +       }
>     +
>     +       mode = drm_mode_create(dev);
>     +       if (!mode)
>     +               return NULL;
>     +
>     +       ret = fill_analog_mode(dev, 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..550e3b95453e
>     --- /dev/null
>     +++ b/drivers/gpu/drm/tests/drm_modes_test.c
>     @@ -0,0 +1,144 @@
>     +// SPDX-License-Identifier: GPL-2.0
>     +/*
>     + * Kunit test for drm_modes functions
>     + */
>     +
>     +#include <drm/drm_modes.h>
>     +
>     +#include <kunit/test.h>
>     +
>     +#include <linux/units.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);
>     +       KUNIT_ASSERT_NOT_NULL(test, priv);
>     +
>     +       priv->drm = drm_kunit_device_init(test, "drm-modes-test");
>     +       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->drm);
>     +
>     +       test->priv = priv;
>     +
>     +       return 0;
>     +}
>     +
>     +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,
>     +                                 13500 * HZ_PER_KHZ, 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);
>     +
>     +       /* BT.601 defines hsync_start at 736 for 480i */
>     +       KUNIT_EXPECT_EQ(test, mode->hsync_start, 736);
>     +
>     +       /*
>     +        * The NTSC standard expects a line to take 63.556us. With a
>     +        * pixel clock of 13.5 MHz, a pixel takes around 74ns, so we
>     +        * need to have 63556ns / 74ns = 858.
>     +        *
>     +        * This is also mandated by BT.601.
>     +        */
>     +       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,
>     +                                     13500 * HZ_PER_KHZ, 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,
>     +                                 13500 * HZ_PER_KHZ, 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);
>     +
>     +       /* BT.601 defines hsync_start at 732 for 576i */
>     +       KUNIT_EXPECT_EQ(test, mode->hsync_start, 732);
>     +
>     +       /*
>     +        * The PAL standard expects a line to take 64us. With a pixel
>     +        * clock of 13.5 MHz, a pixel takes around 74ns, so we need to
>     +        * have 64000ns / 74ns = 864.
>     +        *
>     +        * This is also mandated by BT.601.
>     +        */
>     +       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,
>     +                                     13500 * HZ_PER_KHZ, 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,
>     +       .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 b0c680e6f670..c613f0abe9dc 100644
>     --- a/include/drm/drm_modes.h
>     +++ b/include/drm/drm_modes.h
>     @@ -468,6 +468,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, 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, 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.11.0-dev-99e3a 
>


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

* Re: [Nouveau] [PATCH v7 22/23] drm/vc4: vec: Add support for more analog TV standards
       [not found]   ` <CAEFVmOKn4Won90xyX2Efh2esZ94npoy0BuTQ7n-in+KapfBb=w@mail.gmail.com>
@ 2022-11-08 22:16     ` Mateusz Kwiatkowski
  0 siblings, 0 replies; 17+ messages in thread
From: Mateusz Kwiatkowski @ 2022-11-08 22:16 UTC (permalink / raw)
  To: Lukas Satin, Maxime Ripard
  Cc: Jani Nikula, Joonas Lahtinen, Tvrtko Ursulin, Ben Skeggs,
	Rodrigo Vivi, Maxime Ripard, Samuel Holland, Jernej Skrabec,
	Maarten Lankhorst, Emma Anholt, Karol Herbst, Daniel Vetter,
	Chen-Yu Tsai, Lyude Paul, Thomas Zimmermann, David Airlie,
	Dom Cobley, nouveau, intel-gfx, linux-kernel, dri-devel,
	Phil Elwell, Hans de Goede, Noralf Trønnes,
	Geert Uytterhoeven, linux-sunxi, linux-arm-kernel

Hi Lukas, Maxime and everyone,

W dniu 8.11.2022 o 14:17, Lukas Satin pisze:
> They are important for retrogaming and connecting TV out to CRT TV or using
> emulator.
>
> I have PS1 that is using PAL-60 for example.
>
> Can you add 240p and 288p non-interlaced modes for NTSC and PAL, please?

To add progressive mode support, at least for the VC4/VEC device that's used
on the Raspberry Pi, all that's necessary is a patch like:

--- a/drivers/gpu/drm/vc4/vc4_vec.c
+++ b/drivers/gpu/drm/vc4/vc4_vec.c
@@ -623,7 +623,9 @@ static void vc4_vec_encoder_enable(struct drm_encoder *encoder,
 	VEC_WRITE(VEC_CLMP0_START, 0xac);
 	VEC_WRITE(VEC_CLMP0_END, 0xec);
 	VEC_WRITE(VEC_CONFIG2,
-		  VEC_CONFIG2_UV_DIG_DIS | VEC_CONFIG2_RGB_DIG_DIS);
+		  VEC_CONFIG2_UV_DIG_DIS |
+		  VEC_CONFIG2_RGB_DIG_DIS |
+		  ((adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) ? 0 : VEC_CONFIG2_PROG_SCAN));
 	VEC_WRITE(VEC_CONFIG3, VEC_CONFIG3_HORIZ_LEN_STD);
 	VEC_WRITE(VEC_DAC_CONFIG, vec->variant->dac_config);
 

and then you can just add custom modes, for example within Xorg:

xrandr --newmode 720x240 13.5 720 736 800 858 240 243 246 262
xrandr --newmode 720x288 13.5 720 740 804 864 288 290 293 312

Note that the pixel aspect ratio will be all over the place - unfortunately this
is necessary at the driver level, because VC4's VEC does not support pixel
clocks other than 13.5 MHz. However, you can fix it by running something like
"xrandr --scale-from 320x240" or "xrandr --scale-from 384x288". Other (non-X)
applications would need to be adapted to similarly configure DRM scaling.

I'm not sure if Maxime wants to introduce any more code like the patch above to
facilitate progressive scan support, though (@Maxime: feel free to grab the code
from above or anything else from https://github.com/raspberrypi/linux/pull/4406
if you do, however!). We talked recently that the priority is to finally merge
existing functionality first, see this message:
https://lore.kernel.org/dri-devel/20221027115822.5vd3fqlcpy4gfq5v@houat/

I'm willing to post a couple of follow-up patches to improve things like
support for progressive modes or exotic TV norms (such as PAL-M-50 or PAL-N-60)
within the VC4 driver once this patchset lands - but I agree with Maxime's point
to focus on merging existing functionality first.

> Lukas

Best regards,
Mateusz Kwiatkowski

> On Mon, Nov 7, 2022 at 3:19 PM Maxime Ripard <maxime@cerno.tech> wrote:
>
>     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.
>
>     Acked-by: Noralf Trønnes <noralf@tronnes.org>
>     Signed-off-by: Mateusz Kwiatkowski <kfyatek+publicgit@gmail.com>
>     Signed-off-by: Maxime Ripard <maxime@cerno.tech>
>
>     ---
>     Changes in v6:
>     - Support PAL60 again
>     ---
>      drivers/gpu/drm/vc4/vc4_vec.c | 111 ++++++++++++++++++++++++++++++++++++++++--
>      1 file changed, 107 insertions(+), 4 deletions(-)
>
>     diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c
>     index a828fc6fb776..d23dbad3cbf6 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
>
>     @@ -197,10 +227,15 @@ enum vc4_vec_tv_mode_id {
>             VC4_VEC_TV_MODE_NTSC_J,
>             VC4_VEC_TV_MODE_PAL,
>             VC4_VEC_TV_MODE_PAL_M,
>     +       VC4_VEC_TV_MODE_NTSC_443,
>     +       VC4_VEC_TV_MODE_PAL_60,
>     +       VC4_VEC_TV_MODE_PAL_N,
>     +       VC4_VEC_TV_MODE_SECAM,
>      };
>
>      struct vc4_vec_tv_mode {
>             unsigned int mode;
>     +       u16 expected_htotal;
>             u32 config0;
>             u32 config1;
>             u32 custom_freq;
>     @@ -236,35 +271,68 @@ static const struct debugfs_reg32 vec_regs[] = {
>      static const struct vc4_vec_tv_mode vc4_vec_tv_modes[] = {
>             {
>                     .mode = DRM_MODE_TV_MODE_NTSC,
>     +               .expected_htotal = 858,
>                     .config0 = VEC_CONFIG0_NTSC_STD | VEC_CONFIG0_PDEN,
>                     .config1 = VEC_CONFIG1_C_CVBS_CVBS,
>             },
>     +       {
>     +               .mode = DRM_MODE_TV_MODE_NTSC_443,
>     +               .expected_htotal = 858,
>     +               .config0 = VEC_CONFIG0_NTSC_STD,
>     +               .config1 = VEC_CONFIG1_C_CVBS_CVBS | VEC_CONFIG1_CUSTOM_FREQ,
>     +               .custom_freq = 0x2a098acb,
>     +       },
>             {
>                     .mode = DRM_MODE_TV_MODE_NTSC_J,
>     +               .expected_htotal = 858,
>                     .config0 = VEC_CONFIG0_NTSC_STD,
>                     .config1 = VEC_CONFIG1_C_CVBS_CVBS,
>             },
>             {
>                     .mode = DRM_MODE_TV_MODE_PAL,
>     +               .expected_htotal = 864,
>                     .config0 = VEC_CONFIG0_PAL_BDGHI_STD,
>                     .config1 = VEC_CONFIG1_C_CVBS_CVBS,
>             },
>     +       {
>     +               /* PAL-60 */
>     +               .mode = DRM_MODE_TV_MODE_PAL,
>     +               .expected_htotal = 858,
>     +               .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_M,
>     +               .expected_htotal = 858,
>                     .config0 = VEC_CONFIG0_PAL_M_STD,
>                     .config1 = VEC_CONFIG1_C_CVBS_CVBS,
>             },
>     +       {
>     +               .mode = DRM_MODE_TV_MODE_PAL_N,
>     +               .expected_htotal = 864,
>     +               .config0 = VEC_CONFIG0_PAL_N_STD,
>     +               .config1 = VEC_CONFIG1_C_CVBS_CVBS,
>     +       },
>     +       {
>     +               .mode = DRM_MODE_TV_MODE_SECAM,
>     +               .expected_htotal = 864,
>     +               .config0 = VEC_CONFIG0_SECAM_STD,
>     +               .config1 = VEC_CONFIG1_C_CVBS_CVBS,
>     +               .custom_freq = 0x29c71c72,
>     +       },
>      };
>
>      static inline const struct vc4_vec_tv_mode *
>     -vc4_vec_tv_mode_lookup(unsigned int mode)
>     +vc4_vec_tv_mode_lookup(unsigned int mode, u16 htotal)
>      {
>             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)
>     +               if (tv_mode->mode == mode &&
>     +                   tv_mode->expected_htotal == htotal)
>                             return tv_mode;
>             }
>
>     @@ -273,9 +341,13 @@ vc4_vec_tv_mode_lookup(unsigned int mode)
>
>      static const struct drm_prop_enum_list legacy_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
>     @@ -306,11 +378,16 @@ vc4_vec_connector_set_property(struct drm_connector *connector,
>                     state->tv.mode = DRM_MODE_TV_MODE_NTSC;
>                     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;
>
>             case VC4_VEC_TV_MODE_PAL:
>     +       case VC4_VEC_TV_MODE_PAL_60:
>                     state->tv.mode = DRM_MODE_TV_MODE_PAL;
>                     break;
>
>     @@ -318,6 +395,14 @@ vc4_vec_connector_set_property(struct drm_connector *connector,
>                     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;
>     +               break;
>     +
>             default:
>                     return -EINVAL;
>             }
>     @@ -341,6 +426,10 @@ vc4_vec_connector_get_property(struct drm_connector *connector,
>                     *val = VC4_VEC_TV_MODE_NTSC;
>                     break;
>
>     +       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;
>     @@ -353,6 +442,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:
>     +               *val = VC4_VEC_TV_MODE_SECAM;
>     +               break;
>     +
>             default:
>                     return -EINVAL;
>             }
>     @@ -448,13 +545,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);
>     +       struct drm_display_mode *adjusted_mode =
>     +               &encoder->crtc->state->adjusted_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);
>     +       tv_mode = vc4_vec_tv_mode_lookup(conn_state->tv.mode,
>     +                                        adjusted_mode->htotal);
>             if (!tv_mode)
>                     goto err_dev_exit;
>
>     @@ -648,9 +748,12 @@ static int vc4_vec_bind(struct device *dev, struct device *master, void *data)
>
>             ret = drm_mode_create_tv_properties(drm,
>                                                 BIT(DRM_MODE_TV_MODE_NTSC) |
>     +                                           BIT(DRM_MODE_TV_MODE_NTSC_443) |
>                                                 BIT(DRM_MODE_TV_MODE_NTSC_J) |
>                                                 BIT(DRM_MODE_TV_MODE_PAL) |
>     -                                           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));
>             if (ret)
>                     return ret;
>
>
>     -- 
>     b4 0.11.0-dev-99e3a 
>


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

* Re: [PATCH v7 22/23] drm/vc4: vec: Add support for more analog TV standards
       [not found] ` <20220728-rpi-analog-tv-properties-v7-22-7072a478c6b3@cerno.tech>
       [not found]   ` <CAEFVmOKn4Won90xyX2Efh2esZ94npoy0BuTQ7n-in+KapfBb=w@mail.gmail.com>
@ 2022-11-09  1:15   ` Mateusz Kwiatkowski
       [not found]     ` <CAEFVmOJ5A7+hUPwb3yUiVegJfUb_1-DGKu1YUCsF=hFTrjASzA@mail.gmail.com>
  2022-11-10 10:57     ` Maxime Ripard
  1 sibling, 2 replies; 17+ messages in thread
From: Mateusz Kwiatkowski @ 2022-11-09  1:15 UTC (permalink / raw)
  To: Maxime Ripard, Jani Nikula, Joonas Lahtinen, Tvrtko Ursulin,
	Ben Skeggs, Rodrigo Vivi, Maxime Ripard, Samuel Holland,
	Jernej Skrabec, Maarten Lankhorst, Emma Anholt, Karol Herbst,
	Daniel Vetter, Chen-Yu Tsai, Lyude Paul, Thomas Zimmermann,
	David Airlie
  Cc: Phil Elwell, Hans de Goede, linux-sunxi, linux-kernel,
	Geert Uytterhoeven, Dave Stevenson, linux-arm-kernel, Dom Cobley,
	dri-devel, intel-gfx, nouveau, Noralf Trønnes

Hi Maxime,

I ran your v7 patchset on my Pi with Xorg, and the mode switching, as well as
the preferred mode handling, all work really well now!

I just noted that the downstream version of the vc4 driver still has inaccurate
field delays in vc4_crtc.c, which causes vertical lines to appear jagged (like
here: https://user-images.githubusercontent.com/4499762/112738569-385c3280-8f64-11eb-83c4-d671537af209.png).
This has been fixed downstream in
https://github.com/raspberrypi/linux/pull/4241/commits/bc093f27bf2613ec93524fdc19e922dd7dd3d800,
but I guess that should be upstreamed separately...?

Anyway, it's unrelated to the changes made in this patchset, so... I'm not sure
if I'm qualified or allowed to do these, but just in case:

Tested-by: Mateusz Kwiatkowski <kfyatek+publicgit@gmail.com>

(that pretty much applies to parts 19-22 in general, I can respond to those
messages as well if you wish)

Best regards,
Mateusz Kwiatkowski

W dniu 7.11.2022 o 15:16, Maxime Ripard pisze:
> 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.
>
> Acked-by: Noralf Trønnes <noralf@tronnes.org>
> Signed-off-by: Mateusz Kwiatkowski <kfyatek+publicgit@gmail.com>
> Signed-off-by: Maxime Ripard <maxime@cerno.tech>
>
> ---
> Changes in v6:
> - Support PAL60 again
> ---
>  drivers/gpu/drm/vc4/vc4_vec.c | 111 ++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 107 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c
> index a828fc6fb776..d23dbad3cbf6 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
>  
> @@ -197,10 +227,15 @@ enum vc4_vec_tv_mode_id {
>  	VC4_VEC_TV_MODE_NTSC_J,
>  	VC4_VEC_TV_MODE_PAL,
>  	VC4_VEC_TV_MODE_PAL_M,
> +	VC4_VEC_TV_MODE_NTSC_443,
> +	VC4_VEC_TV_MODE_PAL_60,
> +	VC4_VEC_TV_MODE_PAL_N,
> +	VC4_VEC_TV_MODE_SECAM,
>  };
>  
>  struct vc4_vec_tv_mode {
>  	unsigned int mode;
> +	u16 expected_htotal;
>  	u32 config0;
>  	u32 config1;
>  	u32 custom_freq;
> @@ -236,35 +271,68 @@ static const struct debugfs_reg32 vec_regs[] = {
>  static const struct vc4_vec_tv_mode vc4_vec_tv_modes[] = {
>  	{
>  		.mode = DRM_MODE_TV_MODE_NTSC,
> +		.expected_htotal = 858,
>  		.config0 = VEC_CONFIG0_NTSC_STD | VEC_CONFIG0_PDEN,
>  		.config1 = VEC_CONFIG1_C_CVBS_CVBS,
>  	},
> +	{
> +		.mode = DRM_MODE_TV_MODE_NTSC_443,
> +		.expected_htotal = 858,
> +		.config0 = VEC_CONFIG0_NTSC_STD,
> +		.config1 = VEC_CONFIG1_C_CVBS_CVBS | VEC_CONFIG1_CUSTOM_FREQ,
> +		.custom_freq = 0x2a098acb,
> +	},
>  	{
>  		.mode = DRM_MODE_TV_MODE_NTSC_J,
> +		.expected_htotal = 858,
>  		.config0 = VEC_CONFIG0_NTSC_STD,
>  		.config1 = VEC_CONFIG1_C_CVBS_CVBS,
>  	},
>  	{
>  		.mode = DRM_MODE_TV_MODE_PAL,
> +		.expected_htotal = 864,
>  		.config0 = VEC_CONFIG0_PAL_BDGHI_STD,
>  		.config1 = VEC_CONFIG1_C_CVBS_CVBS,
>  	},
> +	{
> +		/* PAL-60 */
> +		.mode = DRM_MODE_TV_MODE_PAL,
> +		.expected_htotal = 858,
> +		.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_M,
> +		.expected_htotal = 858,
>  		.config0 = VEC_CONFIG0_PAL_M_STD,
>  		.config1 = VEC_CONFIG1_C_CVBS_CVBS,
>  	},
> +	{
> +		.mode = DRM_MODE_TV_MODE_PAL_N,
> +		.expected_htotal = 864,
> +		.config0 = VEC_CONFIG0_PAL_N_STD,
> +		.config1 = VEC_CONFIG1_C_CVBS_CVBS,
> +	},
> +	{
> +		.mode = DRM_MODE_TV_MODE_SECAM,
> +		.expected_htotal = 864,
> +		.config0 = VEC_CONFIG0_SECAM_STD,
> +		.config1 = VEC_CONFIG1_C_CVBS_CVBS,
> +		.custom_freq = 0x29c71c72,
> +	},
>  };
>  
>  static inline const struct vc4_vec_tv_mode *
> -vc4_vec_tv_mode_lookup(unsigned int mode)
> +vc4_vec_tv_mode_lookup(unsigned int mode, u16 htotal)
>  {
>  	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)
> +		if (tv_mode->mode == mode &&
> +		    tv_mode->expected_htotal == htotal)
>  			return tv_mode;
>  	}
>  
> @@ -273,9 +341,13 @@ vc4_vec_tv_mode_lookup(unsigned int mode)
>  
>  static const struct drm_prop_enum_list legacy_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
> @@ -306,11 +378,16 @@ vc4_vec_connector_set_property(struct drm_connector *connector,
>  		state->tv.mode = DRM_MODE_TV_MODE_NTSC;
>  		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;
>  
>  	case VC4_VEC_TV_MODE_PAL:
> +	case VC4_VEC_TV_MODE_PAL_60:
>  		state->tv.mode = DRM_MODE_TV_MODE_PAL;
>  		break;
>  
> @@ -318,6 +395,14 @@ vc4_vec_connector_set_property(struct drm_connector *connector,
>  		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;
> +		break;
> +
>  	default:
>  		return -EINVAL;
>  	}
> @@ -341,6 +426,10 @@ vc4_vec_connector_get_property(struct drm_connector *connector,
>  		*val = VC4_VEC_TV_MODE_NTSC;
>  		break;
>  
> +	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;
> @@ -353,6 +442,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:
> +		*val = VC4_VEC_TV_MODE_SECAM;
> +		break;
> +
>  	default:
>  		return -EINVAL;
>  	}
> @@ -448,13 +545,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);
> +	struct drm_display_mode *adjusted_mode =
> +		&encoder->crtc->state->adjusted_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);
> +	tv_mode = vc4_vec_tv_mode_lookup(conn_state->tv.mode,
> +					 adjusted_mode->htotal);
>  	if (!tv_mode)
>  		goto err_dev_exit;
>  
> @@ -648,9 +748,12 @@ static int vc4_vec_bind(struct device *dev, struct device *master, void *data)
>  
>  	ret = drm_mode_create_tv_properties(drm,
>  					    BIT(DRM_MODE_TV_MODE_NTSC) |
> +					    BIT(DRM_MODE_TV_MODE_NTSC_443) |
>  					    BIT(DRM_MODE_TV_MODE_NTSC_J) |
>  					    BIT(DRM_MODE_TV_MODE_PAL) |
> -					    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));
>  	if (ret)
>  		return ret;
>  
>
*/pre>


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

* Re: [PATCH v7 15/23] drm/modes: Introduce more named modes
  2022-11-08 21:27       ` Mateusz Kwiatkowski
@ 2022-11-09 11:18         ` Maxime Ripard
  0 siblings, 0 replies; 17+ messages in thread
From: Maxime Ripard @ 2022-11-09 11:18 UTC (permalink / raw)
  To: kfyatek+publicgit
  Cc: Noralf Trønnes, Jani Nikula, Joonas Lahtinen,
	Tvrtko Ursulin, Ben Skeggs, Rodrigo Vivi, Samuel Holland,
	Jernej Skrabec, Maarten Lankhorst, Emma Anholt, Karol Herbst,
	Daniel Vetter, Chen-Yu Tsai, Lyude Paul, Thomas Zimmermann,
	David Airlie, Phil Elwell, Hans de Goede, linux-sunxi,
	linux-kernel, Geert Uytterhoeven, Dave Stevenson,
	linux-arm-kernel, Dom Cobley, dri-devel, intel-gfx, nouveau

On Tue, Nov 08, 2022 at 10:27:17PM +0100, Mateusz Kwiatkowski wrote:
> Hi Noralf,
> 
> W dniu 8.11.2022 o 10:38, Noralf Trønnes pisze:
> >
> > Den 07.11.2022 19.03, skrev Noralf Trønnes:
> >>
> >> Den 07.11.2022 15.16, skrev Maxime Ripard:
> >>> 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>
> >>>
> >>> ---
> >>> Changes in v6:
> >>> - Renamed the tests to follow DRM test naming convention
> >>>
> >>> Changes in v5:
> >>> - Switched to KUNIT_ASSERT_NOT_NULL
> >>> ---
> >>>  drivers/gpu/drm/drm_modes.c                     |  2 +
> >>>  drivers/gpu/drm/tests/drm_client_modeset_test.c | 54 +++++++++++++++++++++++++
> >>>  2 files changed, 56 insertions(+)
> >>>
> >>> diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
> >>> index 49441cabdd9d..17c5b6108103 100644
> >>> --- a/drivers/gpu/drm/drm_modes.c
> >>> +++ b/drivers/gpu/drm/drm_modes.c
> >>> @@ -2272,7 +2272,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),
> >>> +	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),
> >>> +	NAMED_MODE("PAL-M", 13500, 720, 480, DRM_MODE_FLAG_INTERLACE, DRM_MODE_TV_MODE_PAL_M),
> >>>  };
> >> I'm now having second thoughts about the tv_mode commandline option. Can
> >> we just add all the variants to this table and drop the tv_mode option?
> >> IMO this will be more user friendly and less confusing.
> >>
> > One downside of this is that it's not possible to force connector status
> > when using named modes, but I think it would be better to have a force
> > option than a tv_mode option. A lot of userspace treats unknown status
> > as disconnected.
> >
> > Anyone know if it's possible to set the connector status sysfs file
> > using a udev rule?
> >
> > Noralf.
> 
> I think that leaving named modes only would be a bit limiting. There are use
> cases for custom modes, e.g. we might want progressive 240p "NTSC" (like 80s/90s
> home computers and video game consoles) or the modes with non-13.5MHz pixel
> clock that Geert requested with Amiga in mind.

Yeah, it was one of the early requirements that we would be allowed to
fill in any analog mode on the command line, so just having the named
modes with the 480i and 576i modes won't really work for that.

> I'm not sure if the current cmdline-to-drm_mode conversion is flexible enough
> to meaningfully facilitate those, but we're at least getting the syntax down.

It might require a bit of plumbing to get
drm_mode_create_from_cmdline_mode() to add the mode if tv_mode_specified
is set, but it's probably it.

Maxime

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

* Re: [PATCH v7 15/23] drm/modes: Introduce more named modes
       [not found] ` <20220728-rpi-analog-tv-properties-v7-15-7072a478c6b3@cerno.tech>
  2022-11-07 18:03   ` [PATCH v7 15/23] drm/modes: Introduce more named modes Noralf Trønnes
@ 2022-11-09 14:09   ` Noralf Trønnes
  1 sibling, 0 replies; 17+ messages in thread
From: Noralf Trønnes @ 2022-11-09 14:09 UTC (permalink / raw)
  To: Maxime Ripard, Jani Nikula, Joonas Lahtinen, Tvrtko Ursulin,
	Ben Skeggs, Rodrigo Vivi, Maxime Ripard, Samuel Holland,
	Jernej Skrabec, Maarten Lankhorst, Emma Anholt, Karol Herbst,
	Daniel Vetter, Chen-Yu Tsai, Lyude Paul, Thomas Zimmermann,
	David Airlie
  Cc: Phil Elwell, Hans de Goede, linux-sunxi, linux-kernel,
	Geert Uytterhoeven, Dave Stevenson, linux-arm-kernel, Dom Cobley,
	Mateusz Kwiatkowski, dri-devel, intel-gfx, nouveau,
	Noralf Trønnes



Den 07.11.2022 15.16, skrev Maxime Ripard:
> 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>
> 
> ---
> Changes in v6:
> - Renamed the tests to follow DRM test naming convention
> 
> Changes in v5:
> - Switched to KUNIT_ASSERT_NOT_NULL
> ---
>  drivers/gpu/drm/drm_modes.c                     |  2 +
>  drivers/gpu/drm/tests/drm_client_modeset_test.c | 54 +++++++++++++++++++++++++
>  2 files changed, 56 insertions(+)
> 
> diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
> index 49441cabdd9d..17c5b6108103 100644
> --- a/drivers/gpu/drm/drm_modes.c
> +++ b/drivers/gpu/drm/drm_modes.c
> @@ -2272,7 +2272,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),
> +	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),
> +	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 fdfe9e20702e..b3820d25beca 100644
> --- a/drivers/gpu/drm/tests/drm_client_modeset_test.c
> +++ b/drivers/gpu/drm/tests/drm_client_modeset_test.c
> @@ -133,6 +133,32 @@ static void drm_test_pick_cmdline_named_ntsc(struct kunit *test)
>  	KUNIT_EXPECT_TRUE(test, drm_mode_equal(drm_mode_analog_ntsc_480i(drm), mode));
>  }
>  
> +static void drm_test_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_NOT_NULL(test, mode);
> +
> +	KUNIT_EXPECT_TRUE(test, drm_mode_equal(drm_mode_analog_ntsc_480i(drm), mode));
> +}
> +
>  static void drm_test_pick_cmdline_named_pal(struct kunit *test)
>  {
>  	struct drm_client_modeset_test_priv *priv = test->priv;
> @@ -159,10 +185,38 @@ static void drm_test_pick_cmdline_named_pal(struct kunit *test)
>  	KUNIT_EXPECT_TRUE(test, drm_mode_equal(drm_mode_analog_pal_576i(drm), mode));
>  }
>  
> +static void drm_test_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_NOT_NULL(test, mode);
> +
> +	KUNIT_EXPECT_TRUE(test, drm_mode_equal(drm_mode_analog_ntsc_480i(drm), mode));
> +}
> +

There are 4 named mode tests that are almost identical, should probably
use KUNIT_ARRAY_PARAM like in the parser tests.

This patchset has been going on for a long time now so it can be fixed
later if you don't want to do it now:

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

>  static struct kunit_case drm_test_pick_cmdline_tests[] = {
>  	KUNIT_CASE(drm_test_pick_cmdline_res_1920_1080_60),
>  	KUNIT_CASE(drm_test_pick_cmdline_named_ntsc),
> +	KUNIT_CASE(drm_test_pick_cmdline_named_ntsc_j),
>  	KUNIT_CASE(drm_test_pick_cmdline_named_pal),
> +	KUNIT_CASE(drm_test_pick_cmdline_named_pal_m),
>  	{}
>  };
>  
> 

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

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

Hi Noralf,

On Mon, Nov 07, 2022 at 07:11:27PM +0100, Noralf Trønnes wrote:
> 
> 
> Den 07.11.2022 15.16, skrev Maxime Ripard:
> > From: Noralf Trønnes <noralf@tronnes.org>
> > 
> > Most of the TV connectors will need a similar get_modes implementation
> > that will, depending on the drivers' capabilities, register the 480i and
> > 576i modes.
> > 
> > That implementation will also need to set the preferred flag and order
> > the modes based on the driver and users preferrence.
> > 
> > This is especially important to guarantee that a userspace stack such as
> > Xorg can start and pick up the preferred mode while maintaining a
> > working output.
> > 
> > Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
> > Signed-off-by: Maxime Ripard <maxime@cerno.tech>
> > 
> > ---
> > Changes in v7:
> > - Used Noralf's implementation
> > 
> > Changes in v6:
> > - New patch
> > ---
> >  drivers/gpu/drm/drm_probe_helper.c | 97 ++++++++++++++++++++++++++++++++++++++
> >  include/drm/drm_probe_helper.h     |  1 +
> >  2 files changed, 98 insertions(+)
> > 
> > diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c
> > index 2fc21df709bc..edb2e4c4530a 100644
> > --- a/drivers/gpu/drm/drm_probe_helper.c
> > +++ b/drivers/gpu/drm/drm_probe_helper.c
> > @@ -1147,3 +1147,100 @@ int drm_connector_helper_get_modes(struct drm_connector *connector)
> >  	return count;
> >  }
> >  EXPORT_SYMBOL(drm_connector_helper_get_modes);
> > +
> > +static bool tv_mode_supported(struct drm_connector *connector,
> > +			      enum drm_connector_tv_mode mode)
> > +{
> > +	struct drm_device *dev = connector->dev;
> > +	struct drm_property *property = dev->mode_config.tv_mode_property;
> > +
> > +	unsigned int i;
> > +
> > +	for (i = 0; i < property->num_values; i++)
> > +		if (property->values[i] == mode)
> > +			return true;
> > +
> > +	return false;
> > +}
> 
> This function is not used in the new implementation.
>
> I hope you have tested this patch since I didn't even compile test my
> implementation (probably should have said so...)

You nailed it ;)

I had tested it (but missed the warning), and added unit tests to make
sure it was behaving properly, and it did. I'll send the unit tests in
my next version.

Thanks
Maxime

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

* Re: [PATCH v7 14/23] drm/modes: Properly generate a drm_display_mode from a named mode
  2022-11-07 17:49   ` [PATCH v7 14/23] drm/modes: Properly generate a drm_display_mode from a named mode Noralf Trønnes
  2022-11-08  9:40     ` Noralf Trønnes
@ 2022-11-10  9:31     ` Maxime Ripard
  1 sibling, 0 replies; 17+ messages in thread
From: Maxime Ripard @ 2022-11-10  9:31 UTC (permalink / raw)
  To: Noralf Trønnes
  Cc: Jani Nikula, Joonas Lahtinen, Tvrtko Ursulin, Ben Skeggs,
	Rodrigo Vivi, Samuel Holland, Jernej Skrabec, Maarten Lankhorst,
	Emma Anholt, Karol Herbst, Daniel Vetter, Chen-Yu Tsai,
	Lyude Paul, Thomas Zimmermann, David Airlie, Phil Elwell,
	Hans de Goede, linux-sunxi, linux-kernel, Geert Uytterhoeven,
	Dave Stevenson, linux-arm-kernel, Dom Cobley,
	Mateusz Kwiatkowski, dri-devel, intel-gfx, nouveau

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

Hi,

On Mon, Nov 07, 2022 at 06:49:57PM +0100, Noralf Trønnes wrote:
> Den 07.11.2022 15.16, skrev Maxime Ripard:
> > 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>
> > 
> > ---
> > Changes in v7:
> > - Use tv_mode_specified in drm_mode_parse_command_line_for_connector
> > 
> > Changes in v6:
> > - Fix get_modes to return 0 instead of an error code
> > - Rename the tests to follow the DRM test naming convention
> > 
> > Changes in v5:
> > - Switched to KUNIT_ASSERT_NOT_NULL
> > ---
> >  drivers/gpu/drm/drm_modes.c                     | 34 ++++++++++-
> >  drivers/gpu/drm/tests/drm_client_modeset_test.c | 77 ++++++++++++++++++++++++-
> >  2 files changed, 109 insertions(+), 2 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
> > index dc037f7ceb37..49441cabdd9d 100644
> > --- a/drivers/gpu/drm/drm_modes.c
> > +++ b/drivers/gpu/drm/drm_modes.c
> > @@ -2497,6 +2497,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 (!cmd->tv_mode_specified)
> > +			continue;
> 
> Only a named mode will set cmd->name, so is this check necessary?

Yeah, but (and even though it's not the case at the moment) there's no
implication that a named mode will be about TV. We could use it for
VGA/XGA/etc just as well, in which case we wouldn't have
tv_mode_specified.

Maxime

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

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

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

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

On Tue, Nov 08, 2022 at 10:40:07AM +0100, Noralf Trønnes wrote:
> 
> 
> Den 07.11.2022 18.49, skrev Noralf Trønnes:
> > 
> > 
> > Den 07.11.2022 15.16, skrev Maxime Ripard:
> >> 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>
> >>
> >> ---
> >> Changes in v7:
> >> - Use tv_mode_specified in drm_mode_parse_command_line_for_connector
> >>
> >> Changes in v6:
> >> - Fix get_modes to return 0 instead of an error code
> >> - Rename the tests to follow the DRM test naming convention
> >>
> >> Changes in v5:
> >> - Switched to KUNIT_ASSERT_NOT_NULL
> >> ---
> >>  drivers/gpu/drm/drm_modes.c                     | 34 ++++++++++-
> >>  drivers/gpu/drm/tests/drm_client_modeset_test.c | 77 ++++++++++++++++++++++++-
> >>  2 files changed, 109 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
> >> index dc037f7ceb37..49441cabdd9d 100644
> >> --- a/drivers/gpu/drm/drm_modes.c
> >> +++ b/drivers/gpu/drm/drm_modes.c
> >> @@ -2497,6 +2497,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 (!cmd->tv_mode_specified)
> >> +			continue;
> > 
> > Only a named mode will set cmd->name, so is this check necessary?
> > 
> >> +
> >> +		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;
> > 
> > You can just return the result from drm_analog_tv_mode() directly.
> > 
> > With those considered:
> > 
> > Reviewed-by: Noralf Trønnes <noralf@tronnes.org>
> > 
> 
> I forgot one thing, shouldn't the named mode test in
> drm_connector_pick_cmdline_mode() be removed now that we have proper modes?

Good catch, I've fixed it

Thanks!
Maxime

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

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

* Re: [Nouveau] [PATCH v7 22/23] drm/vc4: vec: Add support for more analog TV standards
       [not found]     ` <CAEFVmOJ5A7+hUPwb3yUiVegJfUb_1-DGKu1YUCsF=hFTrjASzA@mail.gmail.com>
@ 2022-11-10 10:39       ` Maxime Ripard
  0 siblings, 0 replies; 17+ messages in thread
From: Maxime Ripard @ 2022-11-10 10:39 UTC (permalink / raw)
  To: Lukas Satin
  Cc: kfyatek+publicgit, Jani Nikula, Joonas Lahtinen, Tvrtko Ursulin,
	Ben Skeggs, Rodrigo Vivi, Samuel Holland, Jernej Skrabec,
	Maarten Lankhorst, Emma Anholt, Karol Herbst, Daniel Vetter,
	Chen-Yu Tsai, Lyude Paul, Thomas Zimmermann, David Airlie,
	Dom Cobley, nouveau, intel-gfx, linux-kernel, dri-devel,
	linux-sunxi, Hans de Goede, Noralf Trønnes,
	Geert Uytterhoeven, Phil Elwell, linux-arm-kernel

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

On Wed, Nov 09, 2022 at 05:55:36PM +0100, Lukas Satin wrote:
> That's great, I will test it on Ubuntu + Nouveau x86_64 and Batocera-Linux.
> 
> I'm not interested in Raspberry Pi. I see you have some commit in
> RaspberryPi/Linux. Will this go to some Nouveau driver, so I can test it on
> x86_64 machine? I have some basic experience compiling Linux kernel (nvidia
> driver) from 10 years ago.

Nouveau is only marginally affected by this patch series. It could
leverage the work done here, but it's not part of it and I won't plan to
work on it.

The RaspberryPi is mentioned because it's the platform that will benefit
the most from it, and the main target of that series.

> Scaling is not the way to go because I do this to not use scaling. I could
> use 640x480 and scale 320x240 to that mode, right? That is what old
> retrogaming laptop LCD screens do (you can even enable this in their BIOS).
> 
> More appropriate is to preserve pixel ratio and have some border. So you
> mostly select the closest resolution and live with small border on the
> edge. Then you can crop it on analog TV using real world dials :-)
> 
> I joined Nouveau developer list here. I don't know why we have like 40
> email recipients here and now we discuss Raspberry.

Nouveau is marginally affected by it, so its mailing list is in Cc.

Maxime

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

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

* Re: [PATCH v7 22/23] drm/vc4: vec: Add support for more analog TV standards
  2022-11-09  1:15   ` Mateusz Kwiatkowski
       [not found]     ` <CAEFVmOJ5A7+hUPwb3yUiVegJfUb_1-DGKu1YUCsF=hFTrjASzA@mail.gmail.com>
@ 2022-11-10 10:57     ` Maxime Ripard
  1 sibling, 0 replies; 17+ messages in thread
From: Maxime Ripard @ 2022-11-10 10:57 UTC (permalink / raw)
  To: kfyatek+publicgit
  Cc: Jani Nikula, Joonas Lahtinen, Tvrtko Ursulin, Ben Skeggs,
	Rodrigo Vivi, Samuel Holland, Jernej Skrabec, Maarten Lankhorst,
	Emma Anholt, Karol Herbst, Daniel Vetter, Chen-Yu Tsai,
	Lyude Paul, Thomas Zimmermann, David Airlie, Phil Elwell,
	Hans de Goede, linux-sunxi, linux-kernel, Geert Uytterhoeven,
	Dave Stevenson, linux-arm-kernel, Dom Cobley, dri-devel,
	intel-gfx, nouveau, Noralf Trønnes

Hi!

On Wed, Nov 09, 2022 at 02:15:29AM +0100, Mateusz Kwiatkowski wrote:
> I ran your v7 patchset on my Pi with Xorg, and the mode switching, as well as
> the preferred mode handling, all work really well now!

Thanks again for all your help

> I just noted that the downstream version of the vc4 driver still has inaccurate
> field delays in vc4_crtc.c, which causes vertical lines to appear jagged (like
> here: https://user-images.githubusercontent.com/4499762/112738569-385c3280-8f64-11eb-83c4-d671537af209.png).
> This has been fixed downstream in
> https://github.com/raspberrypi/linux/pull/4241/commits/bc093f27bf2613ec93524fdc19e922dd7dd3d800,
> but I guess that should be upstreamed separately...?

I guess I missed it while rebasing, but yeah, it should definitely be
upstreamed.

Maxime

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

end of thread, other threads:[~2022-11-10 10:57 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <20220728-rpi-analog-tv-properties-v7-0-7072a478c6b3@cerno.tech>
     [not found] ` <20220728-rpi-analog-tv-properties-v7-14-7072a478c6b3@cerno.tech>
2022-11-07 17:49   ` [PATCH v7 14/23] drm/modes: Properly generate a drm_display_mode from a named mode Noralf Trønnes
2022-11-08  9:40     ` Noralf Trønnes
2022-11-10 10:36       ` Maxime Ripard
2022-11-10  9:31     ` Maxime Ripard
     [not found] ` <20220728-rpi-analog-tv-properties-v7-15-7072a478c6b3@cerno.tech>
2022-11-07 18:03   ` [PATCH v7 15/23] drm/modes: Introduce more named modes Noralf Trønnes
2022-11-08  9:38     ` Noralf Trønnes
2022-11-08 21:27       ` Mateusz Kwiatkowski
2022-11-09 11:18         ` Maxime Ripard
2022-11-09 14:09   ` Noralf Trønnes
     [not found] ` <20220728-rpi-analog-tv-properties-v7-16-7072a478c6b3@cerno.tech>
2022-11-07 18:11   ` [PATCH v7 16/23] drm/probe-helper: Provide a TV get_modes helper Noralf Trønnes
2022-11-09 15:41     ` Maxime Ripard
     [not found] ` <CAEFVmOKCTc_ZrFyCxiSwCmhtjJj_fzr6n99cWtb9aECFzzYVXg@mail.gmail.com>
2022-11-08 13:42   ` [Nouveau] [PATCH v7 00/23] drm: Analog TV Improvements Geert Uytterhoeven
     [not found] ` <20220728-rpi-analog-tv-properties-v7-6-7072a478c6b3@cerno.tech>
     [not found]   ` <CAEFVmOJbjK2iug+UsxD8w7W0RTc0AGD=wxB5bX-es=Qc-Mcgrw@mail.gmail.com>
2022-11-08 21:51     ` [Nouveau] [PATCH v7 06/23] drm/modes: Add a function to generate analog display modes Mateusz Kwiatkowski
     [not found] ` <20220728-rpi-analog-tv-properties-v7-22-7072a478c6b3@cerno.tech>
     [not found]   ` <CAEFVmOKn4Won90xyX2Efh2esZ94npoy0BuTQ7n-in+KapfBb=w@mail.gmail.com>
2022-11-08 22:16     ` [Nouveau] [PATCH v7 22/23] drm/vc4: vec: Add support for more analog TV standards Mateusz Kwiatkowski
2022-11-09  1:15   ` Mateusz Kwiatkowski
     [not found]     ` <CAEFVmOJ5A7+hUPwb3yUiVegJfUb_1-DGKu1YUCsF=hFTrjASzA@mail.gmail.com>
2022-11-10 10:39       ` [Nouveau] " Maxime Ripard
2022-11-10 10:57     ` Maxime Ripard

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

Powered by JetHome