diff mbox series

drm/sun4i: uncouple DSI dotclock divider from TCON0_DCLK_REG

Message ID 20230320161636.24411-1-romanberanek@icloud.com (mailing list archive)
State New, archived
Headers show
Series drm/sun4i: uncouple DSI dotclock divider from TCON0_DCLK_REG | expand

Commit Message

Roman Beranek March 20, 2023, 4:16 p.m. UTC
In the case of DSI output, the value of SUN4I_TCON0_DCLK_DIV (4) does
not represent the actual dotclock divider, PLL_MIPI instead runs at
(bpp / lanes )-multiple [1] of the dotclock. [2] Setting 4 as dotclock
divder thus leads to reduced frame rate, specifically by 1/3 on 4-lane
panels, and by 2/3 on 2-lane panels respectively.

As sun4i_dotclock driver stores its calculated divider directly in
the register, conditional handling of the DSI output scenario is needed.
Instead of reading the divider from SUN4I_TCON0_DCLK_REG, retrieve
the value from tcon->dclk_min_div.

[1] bits per pixel / number of DSI lanes
[2] https://github.com/BPI-SINOVOIP/BPI-M64-bsp-4.4/blob/66bef0f2f30b367eb93b1cbad21ce85e0361f7ae/linux-sunxi/drivers/video/fbdev/sunxi/disp2/disp/de/lowlevel_sun50iw1/disp_al.c#L322

Signed-off-by: Roman Beranek <romanberanek@icloud.com>
---
 drivers/gpu/drm/sun4i/sun4i_dotclock.c | 6 +++++-
 drivers/gpu/drm/sun4i/sun4i_tcon.c     | 5 +++--
 drivers/gpu/drm/sun4i/sun4i_tcon.h     | 1 +
 3 files changed, 9 insertions(+), 3 deletions(-)

Comments

Maxime Ripard March 21, 2023, 2:56 p.m. UTC | #1
Hi,

On Mon, Mar 20, 2023 at 05:16:36PM +0100, Roman Beranek wrote:
> In the case of DSI output, the value of SUN4I_TCON0_DCLK_DIV (4) does
> not represent the actual dotclock divider, PLL_MIPI instead runs at
> (bpp / lanes )-multiple [1] of the dotclock. [2] Setting 4 as dotclock
> divder thus leads to reduced frame rate, specifically by 1/3 on 4-lane
> panels, and by 2/3 on 2-lane panels respectively.
> 
> As sun4i_dotclock driver stores its calculated divider directly in
> the register, conditional handling of the DSI output scenario is needed.
> Instead of reading the divider from SUN4I_TCON0_DCLK_REG, retrieve
> the value from tcon->dclk_min_div.
> 
> [1] bits per pixel / number of DSI lanes
> [2] https://github.com/BPI-SINOVOIP/BPI-M64-bsp-4.4/blob/66bef0f2f30b367eb93b1cbad21ce85e0361f7ae/linux-sunxi/drivers/video/fbdev/sunxi/disp2/disp/de/lowlevel_sun50iw1/disp_al.c#L322
> 
> Signed-off-by: Roman Beranek <romanberanek@icloud.com>

This is similar to
https://lore.kernel.org/all/20230319160704.9858-2-frank@oltmanns.dev/

What's the story there? Also, how was it tested/confirmed?

Maxime
Roman Beranek March 21, 2023, 4:50 p.m. UTC | #2
Hello Maxime,

On Tue Mar 21, 2023 at 3:56 PM CET, Maxime Ripard wrote:
>
> This is similar to
> https://lore.kernel.org/all/20230319160704.9858-2-frank@oltmanns.dev/
>
> What's the story there?

Yes, Frank Oltmanns wrote me recently in relation to a patch I wrote
~ 3 years ago that addressed the framerate issue, proposing to
collaborate on pushing it upstream, however as I've been keeping up
with my inbox rather sporadically these days, by the time I read his
message, Frank had already taken the initiative and sent the patch.
So that's how we've got to this slightly awkward situation with two
patches on the same subject arriving 1 day apart of each other.

The problem with the original patch was that it went around
sun4i_dotclock by feeding it a rate adjusted such that the pll-mipi rate
was set correctly. I couldn't quite figure out at the time of how big
a portion of the tcon logic does the sun4i_dotclock code need to be made
aware of.

>Also, how was it tested/confirmed?

By counting Vblank interrupts (GIC 118).

Roman
Roman Beranek March 21, 2023, 8:53 p.m. UTC | #3
On Tue Mar 21, 2023 at 5:50 PM CET, Roman Beranek wrote:

> > Also, how was it tested/confirmed?
>
> By counting Vblank interrupts (GIC 118).

Sorry, that was perhaps too abbreviated. To test this change, I set up
an A64 board running kmscube on DSI-1 and verified that the rate of
Vblank IRQs tracked with a video mode set on DSI-1, once with a 2-lane
panel and once with a 4-lane panel.

Roman
Frank Oltmanns March 25, 2023, 11:40 a.m. UTC | #4
Hi,

On 2023-03-20 at 17:16:36 +0100, Roman Beranek <romanberanek@icloud.com> wrote:
> In the case of DSI output, the value of SUN4I_TCON0_DCLK_DIV (4) does
> not represent the actual dotclock divider, PLL_MIPI instead runs at
> (bpp / lanes )-multiple [1] of the dotclock. [2] Setting 4 as dotclock
> divder thus leads to reduced frame rate, specifically by 1/3 on 4-lane
> panels, and by 2/3 on 2-lane panels respectively.
>
> As sun4i_dotclock driver stores its calculated divider directly in
> the register, conditional handling of the DSI output scenario is needed.
> Instead of reading the divider from SUN4I_TCON0_DCLK_REG, retrieve
> the value from tcon->dclk_min_div.
>
> [1] bits per pixel / number of DSI lanes
> [2] <https://github.com/BPI-SINOVOIP/BPI-M64-bsp-4.4/blob/66bef0f2f30b367eb93b1cbad21ce85e0361f7ae/linux-sunxi/drivers/video/fbdev/sunxi/disp2/disp/de/lowlevel_sun50iw1/disp_al.c#L322>
>
> Signed-off-by: Roman Beranek <romanberanek@icloud.com>
> —
>  drivers/gpu/drm/sun4i/sun4i_dotclock.c | 6 +++++-
>  drivers/gpu/drm/sun4i/sun4i_tcon.c     | 5 +++–
>  drivers/gpu/drm/sun4i/sun4i_tcon.h     | 1 +
>  3 files changed, 9 insertions(+), 3 deletions(-)
>
> diff –git a/drivers/gpu/drm/sun4i/sun4i_dotclock.c b/drivers/gpu/drm/sun4i/sun4i_dotclock.c
> index 417ade3d2565..26fa99aff590 100644
> — a/drivers/gpu/drm/sun4i/sun4i_dotclock.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_dotclock.c
> @@ -11,6 +11,7 @@
>
>  #include “sun4i_tcon.h”
>  #include “sun4i_dotclock.h”
> +#include “sun6i_mipi_dsi.h”
>
>  struct sun4i_dclk {
>  	struct clk_hw  hw;
> @@ -56,6 +57,9 @@ static unsigned long sun4i_dclk_recalc_rate(struct clk_hw *hw,
>  	struct sun4i_dclk *dclk = hw_to_dclk(hw);
>  	u32 val;
>
> +	if (dclk->tcon->is_dsi)
> +		return parent_rate / dclk->tcon->dclk_min_div;
> +
>  	regmap_read(dclk->regmap, SUN4I_TCON0_DCLK_REG, &val);
>
>  	val >>= SUN4I_TCON0_DCLK_DIV_SHIFT;
> @@ -116,7 +120,7 @@ static int sun4i_dclk_set_rate(struct clk_hw *hw, unsigned long rate,
>  			       unsigned long parent_rate)
>  {
>  	struct sun4i_dclk *dclk = hw_to_dclk(hw);
> -	u8 div = parent_rate / rate;
> +	u8 div = dclk->tcon->is_dsi ? SUN6I_DSI_TCON_DIV : parent_rate / rate;
>
>  	return regmap_update_bits(dclk->regmap, SUN4I_TCON0_DCLK_REG,
>  				  GENMASK(6, 0), div);
> diff –git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> index 523a6d787921..7f5d3c135058 100644
> — a/drivers/gpu/drm/sun4i/sun4i_tcon.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> @@ -367,8 +367,9 @@ static void sun4i_tcon0_mode_set_cpu(struct sun4i_tcon *tcon,
>  	u32 block_space, start_delay;
>  	u32 tcon_div;
>
> -	tcon->dclk_min_div = SUN6I_DSI_TCON_DIV;
> -	tcon->dclk_max_div = SUN6I_DSI_TCON_DIV;
> +	tcon->is_dsi = true;
> +	tcon->dclk_min_div = bpp / lanes;
> +	tcon->dclk_max_div = bpp / lanes;

Claiming to set the divider to a different value (bpp / lanes) than what we’re actually using in the end (SUN6I_DSIO_TCON_DIV) is somehow bugging me. I feel like the proposal that I submitted is more direct:
<https://lore.kernel.org/all/20230319160704.9858-2-frank@oltmanns.dev/>

Actually, I had the following third patch prepared that adjusted the dotclock rate so that the required PLL rate is set. But again, this seems very indirect, so that’s why I refrained from submitting it and I submitted the linked patch above instead.

Anyway, here is the third proposal:

— a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
+++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
@@ -819,6 +819,34 @@ static void sun6i_dsi_encoder_disable(struct drm_encoder *encoder)
 	regulator_disable(dsi->regulator);
 }

+static bool sun6i_dsi_encoder_mode_fixup(
⁃ struct drm_encoder *encoder,
⁃ const struct drm_display_mode *mode,
⁃ struct drm_display_mode *adjusted_mode)
+{
⁃ if (encoder->encoder_type == DRM_MODE_ENCODER_DSI) {
⁃ /*
⁃ * For DSI the PLL rate has to respect the bits per pixel and
⁃ * number of lanes.
⁃ *
⁃ * According to the BSP code:
⁃ * PLL rate = DOTCLOCK * bpp / lanes
⁃ *
⁃ * Therefore, the clock has to be adjusted in order to set the
⁃ * correct PLL rate when actually setting the clock.
⁃ */
⁃ struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
⁃ struct mipi_dsi_device *device = dsi->device;
⁃ u8 bpp = mipi_dsi_pixel_format_to_bpp(device->format);
⁃ u8 lanes = device->lanes;
⁃ 

⁃ adjusted_mode->crtc_clock = mode->crtc_clock
⁃ * bpp / (lanes * SUN6I_DSI_TCON_DIV);
⁃ }
⁃ 

⁃ return true;
+}
⁃ static int sun6i_dsi_get_modes(struct drm_connector *connector)
  {
      struct sun6i_dsi *dsi = connector_to_sun6i_dsi(connector);
@@ -851,6 +879,7 @@ static const struct drm_connector_funcs sun6i_dsi_connector_funcs = {
 static const struct drm_encoder_helper_funcs sun6i_dsi_enc_helper_funcs = {
 	.disable	= sun6i_dsi_encoder_disable,
 	.enable		= sun6i_dsi_encoder_enable,
⁃ .mode_fixup = sun6i_dsi_encoder_mode_fixup,
  };

  static u32 sun6i_dsi_dcs_build_pkt_hdr(struct sun6i_dsi *dsi,



Maxime, Roman, CC, what do you think? Can we achieve consensus? If I’m not mistaken, all of the three proposal are a step in the right direction, because they correct faulty behavior. Don’t you think?

Thanks,
  Frank

>
>  	sun4i_tcon0_mode_set_common(tcon, mode);
>
> diff –git a/drivers/gpu/drm/sun4i/sun4i_tcon.h b/drivers/gpu/drm/sun4i/sun4i_tcon.h
> index fa23aa23fe4a..d8150ba2f319 100644
> — a/drivers/gpu/drm/sun4i/sun4i_tcon.h
> +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.h
> @@ -271,6 +271,7 @@ struct sun4i_tcon {
>  	struct clk			*dclk;
>  	u8				dclk_max_div;
>  	u8				dclk_min_div;
> +	bool				is_dsi;
>
>  	/* Reset control */
>  	struct reset_control  *lcd_rst;
Maxime Ripard March 27, 2023, 8:20 p.m. UTC | #5
Hi,

On Sat, Mar 25, 2023 at 12:40:04PM +0100, Frank Oltmanns wrote:
> On 2023-03-20 at 17:16:36 +0100, Roman Beranek <romanberanek@icloud.com> wrote:
> > In the case of DSI output, the value of SUN4I_TCON0_DCLK_DIV (4) does
> > not represent the actual dotclock divider, PLL_MIPI instead runs at
> > (bpp / lanes )-multiple [1] of the dotclock. [2] Setting 4 as dotclock
> > divder thus leads to reduced frame rate, specifically by 1/3 on 4-lane
> > panels, and by 2/3 on 2-lane panels respectively.
> >
> > As sun4i_dotclock driver stores its calculated divider directly in
> > the register, conditional handling of the DSI output scenario is needed.
> > Instead of reading the divider from SUN4I_TCON0_DCLK_REG, retrieve
> > the value from tcon->dclk_min_div.
> >
> > [1] bits per pixel / number of DSI lanes
> > [2] <https://github.com/BPI-SINOVOIP/BPI-M64-bsp-4.4/blob/66bef0f2f30b367eb93b1cbad21ce85e0361f7ae/linux-sunxi/drivers/video/fbdev/sunxi/disp2/disp/de/lowlevel_sun50iw1/disp_al.c#L322>
> >
> > Signed-off-by: Roman Beranek <romanberanek@icloud.com>
> > —
> >  drivers/gpu/drm/sun4i/sun4i_dotclock.c | 6 +++++-
> >  drivers/gpu/drm/sun4i/sun4i_tcon.c     | 5 +++–
> >  drivers/gpu/drm/sun4i/sun4i_tcon.h     | 1 +
> >  3 files changed, 9 insertions(+), 3 deletions(-)
> >
> > diff –git a/drivers/gpu/drm/sun4i/sun4i_dotclock.c b/drivers/gpu/drm/sun4i/sun4i_dotclock.c
> > index 417ade3d2565..26fa99aff590 100644
> > — a/drivers/gpu/drm/sun4i/sun4i_dotclock.c
> > +++ b/drivers/gpu/drm/sun4i/sun4i_dotclock.c
> > @@ -11,6 +11,7 @@
> >
> >  #include “sun4i_tcon.h”
> >  #include “sun4i_dotclock.h”
> > +#include “sun6i_mipi_dsi.h”
> >
> >  struct sun4i_dclk {
> >  	struct clk_hw  hw;
> > @@ -56,6 +57,9 @@ static unsigned long sun4i_dclk_recalc_rate(struct clk_hw *hw,
> >  	struct sun4i_dclk *dclk = hw_to_dclk(hw);
> >  	u32 val;
> >
> > +	if (dclk->tcon->is_dsi)
> > +		return parent_rate / dclk->tcon->dclk_min_div;
> > +
> >  	regmap_read(dclk->regmap, SUN4I_TCON0_DCLK_REG, &val);
> >
> >  	val >>= SUN4I_TCON0_DCLK_DIV_SHIFT;
> > @@ -116,7 +120,7 @@ static int sun4i_dclk_set_rate(struct clk_hw *hw, unsigned long rate,
> >  			       unsigned long parent_rate)
> >  {
> >  	struct sun4i_dclk *dclk = hw_to_dclk(hw);
> > -	u8 div = parent_rate / rate;
> > +	u8 div = dclk->tcon->is_dsi ? SUN6I_DSI_TCON_DIV : parent_rate / rate;
> >
> >  	return regmap_update_bits(dclk->regmap, SUN4I_TCON0_DCLK_REG,
> >  				  GENMASK(6, 0), div);
> > diff –git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> > index 523a6d787921..7f5d3c135058 100644
> > — a/drivers/gpu/drm/sun4i/sun4i_tcon.c
> > +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> > @@ -367,8 +367,9 @@ static void sun4i_tcon0_mode_set_cpu(struct sun4i_tcon *tcon,
> >  	u32 block_space, start_delay;
> >  	u32 tcon_div;
> >
> > -	tcon->dclk_min_div = SUN6I_DSI_TCON_DIV;
> > -	tcon->dclk_max_div = SUN6I_DSI_TCON_DIV;
> > +	tcon->is_dsi = true;
> > +	tcon->dclk_min_div = bpp / lanes;
> > +	tcon->dclk_max_div = bpp / lanes;
> 
> Claiming to set the divider to a different value (bpp / lanes) than what we’re actually using in
> the end (SUN6I_DSIO_TCON_DIV) is somehow bugging me. I feel like the proposal that I submitted is
> more direct: <https://lore.kernel.org/all/20230319160704.9858-2-frank@oltmanns.dev/>

Yeah, this patch looks better to me too: it's simpler, more straightforward. If Roman can confirm it
works with his testing, I'll be happy to merge it.

> Actually, I had the following third patch prepared that adjusted the dotclock rate so that the
> required PLL rate is set. But again, this seems very indirect, so that’s why I refrained from
> submitting it and I submitted the linked patch above instead.
> 
> Anyway, here is the third proposal:
> 
> — a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> +++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> @@ -819,6 +819,34 @@ static void sun6i_dsi_encoder_disable(struct drm_encoder *encoder)
>  	regulator_disable(dsi->regulator);
>  }
> 
> +static bool sun6i_dsi_encoder_mode_fixup(
> ⁃ struct drm_encoder *encoder,
> ⁃ const struct drm_display_mode *mode,
> ⁃ struct drm_display_mode *adjusted_mode)
> +{
> ⁃ if (encoder->encoder_type == DRM_MODE_ENCODER_DSI) {
> ⁃ /*
> ⁃ * For DSI the PLL rate has to respect the bits per pixel and
> ⁃ * number of lanes.
> ⁃ *
> ⁃ * According to the BSP code:
> ⁃ * PLL rate = DOTCLOCK * bpp / lanes
> ⁃ *
> ⁃ * Therefore, the clock has to be adjusted in order to set the
> ⁃ * correct PLL rate when actually setting the clock.
> ⁃ */
> ⁃ struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
> ⁃ struct mipi_dsi_device *device = dsi->device;
> ⁃ u8 bpp = mipi_dsi_pixel_format_to_bpp(device->format);
> ⁃ u8 lanes = device->lanes;
> ⁃ 
> 
> ⁃ adjusted_mode->crtc_clock = mode->crtc_clock
> ⁃ * bpp / (lanes * SUN6I_DSI_TCON_DIV);
> ⁃ }
> ⁃ 
> 
> ⁃ return true;
> +}
> ⁃ static int sun6i_dsi_get_modes(struct drm_connector *connector)
>   {
>       struct sun6i_dsi *dsi = connector_to_sun6i_dsi(connector);
> @@ -851,6 +879,7 @@ static const struct drm_connector_funcs sun6i_dsi_connector_funcs = {
>  static const struct drm_encoder_helper_funcs sun6i_dsi_enc_helper_funcs = {
>  	.disable	= sun6i_dsi_encoder_disable,
>  	.enable		= sun6i_dsi_encoder_enable,
> ⁃ .mode_fixup = sun6i_dsi_encoder_mode_fixup,
>   };

It's not clear to me what this patch is supposed to be doing, there's no mode_fixup implementation
upstream?

Maxime
Maxime Ripard March 27, 2023, 8:21 p.m. UTC | #6
On Tue, Mar 21, 2023 at 09:53:11PM +0100, Roman Beranek wrote:
> On Tue Mar 21, 2023 at 5:50 PM CET, Roman Beranek wrote:
> 
> > > Also, how was it tested/confirmed?
> >
> > By counting Vblank interrupts (GIC 118).
> 
> Sorry, that was perhaps too abbreviated. To test this change, I set up
> an A64 board running kmscube on DSI-1 and verified that the rate of
> Vblank IRQs tracked with a video mode set on DSI-1, once with a 2-lane
> panel and once with a 4-lane panel.

Ok, as long as you confirmed it with multiple panel and multiple lanes
count, I'm ok with it :)

Maxime
Roman Beranek March 27, 2023, 11:48 p.m. UTC | #7
On Mon Mar 27, 2023 at 10:20 PM CEST, Maxime Ripard wrote:
>
> On Sat, Mar 25, 2023 at 12:40:04PM +0100, Frank Oltmanns wrote:
> > Claiming to set the divider to a different value (bpp / lanes) than what we’re actually using in
> > the end (SUN6I_DSIO_TCON_DIV) is somehow bugging me. I feel like the proposal that I submitted is
> > more direct: <https://lore.kernel.org/all/20230319160704.9858-2-frank@oltmanns.dev/>
>
> Yeah, this patch looks better to me too: it's simpler, more straightforward. If Roman can confirm it
> works with his testing, I'll be happy to merge it.
>

So I've just found out that my understanding of what sun4i_dotclock is
was wrong the whole time. I treated it as a virtual clock representing
the true CRTC pixel clock and only coincidentally also matching what
A64 Reference Manual labels as TCON0 data clock (a coincidence to which
DSI is an exception).

Now that I finally see dotclock as 'what could dclk be an abbreviation
to', I to agree that it's not only straightforward but also correct to
keep the divider at 4 and adjust the rate as is done it the patch Frank
submitted.

In order to preserve semantic correctness however, I propose to preface
the change with a patch that renames sun4i_dotclock and tcon-pixel-clock
such that dot/pixel is replaced with d/data. What do you think?

Roman
Frank Oltmanns March 28, 2023, 7:28 p.m. UTC | #8
Hi,

On 2023-03-27 at 22:20:45 +0200, Maxime Ripard <maxime@cerno.tech> wrote:
> Hi,
>
> On Sat, Mar 25, 2023 at 12:40:04PM +0100, Frank Oltmanns wrote:
[...]
>> Actually, I had the following third patch prepared that adjusted the dotclock rate so that the
>> required PLL rate is set. But again, this seems very indirect, so that’s why I refrained from
>> submitting it and I submitted the linked patch above instead.
>>
>> Anyway, here is the third proposal:
>>
>> — a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
>> +++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
>> @@ -819,6 +819,34 @@ static void sun6i_dsi_encoder_disable(struct drm_encoder *encoder)
>>  	regulator_disable(dsi->regulator);
>>  }
>>
>> +static bool sun6i_dsi_encoder_mode_fixup(
>> ⁃ struct drm_encoder *encoder,
>> ⁃ const struct drm_display_mode *mode,
>> ⁃ struct drm_display_mode *adjusted_mode)
>> +{
>> ⁃ if (encoder->encoder_type == DRM_MODE_ENCODER_DSI) {
>> ⁃ /*
>> ⁃ * For DSI the PLL rate has to respect the bits per pixel and
>> ⁃ * number of lanes.
>> ⁃ *
>> ⁃ * According to the BSP code:
>> ⁃ * PLL rate = DOTCLOCK * bpp / lanes
>> ⁃ *
>> ⁃ * Therefore, the clock has to be adjusted in order to set the
>> ⁃ * correct PLL rate when actually setting the clock.
>> ⁃ */
>> ⁃ struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
>> ⁃ struct mipi_dsi_device *device = dsi->device;
>> ⁃ u8 bpp = mipi_dsi_pixel_format_to_bpp(device->format);
>> ⁃ u8 lanes = device->lanes;
>> ⁃
>>
>> ⁃ adjusted_mode->crtc_clock = mode->crtc_clock
>> ⁃ * bpp / (lanes * SUN6I_DSI_TCON_DIV);
>> ⁃ }
>> ⁃
>>
>> ⁃ return true;
>> +}
>> ⁃ static int sun6i_dsi_get_modes(struct drm_connector *connector)
>>   {
>>       struct sun6i_dsi *dsi = connector_to_sun6i_dsi(connector);
>> @@ -851,6 +879,7 @@ static const struct drm_connector_funcs sun6i_dsi_connector_funcs = {
>>  static const struct drm_encoder_helper_funcs sun6i_dsi_enc_helper_funcs = {
>>  	.disable	= sun6i_dsi_encoder_disable,
>>  	.enable		= sun6i_dsi_encoder_enable,
>> ⁃ .mode_fixup = sun6i_dsi_encoder_mode_fixup,
>>   };
>
> It's not clear to me what this patch is supposed to be doing, there's no mode_fixup implementation
> upstream?
>

Sorry, my mail client tried some fancy formatting. :(

This is the patch again.

--- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
+++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
@@ -819,6 +819,34 @@ static void sun6i_dsi_encoder_disable(struct drm_encoder *encoder)
 	regulator_disable(dsi->regulator);
 }

+static bool sun6i_dsi_encoder_mode_fixup(
+				   struct drm_encoder *encoder,
+				   const struct drm_display_mode *mode,
+				   struct drm_display_mode *adjusted_mode)
+{
+	if (encoder->encoder_type == DRM_MODE_ENCODER_DSI) {
+		/*
+		 * For DSI the PLL rate has to respect the bits per pixel and
+		 * number of lanes.
+		 *
+		 * According to the BSP code:
+		 * PLL rate = DOTCLOCK * bpp / lanes
+		 *
+		 * Therefore, the clock has to be adjusted in order to set the
+		 * correct PLL rate when actually setting the clock.
+		 */
+		struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
+		struct mipi_dsi_device *device = dsi->device;
+		u8 bpp = mipi_dsi_pixel_format_to_bpp(device->format);
+		u8 lanes = device->lanes;
+
+		adjusted_mode->crtc_clock = mode->crtc_clock
+				 * bpp / (lanes * SUN6I_DSI_TCON_DIV);
+	}
+
+	return true;
+}
+
 static int sun6i_dsi_get_modes(struct drm_connector *connector)
 {
 	struct sun6i_dsi *dsi = connector_to_sun6i_dsi(connector);
@@ -851,6 +879,7 @@ static const struct drm_connector_funcs sun6i_dsi_connector_funcs = {
 static const struct drm_encoder_helper_funcs sun6i_dsi_enc_helper_funcs = {
 	.disable	= sun6i_dsi_encoder_disable,
 	.enable		= sun6i_dsi_encoder_enable,
+	.mode_fixup	= sun6i_dsi_encoder_mode_fixup,
 };

 static u32 sun6i_dsi_dcs_build_pkt_hdr(struct sun6i_dsi *dsi,


I still like the original patch better, but I'd be happy to submit this
as a proper patch, if this is more to your liking.

Thanks,
  Frank


> Maxime
>
--
Maxime Ripard March 29, 2023, 7:56 p.m. UTC | #9
Hi,

On Tue, Mar 28, 2023 at 09:28:19PM +0200, Frank Oltmanns wrote:
> --- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> +++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
> @@ -819,6 +819,34 @@ static void sun6i_dsi_encoder_disable(struct drm_encoder *encoder)
>  	regulator_disable(dsi->regulator);
>  }
> 
> +static bool sun6i_dsi_encoder_mode_fixup(
> +				   struct drm_encoder *encoder,
> +				   const struct drm_display_mode *mode,
> +				   struct drm_display_mode *adjusted_mode)

So, mode_fixup is kind of deprecated in favour of atomic_check

> +{
> +	if (encoder->encoder_type == DRM_MODE_ENCODER_DSI) {
> +		/*
> +		 * For DSI the PLL rate has to respect the bits per pixel and
> +		 * number of lanes.
> +		 *
> +		 * According to the BSP code:
> +		 * PLL rate = DOTCLOCK * bpp / lanes
> +		 *
> +		 * Therefore, the clock has to be adjusted in order to set the
> +		 * correct PLL rate when actually setting the clock.
> +		 */
> +		struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
> +		struct mipi_dsi_device *device = dsi->device;
> +		u8 bpp = mipi_dsi_pixel_format_to_bpp(device->format);
> +		u8 lanes = device->lanes;
> +
> +		adjusted_mode->crtc_clock = mode->crtc_clock
> +				 * bpp / (lanes * SUN6I_DSI_TCON_DIV);

And that's visible to the userspace, so it's not where we should store
that value. I guess the best way to do something similar would be to
store it into crtc_state, and then reuse it there. But it starts to make
a lot of rather complicated code compared to your previous patch.

Maxime
Maxime Ripard March 29, 2023, 7:58 p.m. UTC | #10
On Tue, Mar 28, 2023 at 01:48:33AM +0200, Roman Beranek wrote:
> On Mon Mar 27, 2023 at 10:20 PM CEST, Maxime Ripard wrote:
> >
> > On Sat, Mar 25, 2023 at 12:40:04PM +0100, Frank Oltmanns wrote:
> > > Claiming to set the divider to a different value (bpp / lanes) than what we’re actually using in
> > > the end (SUN6I_DSIO_TCON_DIV) is somehow bugging me. I feel like the proposal that I submitted is
> > > more direct: <https://lore.kernel.org/all/20230319160704.9858-2-frank@oltmanns.dev/>
> >
> > Yeah, this patch looks better to me too: it's simpler, more straightforward. If Roman can confirm it
> > works with his testing, I'll be happy to merge it.
> >
> 
> So I've just found out that my understanding of what sun4i_dotclock is
> was wrong the whole time. I treated it as a virtual clock representing
> the true CRTC pixel clock and only coincidentally also matching what
> A64 Reference Manual labels as TCON0 data clock (a coincidence to which
> DSI is an exception).
> 
> Now that I finally see dotclock as 'what could dclk be an abbreviation
> to', I to agree that it's not only straightforward but also correct to
> keep the divider at 4 and adjust the rate as is done it the patch Frank
> submitted.
> 
> In order to preserve semantic correctness however, I propose to preface
> the change with a patch that renames sun4i_dotclock and tcon-pixel-clock
> such that dot/pixel is replaced with d/data. What do you think?

I don't think it's exposed to the userspace in any way so it makes sense to me

Maxime
Frank Oltmanns March 30, 2023, 4:41 a.m. UTC | #11
Hi,

On 2023-03-29 at 21:56:39 +0200, Maxime Ripard <maxime@cerno.tech> wrote:
> Hi,
>
> On Tue, Mar 28, 2023 at 09:28:19PM +0200, Frank Oltmanns wrote:
>> --- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
>> +++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
>> @@ -819,6 +819,34 @@ static void sun6i_dsi_encoder_disable(struct drm_encoder *encoder)
>>  	regulator_disable(dsi->regulator);
>>  }
>>
>> +static bool sun6i_dsi_encoder_mode_fixup(
>> +				   struct drm_encoder *encoder,
>> +				   const struct drm_display_mode *mode,
>> +				   struct drm_display_mode *adjusted_mode)
>
> So, mode_fixup is kind of deprecated in favour of atomic_check

I see. Thanks for pointing that out.

>> +{
>> +	if (encoder->encoder_type == DRM_MODE_ENCODER_DSI) {
>> +		/*
>> +		 * For DSI the PLL rate has to respect the bits per pixel and
>> +		 * number of lanes.
>> +		 *
>> +		 * According to the BSP code:
>> +		 * PLL rate = DOTCLOCK * bpp / lanes
>> +		 *
>> +		 * Therefore, the clock has to be adjusted in order to set the
>> +		 * correct PLL rate when actually setting the clock.
>> +		 */
>> +		struct sun6i_dsi *dsi = encoder_to_sun6i_dsi(encoder);
>> +		struct mipi_dsi_device *device = dsi->device;
>> +		u8 bpp = mipi_dsi_pixel_format_to_bpp(device->format);
>> +		u8 lanes = device->lanes;
>> +
>> +		adjusted_mode->crtc_clock = mode->crtc_clock
>> +				 * bpp / (lanes * SUN6I_DSI_TCON_DIV);
>
> And that's visible to the userspace, so it's not where we should store
> that value. I guess the best way to do something similar would be to
> store it into crtc_state, and then reuse it there. But it starts to make
> a lot of rather complicated code compared to your previous patch.

Ah, interesting. But I agree, let's stick to the simpler aproach.

Thanks,
  Frank

>
> Maxime
>
> [[End of PGP Signed Part]]

--
Frank Oltmanns March 30, 2023, 4:45 a.m. UTC | #12
Hi Roman,

On 2023-03-29 at 21:58:02 +0200, Maxime Ripard <maxime@cerno.tech> wrote:
> On Tue, Mar 28, 2023 at 01:48:33AM +0200, Roman Beranek wrote:
>> On Mon Mar 27, 2023 at 10:20 PM CEST, Maxime Ripard wrote:
>> >
>> > On Sat, Mar 25, 2023 at 12:40:04PM +0100, Frank Oltmanns wrote:
>> > > Claiming to set the divider to a different value (bpp / lanes) than what we’re actually using in
>> > > the end (SUN6I_DSIO_TCON_DIV) is somehow bugging me. I feel like the proposal that I submitted is
>> > > more direct: <https://lore.kernel.org/all/20230319160704.9858-2-frank@oltmanns.dev/>
>> >
>> > Yeah, this patch looks better to me too: it's simpler, more straightforward. If Roman can confirm it
>> > works with his testing, I'll be happy to merge it.
>> >
>>
>> So I've just found out that my understanding of what sun4i_dotclock is
>> was wrong the whole time. I treated it as a virtual clock representing
>> the true CRTC pixel clock and only coincidentally also matching what
>> A64 Reference Manual labels as TCON0 data clock (a coincidence to which
>> DSI is an exception).
>>
>> Now that I finally see dotclock as 'what could dclk be an abbreviation
>> to', I to agree that it's not only straightforward but also correct to
>> keep the divider at 4 and adjust the rate as is done it the patch Frank
>> submitted.
>>
>> In order to preserve semantic correctness however, I propose to preface
>> the change with a patch that renames sun4i_dotclock and tcon-pixel-clock
>> such that dot/pixel is replaced with d/data. What do you think?
>
> I don't think it's exposed to the userspace in any way so it makes sense to me

Roman, will you please submit a V2 of the patch I submitted then? Or do
you want me to do it?

Thanks,
  Frank

>
> Maxime
>


--
Roman Beranek March 31, 2023, 5:36 a.m. UTC | #13
Hello Frank,

On Thu Mar 30, 2023 at 6:45 AM CEST, Frank Oltmanns wrote:
> Roman, will you please submit a V2 of the patch I submitted then? Or do
> you want me to do it?

Yes, I'm already on it, only missing a cover letter.

Roman
Roman Beranek April 5, 2023, 12:34 p.m. UTC | #14
Hello Maxime,

On Wed Mar 29, 2023 at 9:58 PM CEST, Maxime Ripard wrote:
> > In order to preserve semantic correctness however, I propose to preface
> > the change with a patch that renames sun4i_dotclock and tcon-pixel-clock
> > such that dot/pixel is replaced with d/data. What do you think?
>
> I don't think it's exposed to the userspace in any way so it makes sense to me
>

Here's a new series that includes those renames:
<https://lore.kernel.org/all/20230331110245.43527-1-me@crly.cz/>

It turns out however that the new dclk rates can't be set exactly as
requested without touching pll-video0*, tcon0 now therefore gets
reparented from pll-mipi to pll-video0-2x which, as it further turns
out, breaks DSI. While simply forbidding the video0-2x mux option seems
to me as the right way to go because there's not much use for it with
non-DSI interfaces either besides the opportunity to power pll-mipi
down, I'd like to run by you first.

Kind regards,
Roman

* As pll-mipi doesn't have CLK_SET_RATE_PARENT flag set, pll-video0
  retains its boot-time rate of 294 MHz set by sunxi-dw-hdmi driver
  in u-boot. Why 294 MHz (as opposed to the default rate of 297 MHz)?
  The driver actually asks for 297 MHz, clock_set_pll3 rounds it to
  294 MHz though because it limits itself to 6 MHz steps.
Maxime Ripard April 5, 2023, 3:03 p.m. UTC | #15
On Wed, Apr 05, 2023 at 02:34:11PM +0200, Roman Beranek wrote:
> Hello Maxime,
> 
> On Wed Mar 29, 2023 at 9:58 PM CEST, Maxime Ripard wrote:
> > > In order to preserve semantic correctness however, I propose to preface
> > > the change with a patch that renames sun4i_dotclock and tcon-pixel-clock
> > > such that dot/pixel is replaced with d/data. What do you think?
> >
> > I don't think it's exposed to the userspace in any way so it makes sense to me
> >
> 
> Here's a new series that includes those renames:
> <https://lore.kernel.org/all/20230331110245.43527-1-me@crly.cz/>
> 
> It turns out however that the new dclk rates can't be set exactly as
> requested without touching pll-video0*, tcon0 now therefore gets
> reparented from pll-mipi to pll-video0-2x which, as it further turns
> out, breaks DSI. While simply forbidding the video0-2x mux option seems
> to me as the right way to go because there's not much use for it with
> non-DSI interfaces either besides the opportunity to power pll-mipi
> down, I'd like to run by you first.

Sounds reasonable

> * As pll-mipi doesn't have CLK_SET_RATE_PARENT flag set, pll-video0
>   retains its boot-time rate of 294 MHz set by sunxi-dw-hdmi driver
>   in u-boot. Why 294 MHz (as opposed to the default rate of 297 MHz)?
>   The driver actually asks for 297 MHz, clock_set_pll3 rounds it to
>   294 MHz though because it limits itself to 6 MHz steps.

We could also address that though

Maxime
Jernej Škrabec April 8, 2023, 7:07 a.m. UTC | #16
Dne sreda, 05. april 2023 ob 14:34:11 CEST je Roman Beranek napisal(a):
> Hello Maxime,
> 
> On Wed Mar 29, 2023 at 9:58 PM CEST, Maxime Ripard wrote:
> > > In order to preserve semantic correctness however, I propose to preface
> > > the change with a patch that renames sun4i_dotclock and tcon-pixel-clock
> > > such that dot/pixel is replaced with d/data. What do you think?
> > 
> > I don't think it's exposed to the userspace in any way so it makes sense
> > to me
> Here's a new series that includes those renames:
> <https://lore.kernel.org/all/20230331110245.43527-1-me@crly.cz/>
> 
> It turns out however that the new dclk rates can't be set exactly as
> requested without touching pll-video0*, tcon0 now therefore gets
> reparented from pll-mipi to pll-video0-2x which, as it further turns
> out, breaks DSI. While simply forbidding the video0-2x mux option seems
> to me as the right way to go because there's not much use for it with
> non-DSI interfaces either besides the opportunity to power pll-mipi
> down, I'd like to run by you first.

It's been a long time since I looked at A64 HDMI clocks, but IIRC, pll-video0 
is the only useful source for HDMI PHY (as opposed to HDMI controller.)
So question remains how to properly support both displays at the same time.

Have you ever tried to make HDMI and DSI work at the same time? This is one of 
issues of the PinePhone IIUC.


> 
> Kind regards,
> Roman
> 
> * As pll-mipi doesn't have CLK_SET_RATE_PARENT flag set, pll-video0
>   retains its boot-time rate of 294 MHz set by sunxi-dw-hdmi driver
>   in u-boot. Why 294 MHz (as opposed to the default rate of 297 MHz)?
>   The driver actually asks for 297 MHz, clock_set_pll3 rounds it to
>   294 MHz though because it limits itself to 6 MHz steps.

Yeah, we added CLK_SET_RATE_PARENT flag to several clocks after initial driver 
was merged. Adding this flag sounds completely reasonable.

Best regards,
Jernej
Roman Beranek April 12, 2023, 1:22 a.m. UTC | #17
On Sat Apr 8, 2023 at 9:07 AM CEST, Jernej Škrabec wrote:
> Dne sreda, 05. april 2023 ob 14:34:11 CEST je Roman Beranek napisal(a):
> > While simply forbidding the video0-2x mux option seems
> > to me as the right way to go because there's not much use for it with
> > non-DSI interfaces either besides the opportunity to power pll-mipi
> > down, I'd like to run by you first.
>
> It's been a long time since I looked at A64 HDMI clocks, but IIRC, pll-video0 
> is the only useful source for HDMI PHY (as opposed to HDMI controller.)
> So question remains how to properly support both displays at the same time.
>

Correct.

> Have you ever tried to make HDMI and DSI work at the same time? This is one of 
> issues of the PinePhone IIUC.
>

Yes, I have. Prusa3D's SL1 printer, on which I previously worked on,
uses both outputs simultaneously. I had encountered the same reparenting
problem back then but since I hadn't been able to identify it,
I resorted to fiddling with the DSI pixelclock until it worked. 

DSI & HDMI co-existence is yet another reasoni though for forbidding
the pll-video-2x parent. megi's kernel includes Mr. Zheng's commit which
does the same.

<https://github.com/megous/linux/commit/7374d57>

Best wishes
Roman Beranek
Roman Beranek April 12, 2023, 7:14 a.m. UTC | #18
On Wed Apr 5, 2023 at 5:03 PM CEST, Maxime Ripard wrote:
> On Wed, Apr 05, 2023 at 02:34:11PM +0200, Roman Beranek wrote:
> > It turns out however that the new dclk rates can't be set exactly as
> > requested without touching pll-video0*, tcon0 now therefore gets
> > reparented from pll-mipi to pll-video0-2x which, as it further turns
> > out, breaks DSI. While simply forbidding the video0-2x mux option seems
> > to me as the right way to go because there's not much use for it with
> > non-DSI interfaces either besides the opportunity to power pll-mipi
> > down, I'd like to run by you first.
>
> Sounds reasonable

Okay, I'm unsure of how to denote that in the code however. Should I
just comment the parent out of the table and put an explanation in
a comment nearby? Or just erase it? I couldn't find an applicable
precedent.

> > * As pll-mipi doesn't have CLK_SET_RATE_PARENT flag set, pll-video0
> >   retains its boot-time rate of 294 MHz set by sunxi-dw-hdmi driver
> >   in u-boot. Why 294 MHz (as opposed to the default rate of 297 MHz)?
> >   The driver actually asks for 297 MHz, clock_set_pll3 rounds it to
> >   294 MHz though because it limits itself to 6 MHz steps.
>
> We could also address that though

Should I include it in v2 of the series, or leave it for later?

Thanks,
Roman
Maxime Ripard April 12, 2023, 2:09 p.m. UTC | #19
On Wed, Apr 12, 2023 at 09:14:59AM +0200, Roman Beranek wrote:
> On Wed Apr 5, 2023 at 5:03 PM CEST, Maxime Ripard wrote:
> > On Wed, Apr 05, 2023 at 02:34:11PM +0200, Roman Beranek wrote:
> > > It turns out however that the new dclk rates can't be set exactly as
> > > requested without touching pll-video0*, tcon0 now therefore gets
> > > reparented from pll-mipi to pll-video0-2x which, as it further turns
> > > out, breaks DSI. While simply forbidding the video0-2x mux option seems
> > > to me as the right way to go because there's not much use for it with
> > > non-DSI interfaces either besides the opportunity to power pll-mipi
> > > down, I'd like to run by you first.
> >
> > Sounds reasonable
> 
> Okay, I'm unsure of how to denote that in the code however. Should I
> just comment the parent out of the table and put an explanation in
> a comment nearby? Or just erase it? I couldn't find an applicable
> precedent.

I think that forcing the parent at boot, and adding the
CLK_SET_RATE_NOREPARENT flag should be enough.

> > > * As pll-mipi doesn't have CLK_SET_RATE_PARENT flag set, pll-video0
> > >   retains its boot-time rate of 294 MHz set by sunxi-dw-hdmi driver
> > >   in u-boot. Why 294 MHz (as opposed to the default rate of 297 MHz)?
> > >   The driver actually asks for 297 MHz, clock_set_pll3 rounds it to
> > >   294 MHz though because it limits itself to 6 MHz steps.
> >
> > We could also address that though
> 
> Should I include it in v2 of the series, or leave it for later?

I guess you can include it into this one too

Maxime
diff mbox series

Patch

diff --git a/drivers/gpu/drm/sun4i/sun4i_dotclock.c b/drivers/gpu/drm/sun4i/sun4i_dotclock.c
index 417ade3d2565..26fa99aff590 100644
--- a/drivers/gpu/drm/sun4i/sun4i_dotclock.c
+++ b/drivers/gpu/drm/sun4i/sun4i_dotclock.c
@@ -11,6 +11,7 @@ 
 
 #include "sun4i_tcon.h"
 #include "sun4i_dotclock.h"
+#include "sun6i_mipi_dsi.h"
 
 struct sun4i_dclk {
 	struct clk_hw		hw;
@@ -56,6 +57,9 @@  static unsigned long sun4i_dclk_recalc_rate(struct clk_hw *hw,
 	struct sun4i_dclk *dclk = hw_to_dclk(hw);
 	u32 val;
 
+	if (dclk->tcon->is_dsi)
+		return parent_rate / dclk->tcon->dclk_min_div;
+
 	regmap_read(dclk->regmap, SUN4I_TCON0_DCLK_REG, &val);
 
 	val >>= SUN4I_TCON0_DCLK_DIV_SHIFT;
@@ -116,7 +120,7 @@  static int sun4i_dclk_set_rate(struct clk_hw *hw, unsigned long rate,
 			       unsigned long parent_rate)
 {
 	struct sun4i_dclk *dclk = hw_to_dclk(hw);
-	u8 div = parent_rate / rate;
+	u8 div = dclk->tcon->is_dsi ? SUN6I_DSI_TCON_DIV : parent_rate / rate;
 
 	return regmap_update_bits(dclk->regmap, SUN4I_TCON0_DCLK_REG,
 				  GENMASK(6, 0), div);
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
index 523a6d787921..7f5d3c135058 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
@@ -367,8 +367,9 @@  static void sun4i_tcon0_mode_set_cpu(struct sun4i_tcon *tcon,
 	u32 block_space, start_delay;
 	u32 tcon_div;
 
-	tcon->dclk_min_div = SUN6I_DSI_TCON_DIV;
-	tcon->dclk_max_div = SUN6I_DSI_TCON_DIV;
+	tcon->is_dsi = true;
+	tcon->dclk_min_div = bpp / lanes;
+	tcon->dclk_max_div = bpp / lanes;
 
 	sun4i_tcon0_mode_set_common(tcon, mode);
 
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.h b/drivers/gpu/drm/sun4i/sun4i_tcon.h
index fa23aa23fe4a..d8150ba2f319 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.h
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.h
@@ -271,6 +271,7 @@  struct sun4i_tcon {
 	struct clk			*dclk;
 	u8				dclk_max_div;
 	u8				dclk_min_div;
+	bool				is_dsi;
 
 	/* Reset control */
 	struct reset_control		*lcd_rst;