-
Notifications
You must be signed in to change notification settings - Fork 5.4k
Description
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.
- Add stabilization delay in probe:
C
ts->i2c = i2c;
msleep(100); /* Allow panel controller to stabilize after power-up */
- 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;
}