From 9f2a9e624b59f50ad0f4a47a63c659d3af31f30a Mon Sep 17 00:00:00 2001 From: BPI-M2C Date: Sun, 20 Sep 2026 12:00:00 +0800 Subject: [PATCH] uboot: sprd: fix MIPI panel probe failure reboot When multiple panel nodes are probed, release IOVDD together with the other panel GPIOs. Otherwise the next candidate fails with -EBUSY. Handle power-on errors without attempting an ID read, and never continue initializing the last candidate after all panel ID probes have failed. Continuing after panel_slave_if_uinit() caused an access to the powered-off DSI1 register block at 0x31400000 and a synchronous abort. Also unwind GPIOs acquired by a partially failed power-on sequence and check the selected init callback before invoking it. --- drivers/video/sprd/panel-if/panel_ops_mipi.c | 31 ++++++++++++++++++++++++---- drivers/video/sprd/sprd_panel.c | 38 +++++++++++++++++--------- 2 files changed, 52 insertions(+), 17 deletions(-) --- a/drivers/video/sprd/panel-if/panel_ops_mipi.c +++ b/drivers/video/sprd/panel-if/panel_ops_mipi.c @@ -378,6 +378,10 @@ struct panel_info *info = &panel_device; struct power_gpio *io = &info->power_pin; int ret; + bool iovdd_requested = false; + bool avdd_requested = false; + bool avee_requested = false; + bool reset_requested = false; if (!io->gpio_reset) { pr_err("gpio_reset is NULL\n"); @@ -390,8 +394,9 @@ &power_iovdd, GPIOD_IS_OUT); if (ret) { pr_err("request sprd,lcd-iovdd-gpio fail:%d\n", ret); - return ret; + goto power_on_failed; } + iovdd_requested = true; dm_gpio_set_value(&power_iovdd, 1); mdelay(10); } @@ -401,8 +406,9 @@ &power_avdd, GPIOD_IS_OUT); if (ret) { pr_err("request sprd,lcd-avdd-gpio fail:%d\n", ret); - return ret; + goto power_on_failed; } + avdd_requested = true; dm_gpio_set_value(&power_avdd, 1); mdelay(info->power_gpio_delay); } @@ -412,8 +418,9 @@ &power_avee, GPIOD_IS_OUT); if (ret) { pr_err("request sprd,lcd-avee-gpio fail:%d\n", ret); - return ret; + goto power_on_failed; } + avee_requested = true; dm_gpio_set_value(&power_avee, 1); mdelay(20); } @@ -435,8 +442,9 @@ &power_reset, GPIOD_IS_OUT); if (ret) { pr_err("request sprd,lcd-reset-gpio fail:%d\n", ret); - return ret; + goto power_on_failed; } + reset_requested = true; timing = info->power_on_seq.timing; for (i = 0; i < info->power_on_seq.items; i++) { @@ -463,10 +471,25 @@ dm_gpio_free(dev, &power_avdd); dm_gpio_free(dev, &power_avee); + dm_gpio_free(dev, &power_iovdd); dm_gpio_free(dev, &power_off); } #endif return 0; + +#ifndef CONFIG_FPGA +power_on_failed: + if (reset_requested) + dm_gpio_free(dev, &power_reset); + if (avee_requested) + dm_gpio_free(dev, &power_avee); + if (avdd_requested) + dm_gpio_free(dev, &power_avdd); + if (iovdd_requested) + dm_gpio_free(dev, &power_iovdd); + + return ret; +#endif } static int panel_set_brightness(int level) --- a/drivers/video/sprd/sprd_panel.c +++ b/drivers/video/sprd/sprd_panel.c @@ -821,12 +821,13 @@ static int sprd_panel_probe(struct udevice *dev) { struct panel_info *info; - struct sprd_panel_ops *ops; + struct sprd_panel_ops *ops = NULL; u8 *info_addr; int lcd_offset, offset; int ret = -1; int lcd_panel_offset = 0; int info_size; + bool panel_powered; struct udevice *panel_dev = NULL; const void *fdt = gd->fdt_blob; @@ -877,6 +878,7 @@ for (offset = fdt_first_subnode(fdt, lcd_offset); offset >= 0; offset = fdt_next_subnode(fdt, offset)) { + panel_powered = false; if (info) { memset((uint8_t *)info_addr, 0, info_size); of_parse_panel(fdt, offset, info); @@ -890,7 +892,13 @@ ops = panel_drv->ops; if (ops && ops->power) { printf("enter power panel\n"); - ops->power(dev, true); + ret = ops->power(dev, true); + if (ret) { + pr_err("power on panel 0x%x failed: %d\n", + info->lcd_id, ret); + goto panel_probe_failed; + } + panel_powered = true; } if (ops && ops->read_id) { @@ -903,7 +911,8 @@ } } - if (ops && ops->power) { +panel_probe_failed: + if (panel_powered && ops && ops->power) { ops->power(dev, false); } @@ -919,7 +928,7 @@ if (ret) { pr_err("No Panel Attached!\n"); - //return -1; + return ret; } if (info->dual_dsi_en){ @@ -929,18 +938,21 @@ panel_if_init(); } - if (ops && ops->init){ - if(info->mipi_port == 0){ + if (info->mipi_port == 0) { + if (ops && ops->init) ops->init(); - } - else + } else { + if (ops && ops->slave_init) ops->slave_init(); } - if (info->dual_dsi_en){ - if(info->mipi_port == 0) - ops->slave_init(); - else - ops->init(); + if (info->dual_dsi_en) { + if (info->mipi_port == 0) { + if (ops && ops->slave_init) + ops->slave_init(); + } else { + if (ops && ops->init) + ops->init(); + } } -- 2.34.1