On 08/12/2020 17:48, Laurent Pinchart wrote:
> Hi Tomi,
> 
> Thank you for the patch.
> 
> On Tue, Dec 08, 2020 at 02:28:55PM +0200, Tomi Valkeinen wrote:
>> Panel drivers can send DSI commands in panel's prepare(), which happens
>> before the bridge's enable() is called. The OMAP DSI driver currently
>> only sets up the DSI interface at bridge's enable(), so prepare() cannot
>> be used to send DSI commands.
>>
>> This patch fixes the issue by making it possible to enable the DSI
>> interface any time a command is about to be sent. Disabling the
>> interface is be done via delayed work.
>>
>> Signed-off-by: Tomi Valkeinen <tomi.valkei...@ti.com>
>> ---
>>  drivers/gpu/drm/omapdrm/dss/dsi.c | 49 +++++++++++++++++++++++++++----
>>  drivers/gpu/drm/omapdrm/dss/dsi.h |  3 ++
>>  2 files changed, 47 insertions(+), 5 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/omapdrm/dss/dsi.c 
>> b/drivers/gpu/drm/omapdrm/dss/dsi.c
>> index 53a64bc91867..34f665aa9a59 100644
>> --- a/drivers/gpu/drm/omapdrm/dss/dsi.c
>> +++ b/drivers/gpu/drm/omapdrm/dss/dsi.c
>> @@ -3503,6 +3503,9 @@ static void dsi_enable(struct dsi_data *dsi)
>>  
>>      WARN_ON(!dsi_bus_is_locked(dsi));
>>  
>> +    if (WARN_ON(dsi->iface_enabled))
>> +            return;
>> +
>>      mutex_lock(&dsi->lock);
>>  
>>      r = dsi_runtime_get(dsi);
>> @@ -3515,6 +3518,8 @@ static void dsi_enable(struct dsi_data *dsi)
>>      if (r)
>>              goto err_init_dsi;
>>  
>> +    dsi->iface_enabled = true;
>> +
>>      mutex_unlock(&dsi->lock);
>>  
>>      return;
>> @@ -3530,6 +3535,9 @@ static void dsi_disable(struct dsi_data *dsi)
>>  {
>>      WARN_ON(!dsi_bus_is_locked(dsi));
>>  
>> +    if (WARN_ON(!dsi->iface_enabled))
>> +            return;
>> +
>>      mutex_lock(&dsi->lock);
>>  
>>      dsi_sync_vc(dsi, 0);
>> @@ -3541,6 +3549,8 @@ static void dsi_disable(struct dsi_data *dsi)
>>  
>>      dsi_runtime_put(dsi);
>>  
>> +    dsi->iface_enabled = false;
>> +
>>      mutex_unlock(&dsi->lock);
>>  }
>>  
>> @@ -4229,10 +4239,12 @@ static ssize_t omap_dsi_host_transfer(struct 
>> mipi_dsi_host *host,
>>  
>>      dsi_bus_lock(dsi);
>>  
>> -    if (dsi->video_enabled)
>> -            r = _omap_dsi_host_transfer(dsi, vc, msg);
>> -    else
>> -            r = -EIO;
>> +    if (!dsi->iface_enabled) {
>> +            dsi_enable(dsi);
>> +            schedule_delayed_work(&dsi->dsi_disable_work, 
>> msecs_to_jiffies(2000));
>> +    }
>> +
>> +    r = _omap_dsi_host_transfer(dsi, vc, msg);
>>  
>>      dsi_bus_unlock(dsi);
>>  
>> @@ -4397,6 +4409,14 @@ static int omap_dsi_host_detach(struct mipi_dsi_host 
>> *host,
>>      if (WARN_ON(dsi->dsidev != client))
>>              return -EINVAL;
>>  
>> +    cancel_delayed_work_sync(&dsi->dsi_disable_work);
>> +
>> +    if (dsi->iface_enabled) {
>> +            dsi_bus_lock(dsi);
>> +            dsi_disable(dsi);
>> +            dsi_bus_unlock(dsi);
>> +    }
>> +
>>      omap_dsi_unregister_te_irq(dsi);
>>      dsi->dsidev = NULL;
>>      return 0;
>> @@ -4632,9 +4652,12 @@ static void dsi_bridge_enable(struct drm_bridge 
>> *bridge)
>>      struct dsi_data *dsi = drm_bridge_to_dsi(bridge);
>>      struct omap_dss_device *dssdev = &dsi->output;
>>  
>> +    cancel_delayed_work_sync(&dsi->dsi_disable_work);
>> +
> 
> Is there a risk of a race condition if omap_dsi_host_transfer() is
> called right here, before locking the bus ? Or is there a guarantee that
> the two functions can't be executed concurrently ? Same for
> dsi_bridge_disable() below.

Yes, there's a possibility for a race, if the panel driver does dsi command 
transactions via, say, a
timer, and doesn't take DRM locks that are shared with 
bridge-enable/disable/detach.

For bridge-enable, it shouldn't matter: If the disable callback is called just 
before bridge_enable
takes the dsi_bus_lock, no problem, bridge_enable just enables the interface 
again. If the callback
is ran just after bridge_enable's dsi_bus_unlock, no problem, 
dsi->video_enabled == true so the
callback does nothing.

Similarly for bridge-disable, the callback won't do anything if video_enabled 
== true, and after
bridge-disable has turned the video and the interface off, there's nothing to 
do for the callback.

The detach is a bit more unclear. Is the panel driver allowed to do "stuff" 
with bridges while
bridge detach is going on? If yes, it's probably broken. We should move the 
bus_locks to cover the
whole if() so that dsi->iface_enabled is inside the locks. With that change the 
delayed disable
itself should work fine.

But we don't have anything stopping omap_dsi_host_transfer being called after 
the whole bridge has
been detached (or called before attach). So, if we have a guarantee that the 
panels won't be doing
dsi transfers before/during bridge attach or after/during bridge detach, we 
have no issue. If we
don't have such a guarantee, it's broken.

I'll try to figure out if there's such a guarantee, but maybe it's safer to add 
a flag to indicate
if the bridge is available, and check that during omap_dsi_host_transfer.

 Tomi

-- 
Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to