[PATCH V6 2/8] drm/panel: Add support for prepare and unprepare routines

Ajay kumar ajaynumb at gmail.com
Wed Jul 30 04:09:44 PDT 2014


On Wed, Jul 30, 2014 at 4:02 PM, Thierry Reding
<thierry.reding at gmail.com> wrote:
> On Sat, Jul 26, 2014 at 12:52:04AM +0530, Ajay Kumar wrote:
>> Now that we have 2 new callbacks(prepare and unprepare) for drm_panel,
>> make changes in all the drm drivers which use the drm_panel framework
>> to support the new callbacks.
>>
>> Signed-off-by: Ajay Kumar <ajaykumar.rs at samsung.com>
>> ---
>>  drivers/gpu/drm/exynos/exynos_drm_dpi.c |    8 +++--
>>  drivers/gpu/drm/exynos/exynos_drm_dsi.c |    7 +++++
>>  drivers/gpu/drm/panel/panel-ld9040.c    |   18 +++++++++--
>>  drivers/gpu/drm/panel/panel-s6e8aa0.c   |   18 +++++++++--
>>  drivers/gpu/drm/panel/panel-simple.c    |   51 ++++++++++++++++++++++++-------
>>  drivers/gpu/drm/tegra/output.c          |    2 ++
>>  6 files changed, 85 insertions(+), 19 deletions(-)
>
> I'd prefer for this to be split up into patches per panel and per
> display driver. The reason is that if this patch is merged as-is, then
> if it's ever determined to cause a regression it'll be difficult to find
> out which change exactly caused this.
>
> But to not break bisectability you'll need to be careful in how you
> break up the patches. I think the following should work:
>
>         - for each panel driver, implement dummy .prepare() and
>           .unprepare() that return 0
>         - for each display driver, make use of drm_panel_prepare() and
>           drm_panel_unprepare()
>         - for each panel driver, properly implement .prepare() and
>           .unprepare() (presumably by moving code out of .enable() and
>           .disable(), respectively)
>
I will try this. With this approach, compilation should not fail.

> I have a couple more comments below about the ordering of the .prepare()
> vs. .enable() and .disable() vs. .unprepare() calls.
>
>> diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
>> index 5e78d45..2f58e45 100644
>> --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
>> +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
>> @@ -1333,6 +1333,12 @@ static int exynos_dsi_enable(struct exynos_dsi *dsi)
>>       if (ret < 0)
>>               return ret;
>>
>> +     ret = drm_panel_prepare(dsi->panel);
>> +     if (ret < 0) {
>> +             exynos_dsi_poweroff(dsi);
>> +             return ret;
>> +     }
>> +
>>       ret = drm_panel_enable(dsi->panel);
>>       if (ret < 0) {
>>               exynos_dsi_poweroff(dsi);
>> @@ -1354,6 +1360,7 @@ static void exynos_dsi_disable(struct exynos_dsi *dsi)
>>
>>       exynos_dsi_set_display_enable(dsi, false);
>>       drm_panel_disable(dsi->panel);
>> +     drm_panel_unprepare(dsi->panel);
>>       exynos_dsi_poweroff(dsi);
>
> I don't know Exynos very well, so this may be completely wrong, but
> should disable_panel_prepare() be called much earlier than
> drm_panel_enable() and drm_panel_unprepare() much later than
> drm_panel_disable()? With the above the result is still the same, so
> you'll get the same glitches as without their separation.
Actually, I have not worked on DSI panels.
And till now, these DSI panels have been working with just the
enable/disable callback. So, I thought it might not really cause a
glitch/garbage on the screen.
I just placed the new panel calls so that basic working will not be broken.
It would be great if someone can test this on exynos boards with DSI panels :(
Inki/Andrej?

Anyways, now there is a kerneldoc which explains all these calls,
I will rearrange the panel calls.

> Without knowing exactly what Exynos does in the above, I'd expect the
> correct sequence to be something like this:
>
>         ret = exynos_dsi_power_on(dsi);
>         if (ret < 0)
>                 return ret;
>
>         ret = drm_panel_prepare(dsi->panel);
>         if (ret < 0) {
>                 exynos_dsi_poweroff(dsi);
>                 return ret;
>         }
>
>         exynos_dsi_set_display_mode(dsi);
>         exynos_dsi_set_display_enable(dsi, true);
>
>         ret = drm_panel_enable(dsi->panel);
>         if (ret < 0) {
>                 /* perhaps undo exynos_dsi_set_display_enable() here? */
>                 exynos_dsi_poweroff(dsi);
>                 return ret;
>         }
>
> And for disable:
>
>         drm_panel_disable(dsi->panel);
>         exynos_dsi_set_display_enable(dsi, false);
>         drm_panel_unprepare(dsi->panel);
>         exynos_dsi_poweroff(dsi);
>
> Perhaps I should quote the kerneldoc that I added for drm_panel_funcs to
> underline why I think this is important:
>
> /**
>  * struct drm_panel_funcs - perform operations on a given panel
>  * @disable: disable panel (turn off back light, etc.)
>  * @unprepare: turn off panel
>  * @prepare: turn on panel and perform set up
>  * @enable: enable panel (turn on back light, etc.)
>  * @get_modes: add modes to the connector that the panel is attached to and
>  * return the number of modes added
>  *
>  * The .prepare() function is typically called before the display controller
>  * starts to transmit video data. Panel drivers can use this to turn the panel
>  * on and wait for it to become ready. If additional configuration is required
>  * (via a control bus such as I2C, SPI or DSI for example) this is a good time
>  * to do that.
>  *
>  * After the display controller has started transmitting video data, it's safe
>  * to call the .enable() function. This will typically enable the backlight to
>  * make the image on screen visible. Some panels require a certain amount of
>  * time or frames before the image is displayed. This function is responsible
>  * for taking this into account before enabling the backlight to avoid visual
>  * glitches.
>  *
>  * Before stopping video transmission from the display controller it can be
>  * necessary to turn off the panel to avoid visual glitches. This is done in
>  * the .disable() function. Analogously to .enable() this typically involves
>  * turning off the backlight and waiting for some time to make sure no image
>  * is visible on the panel. It is then safe for the display controller to
>  * cease transmission of video data.
>  *
>  * To save power when no video data is transmitted, a driver can power down
>  * the panel. This is the job of the .unprepare() function.
>  */
>
> As you see, .prepare() should do whatever is necessary to make the panel
> accept a stream of video data, then the display driver can start sending
> video data and call .enable() to make the transmitted data visible.
>
> Analogously .disable() should turn off the display, so that the user can
> no longer see what's going on, then the display controller can cease
> transmission of video data (and since the panel is disabled this should
> no longer cause visual glitches) and then call .unprepare() to turn the
> panel off.
>
> I know that this isn't immediately relevant just yet because currently
> the backlight will already turn on by default, but like we discussed
> earlier I have ideas on how to properly fix it. As a matter of fact I'll
> go and send out another mail about that when I'm through this series.
>
>>  static const struct drm_panel_funcs ld9040_drm_funcs = {
>> +     .unprepare = ld9040_unprepare,
>>       .disable = ld9040_disable,
>> +     .prepare = ld9040_prepare,
>>       .enable = ld9040_enable,
>>       .get_modes = ld9040_get_modes,
>>  };
>
> The patch I applied for .prepare() and .unprepare() I've reordered the
> functions slightly to give a more natural sequence. .disable() is now
> first, while .unprepare() is next, since that's the sequence that they
> should be called in.
>
> Patches for the panel drivers should follow this same ordering.
Ok. I will follow the same order for all panel drivers.

>> diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
>> index a251361..fb0cfe2 100644
>> --- a/drivers/gpu/drm/panel/panel-simple.c
>> +++ b/drivers/gpu/drm/panel/panel-simple.c
>> @@ -45,7 +45,8 @@ struct panel_desc {
>>
>>  struct panel_simple {
>>       struct drm_panel base;
>> -     bool enabled;
>> +     bool panel_enabled;
>> +     bool backlight_enabled;
>
> Perhaps this should rather be:
>
>         bool prepared;
>         bool enabled;
>
More generic. Will change it!

Ajay

>
>> diff --git a/drivers/gpu/drm/tegra/output.c b/drivers/gpu/drm/tegra/output.c
>> index 446837e..b574ee6 100644
>> --- a/drivers/gpu/drm/tegra/output.c
>> +++ b/drivers/gpu/drm/tegra/output.c
>> @@ -139,9 +139,11 @@ static void tegra_encoder_dpms(struct drm_encoder *encoder, int mode)
>>
>>       if (mode != DRM_MODE_DPMS_ON) {
>>               drm_panel_disable(panel);
>> +             drm_panel_unprepare(panel);
>>               tegra_output_disable(output);
>
> Similarly to my comments for the Exynos drivers, this should be:
>
>                 drm_panel_disable(panel);
>                 tegra_output_disable(output);
>                 drm_panel_unprepare(panel);
>
>>       } else {
>>               tegra_output_enable(output);
>> +             drm_panel_prepare(panel);
>>               drm_panel_enable(panel);
>>       }
>
> and
>
>                 drm_panel_prepare(panel);
>                 tegra_output_enable(output);
>                 drm_panel_enable(panel);
>
> Thierry


More information about the dri-devel mailing list