[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <2716873.T4RGvjZqqn@avalon>
Date: Tue, 21 Nov 2017 08:48:01 +0200
From: Laurent Pinchart <laurent.pinchart@...asonboard.com>
To: Hans Verkuil <hverkuil@...all.nl>
Cc: Arnd Bergmann <arnd@...db.de>, Bhumika Goyal <bhumirks@...il.com>,
David Airlie <airlied@...ux.ie>,
lkml <linux-kernel@...r.kernel.org>,
dri-devel@...ts.freedesktop.org,
Hans Verkuil <hans.verkuil@...co.com>,
Dan Carpenter <dan.carpenter@...cle.com>,
John Stultz <john.stultz@...aro.org>
Subject: Re: [PATCHv2] drm: adv7511/33: Fix adv7511_cec_init() failure handling
Hi Hans,
Thank you for the patch.
On Monday, 20 November 2017 22:57:34 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.
I don't think that's correct. You at least need to defer probing if the clock
is specified in DT but has no provider available yet. For other errors I agree
that we can still initialize the ADV7511 in a degraded mode without CEC
support, although I would prefer to also error out in case of invalid DT to
ensure that DT errors are caught as early as possible.
> 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@...aro.org>
> Cc: Xinliang Liu <xinliang.liu@...aro.org>
> Cc: Dan Carpenter <dan.carpenter@...cle.com>
> Cc: Sean Paul <seanpaul@...omium.org>
> Cc: Archit Taneja <architt@...eaurora.org>
> Cc: John Stultz <john.stultz@...aro.org>
> 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@...co.com>
> Tested-by: Hans Verkuil <hans.verkuil@...co.com>
> ---
> This rework of Arnd and John's patches goes a bit further and makes
> cec_init a void function 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.
>
> 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 543a5eb91624..16051bfa5578
> 100644
> --- a/drivers/gpu/drm/bridge/adv7511/adv7511.h
> +++ b/drivers/gpu/drm/bridge/adv7511/adv7511.h
> @@ -374,9 +374,17 @@ struct adv7511 {
> };
>
> #ifdef CONFIG_DRM_I2C_ADV7511_CEC
> -int adv7511_cec_init(struct device *dev, struct adv7511 *adv7511,
> - unsigned int offset);
> +void adv7511_cec_init(struct device *dev, struct adv7511 *adv7511,
> + unsigned int offset);
> void adv7511_cec_irq_process(struct adv7511 *adv7511, unsigned int irq1);
> +#else
> +static inline void adv7511_cec_init(struct device *dev,
> + struct adv7511 *adv7511,
> + unsigned int offset)
> +{
> + regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL + offset,
> + ADV7511_CEC_CTRL_POWER_DOWN);
> +}
> #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..c1cd471d31fa 100644
> --- a/drivers/gpu/drm/bridge/adv7511/adv7511_cec.c
> +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_cec.c
> @@ -300,18 +300,20 @@ 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)
> +void adv7511_cec_init(struct device *dev, struct adv7511 *adv7511,
> + unsigned int offset)
> {
> int ret = adv7511_cec_parse_dt(dev, adv7511);
>
> if (ret)
> - return ret;
> + goto disable_cec;
>
> 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 fail;
> + }
>
> regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL + offset, 0);
> /* cec soft reset */
> @@ -329,9 +331,15 @@ 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)
> + return;
This confused me for an instant, I think a goto error_cec_delete would be
clearer, but that's up to you (maybe I just wasn't awake enough).
> + cec_delete_adapter(adv7511->cec_adap);
> + adv7511->cec_adap = NULL;
> +
> +fail:
Nitpicking, I'd name this error to match the labels in the probe function.
> + dev_info(dev, "Initializing CEC failed with error %d, disabling CEC\n",
> + ret);
> +disable_cec:
> + regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL + offset,
> + ADV7511_CEC_CTRL_POWER_DOWN);
> }
> diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
> b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c index
> 3a33075dbb22..2eb465827bcd 100644
> --- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
> +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
> @@ -1200,15 +1200,7 @@ static int adv7511_probe(struct i2c_client *i2c,
> const struct i2c_device_id *id) 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
> + adv7511_cec_init(dev, adv7511, offset);
Now that the offset is only passed to this function, how about computing it in
adv7511_cec_init() to store as much CEC code as possible in drivers/gpu/drm/
bridge/adv7511/adv7511_cec.c ?
>
> return 0;
--
Regards,
Laurent Pinchart
Powered by blists - more mailing lists