Re: [PATCH] drm/bridge: adv7511: Fix Intermittent EDID failures

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 5/22/24 05:51, Adam Ford wrote:
> On Mon, May 20, 2024 at 8:16 PM Adam Ford <aford173@xxxxxxxxx> wrote:
>>
>> In the process of adding support for shared IRQ pins, a scenario
>> was accidentally created where adv7511_irq_process returned
>> prematurely causing the EDID to fail randomly.
>>
>> Since the interrupt handler is broken up into two main helper functions,
>> update both of them to treat the helper functions as IRQ handlers. These
>> IRQ routines process their respective tasks as before, but if they
>> determine that actual work was done, mark the respective IRQ status
>> accordingly, and delay the check until everything has been processed.
>>
>> This should guarantee the helper functions don't return prematurely
>> while still returning proper values of either IRQ_HANDLED or IRQ_NONE.
>>
>> Reported by: Liu Ying <victor.liu@xxxxxxx>

s/Reported by/Reported-by/

>> Fixes: f3d9683346d6 ("drm/bridge: adv7511: Allow IRQ to share GPIO pins")
>> Signed-off-by: Adam Ford <aford173@xxxxxxxxx>
> 
> + Liu
> 
> Sorry about the e-mail address copy-paste error.

No worries.

With this patch, it looks EDID retrieval works ok for me without
interrupt requested.

Tested-by: Liu Ying <victor.liu@xxxxxxx> # i.MX8MP EVK ADV7535 EDID retrieval w/o IRQ

>>
>> diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511.h b/drivers/gpu/drm/bridge/adv7511/adv7511.h
>> index ea271f62b214..ec0b7f3d889c 100644
>> --- a/drivers/gpu/drm/bridge/adv7511/adv7511.h
>> +++ b/drivers/gpu/drm/bridge/adv7511/adv7511.h
>> @@ -401,7 +401,7 @@ struct adv7511 {
>>
>>  #ifdef CONFIG_DRM_I2C_ADV7511_CEC
>>  int adv7511_cec_init(struct device *dev, struct adv7511 *adv7511);
>> -void adv7511_cec_irq_process(struct adv7511 *adv7511, unsigned int irq1);
>> +int adv7511_cec_irq_process(struct adv7511 *adv7511, unsigned int irq1);
>>  #else
>>  static inline int adv7511_cec_init(struct device *dev, struct adv7511 *adv7511)
>>  {
>> diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_cec.c b/drivers/gpu/drm/bridge/adv7511/adv7511_cec.c
>> index 44451a9658a3..4efb2cabf1b5 100644
>> --- a/drivers/gpu/drm/bridge/adv7511/adv7511_cec.c
>> +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_cec.c
>> @@ -119,7 +119,7 @@ static void adv7511_cec_rx(struct adv7511 *adv7511, int rx_buf)
>>         cec_received_msg(adv7511->cec_adap, &msg);
>>  }
>>
>> -void adv7511_cec_irq_process(struct adv7511 *adv7511, unsigned int irq1)
>> +int adv7511_cec_irq_process(struct adv7511 *adv7511, unsigned int irq1)
>>  {
>>         unsigned int offset = adv7511->info->reg_cec_offset;
>>         const u32 irq_tx_mask = ADV7511_INT1_CEC_TX_READY |
>> @@ -130,17 +130,21 @@ void adv7511_cec_irq_process(struct adv7511 *adv7511, unsigned int irq1)
>>                                 ADV7511_INT1_CEC_RX_READY3;
>>         unsigned int rx_status;
>>         int rx_order[3] = { -1, -1, -1 };
>> -       int i;
>> +       int i, ret = 0;
>> +       int irq_status = IRQ_NONE;
>>
>> -       if (irq1 & irq_tx_mask)
>> +       if (irq1 & irq_tx_mask) {
>>                 adv_cec_tx_raw_status(adv7511, irq1);
>> +               irq_status = IRQ_HANDLED;
>> +       }
>>
>>         if (!(irq1 & irq_rx_mask))
>> -               return;
>> +               return irq_status;
>>
>> -       if (regmap_read(adv7511->regmap_cec,
>> -                       ADV7511_REG_CEC_RX_STATUS + offset, &rx_status))
>> -               return;
>> +       ret = regmap_read(adv7511->regmap_cec,
>> +                       ADV7511_REG_CEC_RX_STATUS + offset, &rx_status);
>> +       if (ret < 0)
>> +               return ret;
>>
>>         /*
>>          * ADV7511_REG_CEC_RX_STATUS[5:0] contains the reception order of RX
>> @@ -172,6 +176,8 @@ void adv7511_cec_irq_process(struct adv7511 *adv7511, unsigned int irq1)
>>
>>                 adv7511_cec_rx(adv7511, rx_buf);
>>         }
>> +
>> +       return IRQ_HANDLED;
>>  }
>>
>>  static int adv7511_cec_adap_enable(struct cec_adapter *adap, bool enable)
>> diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
>> index 66ccb61e2a66..56dd2d5a0376 100644
>> --- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
>> +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
>> @@ -469,6 +469,8 @@ static int adv7511_irq_process(struct adv7511 *adv7511, bool process_hpd)
>>  {
>>         unsigned int irq0, irq1;
>>         int ret;
>> +       int cec_status;
>> +       int irq_status = IRQ_NONE;
>>
>>         ret = regmap_read(adv7511->regmap, ADV7511_REG_INT(0), &irq0);
>>         if (ret < 0)
>> @@ -478,38 +480,41 @@ static int adv7511_irq_process(struct adv7511 *adv7511, bool process_hpd)
>>         if (ret < 0)
>>                 return ret;
>>
>> -       /* If there is no IRQ to handle, exit indicating no IRQ data */
>> -       if (!(irq0 & (ADV7511_INT0_HPD | ADV7511_INT0_EDID_READY)) &&
>> -           !(irq1 & ADV7511_INT1_DDC_ERROR))
>> -               return -ENODATA;
>> -
>>         regmap_write(adv7511->regmap, ADV7511_REG_INT(0), irq0);
>>         regmap_write(adv7511->regmap, ADV7511_REG_INT(1), irq1);
>>
>> -       if (process_hpd && irq0 & ADV7511_INT0_HPD && adv7511->bridge.encoder)
>> +       if (process_hpd && irq0 & ADV7511_INT0_HPD && adv7511->bridge.encoder) {
>>                 schedule_work(&adv7511->hpd_work);
>> +               irq_status = IRQ_HANDLED;
>> +       }
>>
>>         if (irq0 & ADV7511_INT0_EDID_READY || irq1 & ADV7511_INT1_DDC_ERROR) {
>>                 adv7511->edid_read = true;
>>
>>                 if (adv7511->i2c_main->irq)
>>                         wake_up_all(&adv7511->wq);
>> +               irq_status = IRQ_HANDLED;
>>         }
>>
>>  #ifdef CONFIG_DRM_I2C_ADV7511_CEC
>> -       adv7511_cec_irq_process(adv7511, irq1);
>> +       cec_status = adv7511_cec_irq_process(adv7511, irq1);
>> +
>> +       if (cec_status < 0)
>> +               return cec_status;
>>  #endif
>>
>> -       return 0;
>> +       /* If there is no IRQ to handle, exit indicating no IRQ data */
>> +       if (irq_status == IRQ_HANDLED || cec_status == IRQ_HANDLED)
>> +               return IRQ_HANDLED;
>> +
>> +       return IRQ_NONE;
>>  }
>>
>>  static irqreturn_t adv7511_irq_handler(int irq, void *devid)
>>  {
>>         struct adv7511 *adv7511 = devid;
>> -       int ret;
>>
>> -       ret = adv7511_irq_process(adv7511, true);
>> -       return ret < 0 ? IRQ_NONE : IRQ_HANDLED;
>> +       return adv7511_irq_process(adv7511, true);
>>  }
>>
>>  /* -----------------------------------------------------------------------------
>> --
>> 2.43.0
>>




[Index of Archives]     [Linux DRI Users]     [Linux Intel Graphics]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux