Re: [PATCHv3] drm: adv7511/33: Fix adv7511_cec_init() failure handling

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

 



Hi Hans,

Thank you for the patch.

On Tuesday, 21 November 2017 10:17:43 EET Hans Verkuil wrote:
> If the device tree for a board did not specify a cec clock, then
> adv7511_cec_init would return an error, which would cause adv7511_probe()
> to fail and thus there is no HDMI output.
> 
> There is no need to have adv7511_probe() fail if the CEC initialization
> fails, so just change adv7511_cec_init() to a void function. In addition,
> adv7511_cec_init() should just return silently if the cec clock isn't
> found and show a message for any other errors.
> 
> An otherwise correct cleanup patch from Dan Carpenter turned this broken
> failure handling into a kernel Oops, so bisection points to commit
> 7af35b0addbc ("drm/kirin: Checking for IS_ERR() instead of NULL") rather
> than 3b1b975003e4 ("drm: adv7511/33: add HDMI CEC support").
> 
> Based on earlier patches from Arnd and John.
> 
> Reported-by: Naresh Kamboju <naresh.kamboju@xxxxxxxxxx>
> Cc: Xinliang Liu <xinliang.liu@xxxxxxxxxx>
> Cc: Dan Carpenter <dan.carpenter@xxxxxxxxxx>
> Cc: Sean Paul <seanpaul@xxxxxxxxxxxx>
> Cc: Archit Taneja <architt@xxxxxxxxxxxxxx>
> Cc: John Stultz <john.stultz@xxxxxxxxxx>
> Link: https://bugs.linaro.org/show_bug.cgi?id=3345
> Link: https://lkft.validation.linaro.org/scheduler/job/48017#L3551
> Fixes: 7af35b0addbc ("drm/kirin: Checking for IS_ERR() instead of NULL")
> Fixes: 3b1b975003e4 ("drm: adv7511/33: add HDMI CEC support")
> Signed-off-by: Hans Verkuil <hans.verkuil@xxxxxxxxx>
> Tested-by: Hans Verkuil <hans.verkuil@xxxxxxxxx>

Reviewed-by: Laurent Pinchart <laurent.pinchart@xxxxxxxxxxxxxxxx>

> ---
> This rework of Arnd and John's patches goes a bit further and just silently
> exits if there is no cec clock defined in the dts. I'm sure that's the
> reason why the kirin board failed on this. BTW: if the kirin board DOES
> support cec, then it would be nice if it can be hooked up in the dts!
> 
> Tested with my Dragonboard and Renesas Koelsch board. Also tested what
> happens when probing is deferred due to missing cec clock.
> 
> John, can you test this again?
> 
> Changes since v2:
> - reverted adv7511_cec_init back to an int function for EPROBE_DEFER
> - incorporated Laurent's comments
> - moved the adv7511_cec_init call up in the probe function to prevent
>   having to remove the bridge in case of an error.
> 
> Change since my previous RFC PATCH:
> 
> - added static inline adv7511_cec_init to avoid #ifdef in the probe function
> as suggested by John Stultz.
> 
> Regards,
> 
> 	Hans
> ---
> diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511.h
> b/drivers/gpu/drm/bridge/adv7511/adv7511.h index b4efcbabf7f7..d034b2cb5eee
> 100644
> --- a/drivers/gpu/drm/bridge/adv7511/adv7511.h
> +++ b/drivers/gpu/drm/bridge/adv7511/adv7511.h
> @@ -372,9 +372,18 @@ struct adv7511 {
>  };
> 
>  #ifdef CONFIG_DRM_I2C_ADV7511_CEC
> -int adv7511_cec_init(struct device *dev, struct adv7511 *adv7511,
> -		     unsigned int offset);
> +int adv7511_cec_init(struct device *dev, struct adv7511 *adv7511);
>  void adv7511_cec_irq_process(struct adv7511 *adv7511, unsigned int irq1);
> +#else
> +static inline int adv7511_cec_init(struct device *dev, struct adv7511
> *adv7511) +{
> +	unsigned int offset = adv7511->type == ADV7533 ?
> +						ADV7533_REG_CEC_OFFSET : 0;
> +
> +	regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL + offset,
> +		     ADV7511_CEC_CTRL_POWER_DOWN);
> +	return 0;
> +}
>  #endif
> 
>  #ifdef CONFIG_DRM_I2C_ADV7533
> diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_cec.c
> b/drivers/gpu/drm/bridge/adv7511/adv7511_cec.c index
> b33d730e4d73..a20a45c0b353 100644
> --- a/drivers/gpu/drm/bridge/adv7511/adv7511_cec.c
> +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_cec.c
> @@ -300,18 +300,21 @@ static int adv7511_cec_parse_dt(struct device *dev,
> struct adv7511 *adv7511) return 0;
>  }
> 
> -int adv7511_cec_init(struct device *dev, struct adv7511 *adv7511,
> -		     unsigned int offset)
> +int adv7511_cec_init(struct device *dev, struct adv7511 *adv7511)
>  {
> +	unsigned int offset = adv7511->type == ADV7533 ?
> +						ADV7533_REG_CEC_OFFSET : 0;
>  	int ret = adv7511_cec_parse_dt(dev, adv7511);
> 
>  	if (ret)
> -		return ret;
> +		goto err_cec_parse_dt;
> 
>  	adv7511->cec_adap = cec_allocate_adapter(&adv7511_cec_adap_ops,
>  		adv7511, dev_name(dev), CEC_CAP_DEFAULTS, ADV7511_MAX_ADDRS);
> -	if (IS_ERR(adv7511->cec_adap))
> -		return PTR_ERR(adv7511->cec_adap);
> +	if (IS_ERR(adv7511->cec_adap)) {
> +		ret = PTR_ERR(adv7511->cec_adap);
> +		goto err_cec_alloc;
> +	}
> 
>  	regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL + offset, 0);
>  	/* cec soft reset */
> @@ -329,9 +332,18 @@ int adv7511_cec_init(struct device *dev, struct adv7511
> *adv7511, ((adv7511->cec_clk_freq / 750000) - 1) << 2);
> 
>  	ret = cec_register_adapter(adv7511->cec_adap, dev);
> -	if (ret) {
> -		cec_delete_adapter(adv7511->cec_adap);
> -		adv7511->cec_adap = NULL;
> -	}
> -	return ret;
> +	if (ret)
> +		goto err_cec_register;
> +	return 0;
> +
> +err_cec_register:
> +	cec_delete_adapter(adv7511->cec_adap);
> +	adv7511->cec_adap = NULL;
> +err_cec_alloc:
> +	dev_info(dev, "Initializing CEC failed with error %d, disabling CEC\n",
> +		 ret);
> +err_cec_parse_dt:
> +	regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL + offset,
> +		     ADV7511_CEC_CTRL_POWER_DOWN);
> +	return ret == -EPROBE_DEFER ? ret : 0;
>  }
> diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
> b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c index
> 0e14f1572d05..efa29db5fc2b 100644
> --- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
> +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
> @@ -1084,7 +1084,6 @@ static int adv7511_probe(struct i2c_client *i2c, const
> struct i2c_device_id *id) struct device *dev = &i2c->dev;
>  	unsigned int main_i2c_addr = i2c->addr << 1;
>  	unsigned int edid_i2c_addr = main_i2c_addr + 4;
> -	unsigned int offset;
>  	unsigned int val;
>  	int ret;
> 
> @@ -1192,24 +1191,16 @@ static int adv7511_probe(struct i2c_client *i2c,
> const struct i2c_device_id *id) if (adv7511->type == ADV7511)
>  		adv7511_set_link_config(adv7511, &link_config);
> 
> +	ret = adv7511_cec_init(dev, adv7511);
> +	if (ret)
> +		goto err_unregister_cec;
> +
>  	adv7511->bridge.funcs = &adv7511_bridge_funcs;
>  	adv7511->bridge.of_node = dev->of_node;
> 
>  	drm_bridge_add(&adv7511->bridge);
> 
>  	adv7511_audio_init(dev, adv7511);
> -
> -	offset = adv7511->type == ADV7533 ? ADV7533_REG_CEC_OFFSET : 0;
> -
> -#ifdef CONFIG_DRM_I2C_ADV7511_CEC
> -	ret = adv7511_cec_init(dev, adv7511, offset);
> -	if (ret)
> -		goto err_unregister_cec;
> -#else
> -	regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL + offset,
> -		     ADV7511_CEC_CTRL_POWER_DOWN);
> -#endif
> -
>  	return 0;
> 
>  err_unregister_cec:

-- 
Regards,

Laurent Pinchart

_______________________________________________
dri-devel mailing list
dri-devel@xxxxxxxxxxxxxxxxxxxxx
https://lists.freedesktop.org/mailman/listinfo/dri-devel




[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