Skip to content

panel-waveshare-dsi: Reliable initialization failure on cold boot due to missing stabilization delays and retry logic #7240

Description

@m0g13r

Describe the bug

The current implementation of the panel-waveshare-dsi driver (specifically for DSI-based Waveshare panels using the Goodix/Ilitek controllers) frequently fails to initialize during cold boots. This results in a dark screen or failed touch/panel probe, as the I2C communication is attempted before the panel's internal controller has stabilized.

The driver lacks standard defensive programming patterns required for embedded display hardware, such as power-up delays or retry loops for critical I2C initialization commands.

Steps to reproduce the behaviour

make cold boot :)

Device (s)

Raspberry Pi 5

System

volumio

Logs

No response

Additional context

In drivers/gpu/drm/panel/panel-waveshare-dsi.c, the ws_panel_probe function (line 390) executes several I2C writes immediately after obtaining the handle:
C

ts->i2c = i2c;

ws_panel_i2c_write(ts, 0xc0, 0x01);
ws_panel_i2c_write(ts, 0xc2, 0x01);
ws_panel_i2c_write(ts, 0xac, 0x01);

The ws_panel_i2c_write function (line 309) is a "single-shot" attempt:
C

static void ws_panel_i2c_write(struct ws_panel *ts, u8 reg, u8 val)
{
int ret;
ret = i2c_smbus_write_byte_data(ts->i2c, reg, val);
if (ret)
dev_err(&ts->i2c->dev, "I2C write failed: %d\n", ret);
}

If the panel is still in its power-up cycle, these writes fail, the error is logged, and the panel remains uninitialized. Unlike other production-grade DSI drivers (e.g., those using ILITEK controllers), there is no msleep() to allow for stabilization and no retry logic.
Suggested Fix

A minimum viable fix involves adding a delay before the first I2C write and implementing a retry mechanism in the write function.

  1. Add stabilization delay in probe:
    C

ts->i2c = i2c;
msleep(100); /* Allow panel controller to stabilize after power-up */

  1. Improve ws_panel_i2c_write with retries:
    C

static int ws_panel_i2c_write(struct ws_panel *ts, u8 reg, u8 val)
{
int ret, retries = 5;

while (retries--) {
    ret = i2c_smbus_write_byte_data(ts->i2c, reg, val);
    if (!ret) return 0;
    msleep(50);
}
dev_err(&ts->i2c->dev, "I2C write failed after multiple retries: %d\n", ret);
return ret;

}

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions