196 lines
4.8 KiB
Diff
196 lines
4.8 KiB
Diff
From 9f2a9e624b59f50ad0f4a47a63c659d3af31f30a Mon Sep 17 00:00:00 2001
|
|||
|
|
From: BPI-M2C <bpi-m2c@local>
|
||
|
|
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
|