imx6: i2c_transfer timeout issue after resume

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

imx6: i2c_transfer timeout issue after resume

2,202 Views
pintukumar
Contributor II

[i.MX6] Suspend/resume implementation for dw_hdmi-imx.c

IMX6 LVDS and HDMI display

Hi,

On a custom imx6dl board (with custom 4.9 kernel), we are facing i2c_transfer timeout issue after system resume.

So, I need some help in debugging this issue.

This does not happen in normal boot case (without suspend/resume).

 These are the steps I follow for my use case:
* Boot the system normally (without display) and install all imx-drm as modules.
* Then uninstall the modules in reverse order.
* Take the snapshot of the system (suspend to disk).
* Reboot the system and boot with the image.
* Install all the modules again.
* Then launch the Weston.
* During the weston launch in the beginning we observe this error.

After system resume, HDMI is trying to get EDID data from the monitor using I2C interface.
But its seems i2c_transfer is getting timeout after 5 retries.
Thus EDID data is failing, and HDMI could not able to detect the monitor.

This is the logs:

[ 441.104989] [drm:drm_helper_probe_single_connector_modes] [CONNECTOR:29:HDMI-A-1] status updated from unknown to connected
[ 441.116080]: drm_helper_probe_single_connector_modes - inside - else override_edid
[ 441.124416]: drm_helper_probe_single_connector_modes - inside - else - drm_load_edid_firmware: count: 0
[ 441.134546]: drm_helper_probe_single_connector_modes - calling - get_modes
[ 441.142157]: dw_hdmi_connector_get_modes : called
[ 441.147652]: dw_hdmi_connector_get_modes : called - calling -> drm_get_edid
[ 441.155346]: drm_do_probe_ddc_edid : called!
[ 441.660759]: drm_do_probe_ddc_edid : i2c_transfer: ret: -110, retry: 5
[ 442.170758]: drm_do_probe_ddc_edid : i2c_transfer: ret: -110, retry: 4
[ 442.680755]: drm_do_probe_ddc_edid : i2c_transfer: ret: -110, retry: 3
[ 443.190755]: drm_do_probe_ddc_edid : i2c_transfer: ret: -110, retry: 2
[ 443.700754]: drm_do_probe_ddc_edid : i2c_transfer: ret: -110, retry: 1
[ 443.707989]: drm_get_edid : called - drm_probe_ddc - failed
[ 443.714303] dwhdmi-imx 120000.hdmi: failed to get edid
[ 443.719456]: dw_hdmi_connector_get_modes : DONE: ret: 0

So, please let me know what needs to be done to handle this type of issue.

This is one of our major requirement for our customer, so please support this on high-priority.

Regards,

Pintu

Labels (2)
0 Kudos
7 Replies

1,905 Views
pintukumar
Contributor II

Power Management‌ 

Hi,

Now, I am able to resolve i2c timeout issue after hibernation resume.

Now i2c transfer is working fine after restoring all the mux/pad configuration after resume.

Now, I am facing similar issue with the IPU module.

After resume, LCD display is working fine, but HDMI is not working.

I get "vblank timeout issue". I found that ipu_irq_handler is not getting called for crtc 1 (hdmi case).

This handler in: drivers/gpu/drm/imx-ipuv3-crtc.c

static irqreturn_t ipu_irq_handler(int irq, void *dev_id)
{
struct ipu_crtc *ipu_crtc = dev_id;

pr_info("%s: called\n", __func__);
imx_drm_handle_vblank(ipu_crtc->imx_crtc);

return IRQ_HANDLED;
}

Thus timeout is happening.

I guess this is happening because IOMUX/PAD configuration for IPU/HDMI is losted after the system resume from image.

So, I wanted to know, how to verify the IOMUX details before and after the resume.

Also, how to save and restore the IOMUX data with suspend and resume?

Please help!

Regards,

Pintu

0 Kudos

1,905 Views
pintukumar
Contributor II

Hi,

Currently, I suspect that i2c needs to be re-initialized again in the resume path.

So, I needed some function, like i2c_imx_init() which can be called after resume.

I found that these functionalities are available in other vendors such as tegra/exynos etc.

Like: tegra_i2c_inti() ; exynos5_i2c_init()

Please check the reference here:

i2c-tegra.c\busses\i2c\drivers - kernel/git/torvalds/linux.git - Linux kernel source tree 

i2c-exynos5.c\busses\i2c\drivers - kernel/git/stable/linux.git - Linux kernel stable tree 

So, I needed a similar function for i2c_imx driver.

Please let me know how to implement this for imx6.

Regards,

Pintu

0 Kudos

1,905 Views
igorpadykov
NXP Employee
NXP Employee

Hi Pintu

one can check "Inter-IC (I2C)" Chapter in Linux Manual

included in Linux L4.14.98_2.0.0 Documentation

Best regards
igor

0 Kudos

1,905 Views
igorpadykov
NXP Employee
NXP Employee

Hi Pintu

may be recommended to try to reproduce issue on NXP Sabre SD reference board

with latest NXP Demo Images from below link

i.MX Software | NXP 

Best regards
igor
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos

1,905 Views
pintukumar
Contributor II

Dear Igor,

Thank you so much for your reply.

But, I am afraid, moving to another board at this time is not feasible, as this is customer requirement on existing products.

The HDMI edid reading from monitor using i2c_transfer is working fine. So I think there is no hardware issue.

We are only facing i2c_transfer timeout issue after full system resume.

Also, the LCD is working fine.

So, if anything can be done in this version itself, please let me know.

I just need some clue to debug the issue. I will try to fix myself.

I tried to implement suspend/resume support in i2c-imx driver (drivers/i2c/busses/i2c-imx.c).

Like this:

{{{

+static int i2c_imx_suspend(struct device *dev) +{ +       pinctrl_pm_select_sleep_state(dev); + +       pr_info("[PINTU]: %s: Done\n", __func__); + +       return 0; +} + +static int i2c_imx_resume(struct device *dev) +{ +       pinctrl_pm_select_default_state(dev); + +       pr_info("[PINTU]: %s: Done\n", __func__); + +       return 0; +} + + +static SIMPLE_DEV_PM_OPS(i2c_imx_pm_ops, i2c_imx_suspend, i2c_imx_resume); +  static struct platform_driver i2c_imx_driver = {         .probe = i2c_imx_probe,         .remove = i2c_imx_remove,         .driver = {                 .name   = DRIVER_NAME,                 .owner  = THIS_MODULE, +               .pm = &i2c_imx_pm_ops,                 .of_match_table = i2c_imx_dt_ids,         },         .id_table       = imx_i2c_devtype,

}}}

But still I get i2c_transfer timeout issue.

I also tried to implement like this:

{{{

static int i2c_imx_suspend(struct device *dev)
{
struct platform_device *pdev = container_of(dev,
struct platform_device, dev);
struct imx_i2c_struct *i2c_imx = platform_get_drvdata(pdev);

clk_disable_unprepare(i2c_imx->clk);
devm_clk_put(&pdev->dev, NULL);

i2c_imx->suspended = 1;

return 0;
}

static int i2c_imx_resume(struct device *dev)
{
struct platform_device *pdev = container_of(dev,
struct platform_device, dev);
struct imx_i2c_struct *i2c_imx = platform_get_drvdata(pdev);
int ret;

i2c_imx->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(i2c_imx->clk)) {
dev_err(&pdev->dev, "can't get I2C clock\n");
return PTR_ERR(i2c_imx->clk);
}

ret = clk_prepare_enable(i2c_imx->clk);
if (ret) {
dev_err(dev, "Cannot enable clock.\n");
return ret;
}

i2c_imx->suspended = 0;

return 0;
}


static const struct dev_pm_ops i2c_imx_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(i2c_imx_suspend,
i2c_imx_resume)
};

}}}

But, this way it gives some backtraces, and clk_disable fails.

So, I am not sure which is the right way, and also not sure whether suspend/resume can resolve i2c transfer issue.

Currently, I think, after resume, i2c-imx would have gone to some invalid state.

So, if you have any other pointers about i2c_transfer timeout issue (after resume).

Please help!

This is a customer specific requirement, so at least we need to update what is the exact issue.

Regards,

Pintu

0 Kudos

1,904 Views
igorpadykov
NXP Employee
NXP Employee

Hi Pintu

for issues which can not be reproduced on nxp reference boards may be

recommended to try extended support with NXP Professional Services:
Commercial Support and Engineering Services | NXP 

Best regards
igor

0 Kudos

1,905 Views
pintukumar
Contributor II

Dear Igor,

Thanks for your help!

I found that i2c-imx needs to be reinitialized again in the resume path.

But, I am not sure how to do it for imx.

I tried to do it like this: just like in latest mainline code, but this

also does not work.

It says cannot enable clock.

static int __maybe_unused i2c_imx_runtime_suspend(struct device *dev){

struct imx_i2c_struct *i2c_imx = dev_get_drvdata(dev);

clk_disable(i2c_imx->clk);

return 0;}

static int __maybe_unused i2c_imx_runtime_resume(struct device *dev){

struct imx_i2c_struct *i2c_imx = dev_get_drvdata(dev);

int ret;

ret = clk_enable(i2c_imx->clk);

if (ret)

dev_err(dev, "can't enable I2C clock, ret=%d\n", ret);

return ret;}

imx-i2c 21a8000.i2c: can't enable I2C clock, ret=-108

i2c i2c-2:

i2c i2c-2:

: i2c_imx_start: Done: result: 0

: i2c_imx_resume: Done

So, I just want to know the right way to re-init i2c after resume.

I think some reference patch should be enough for me.

Regards,

Pintu

0 Kudos