summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuihai Zhou <zhouruihai@huaqin.corp-partner.google.com>2023-03-28 16:49:01 +0800
committerLean Sheng Tan <sheng.tan@9elements.com>2023-05-14 12:52:21 +0000
commitd5c1e1330434c750ce0cd7bf635f55b789f67934 (patch)
treeb4f8f88c196793da6f5dded41ceb2acaae22a668
parent946d17a2a53e6d2de8387ba3cd3d94ef91e36f59 (diff)
downloadcoreboot-d5c1e1330434c750ce0cd7bf635f55b789f67934.tar.gz
mb/google/corsola: Add support for MIPI panel
The detachable Starmie will use MIPI panels, which require reading serializable data from the CBFS. So we add MIPI panel support to the display configuration and align the configuration sequence with the panels that use MIPI bridges. The PMIC Datasheet: TPS65132-Single-Inductor-Dual-Output-Power-Supply.pdf BUG=b:275470328 BRANCH=corsola TEST=emerge-corsola coreboot chromeos-bootimage and display normally Signed-off-by: Ruihai Zhou <zhouruihai@huaqin.corp-partner.google.com> Change-Id: I6f079e54f0317ff2f685f0e3834ebd1ceb8e9fcb Reviewed-on: https://review.coreboot.org/c/coreboot/+/74051 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Yidi Lin <yidilin@google.com> Reviewed-by: Yu-Ping Wu <yupingso@google.com>
-rw-r--r--src/mainboard/google/corsola/Makefile.inc4
-rw-r--r--src/mainboard/google/corsola/display.c215
-rw-r--r--src/mainboard/google/corsola/display.h29
-rw-r--r--src/mainboard/google/corsola/panel_anx7625.c61
-rw-r--r--src/mainboard/google/corsola/panel_ps8640.c79
-rw-r--r--src/mainboard/google/corsola/panel_starmie.c46
6 files changed, 314 insertions, 120 deletions
diff --git a/src/mainboard/google/corsola/Makefile.inc b/src/mainboard/google/corsola/Makefile.inc
index d11f6ba295..da6775af2e 100644
--- a/src/mainboard/google/corsola/Makefile.inc
+++ b/src/mainboard/google/corsola/Makefile.inc
@@ -19,5 +19,9 @@ ramstage-y += boardid.c
ramstage-y += chromeos.c
ramstage-y += display.c
ramstage-y += mainboard.c
+ramstage-y += panel_anx7625.c
+ramstage-y += panel_ps8640.c
ramstage-y += regulator.c
ramstage-y += reset.c
+
+ramstage-$(CONFIG_BOARD_GOOGLE_STARMIE) += panel_starmie.c
diff --git a/src/mainboard/google/corsola/display.c b/src/mainboard/google/corsola/display.c
index 22d8c399fd..697db0759e 100644
--- a/src/mainboard/google/corsola/display.c
+++ b/src/mainboard/google/corsola/display.c
@@ -2,163 +2,141 @@
#include <assert.h>
#include <boardid.h>
+#include <cbfs.h>
#include <console/console.h>
#include <delay.h>
-#include <drivers/analogix/anx7625/anx7625.h>
-#include <drivers/parade/ps8640/ps8640.h>
+#include <device/i2c_simple.h>
+#include <edid.h>
#include <gpio.h>
#include <soc/ddp.h>
#include <soc/dsi.h>
#include <soc/gpio_common.h>
-#include <soc/regulator.h>
#include <soc/i2c.h>
#include <soc/mtcmos.h>
#include "display.h"
#include "gpio.h"
-/* Bridge functions */
-static void bridge_ps8640_power_on(void)
+static void backlight_control(void)
{
- /*
- * PS8640 power-on sequence is described in chapter 14, PS8640_DS_V1.4_20200210.docx
- * - set VDD12 to be 1.2V
- * - delay 100us
- * - set VDD33 to be 3.3V
- * - pull hign PD#
- * - pull down RST#
- * - delay 2ms
- * - pull high RST#
- * - delay more than 50ms (55ms for margin)
- * - pull down RST#
- * - delay more than 50ms (55ms for margin)
- * - pull high RST#
- */
-
- /* Set VRF12 to 1.2V and VCN33 to 3.3V */
- mainboard_set_regulator_voltage(MTK_REGULATOR_VRF12, 1200000);
- udelay(100);
- mainboard_set_regulator_voltage(MTK_REGULATOR_VCN33, 3300000);
- udelay(200);
-
- /* Turn on bridge */
- gpio_output(GPIO_EDPBRDG_PWREN, 1);
- gpio_output(GPIO_EDPBRDG_RST_L, 0);
- mdelay(2);
- gpio_output(GPIO_EDPBRDG_RST_L, 1);
- mdelay(55);
- gpio_output(GPIO_EDPBRDG_RST_L, 0);
- mdelay(55);
- gpio_output(GPIO_EDPBRDG_RST_L, 1);
+ /* Disable backlight before turning on bridge */
+ gpio_output(GPIO_AP_EDP_BKLTEN, 0);
+ gpio_output(GPIO_BL_PWM_1V8, 0);
+ gpio_output(GPIO_EN_PP3300_DISP_X, 1);
}
-static int bridge_ps8640_get_edid(u8 i2c_bus, struct edid *edid)
+int panel_pmic_reg_mask(unsigned int bus, uint8_t chip, uint8_t addr,
+ uint8_t val, uint8_t mask)
{
- const u8 chip = 0x8;
+ uint8_t msg = 0;
- if (ps8640_init(i2c_bus, chip) < 0) {
- printk(BIOS_ERR, "%s: Can't init PS8640 bridge\n", __func__);
+ if (i2c_read_field(bus, chip, addr, &msg, 0xFF, 0) < 0) {
+ printk(BIOS_ERR, "%s: Failed to read i2c(%u): addr(%u)\n",
+ __func__, bus, addr);
return -1;
}
- if (ps8640_get_edid(i2c_bus, chip, edid) < 0) {
- printk(BIOS_ERR, "%s: Can't get panel's edid\n", __func__);
- return -1;
- }
- return 0;
-}
-static int bridge_ps8640_post_power_on(u8 i2c_bus, struct edid *edid)
-{
- /* Do nothing */
- return 0;
-}
+ msg &= ~mask;
+ msg |= val;
-static void bridge_anx7625_power_on(void)
-{
- /* Turn on bridge */
- gpio_output(GPIO_EDPBRDG_RST_L, 0);
- gpio_output(GPIO_EN_PP1000_EDPBRDG, 1);
- gpio_output(GPIO_EN_PP1800_EDPBRDG, 1);
- gpio_output(GPIO_EN_PP3300_EDPBRDG, 1);
- mdelay(14);
- gpio_output(GPIO_EDPBRDG_PWREN, 1);
- mdelay(80);
- gpio_output(GPIO_EDPBRDG_RST_L, 1);
+ return i2c_write_field(bus, chip, addr, msg, 0xFF, 0);
}
-static int bridge_anx7625_get_edid(u8 i2c_bus, struct edid *edid)
+void tps65132s_program_eeprom(void)
{
- if (anx7625_init(i2c_bus) < 0) {
- printk(BIOS_ERR, "%s: Can't init ANX7625 bridge\n", __func__);
- return -1;
- }
- if (anx7625_dp_get_edid(i2c_bus, edid) < 0) {
- printk(BIOS_ERR, "%s: Can't get panel's edid\n", __func__);
- return -1;
+ u8 value = 0;
+ u8 value1 = 0;
+
+ /* Initialize I2C6 for PMIC TPS65132 */
+ mtk_i2c_bus_init(PMIC_TPS65132_I2C, I2C_SPEED_FAST);
+ mdelay(10);
+
+ /* EN_PP6000_MIPI_DISP */
+ gpio_output(GPIO_EN_PP3300_DISP_X, 1);
+ /* EN_PP6000_MIPI_DISP_150MA */
+ gpio_output(GPIO_EN_PP3300_SDBRDG_X, 1);
+ mdelay(10);
+
+ i2c_read_field(PMIC_TPS65132_I2C, PMIC_TPS65132_SLAVE, 0x00, &value, 0xFF, 0);
+ i2c_read_field(PMIC_TPS65132_I2C, PMIC_TPS65132_SLAVE, 0x01, &value1, 0xFF, 0);
+
+ if (value != 0x14 || value1 != 0x14) {
+ printk(BIOS_INFO, "Set AVDD AVEE 6.0V to EEPROM Data in first time\n");
+
+ /* Set AVDD = 6.0V */
+ if (panel_pmic_reg_mask(PMIC_TPS65132_I2C, PMIC_TPS65132_SLAVE, 0x00, 0x14,
+ 0x1F) < 0)
+ return;
+
+ /* Set AVEE = -6.0V */
+ if (panel_pmic_reg_mask(PMIC_TPS65132_I2C, PMIC_TPS65132_SLAVE, 0x01, 0x14,
+ 0x1F) < 0)
+ return;
+
+ /* Set EEPROM Data */
+ if (panel_pmic_reg_mask(PMIC_TPS65132_I2C, PMIC_TPS65132_SLAVE, 0xFF, 0x80,
+ 0xFC) < 0)
+ return;
+ mdelay(50);
}
- return 0;
+ /* EN_PP6000_MIPI_DISP */
+ gpio_output(GPIO_EN_PP3300_DISP_X, 0);
+ /* EN_PP6000_MIPI_DISP_150MA */
+ gpio_output(GPIO_EN_PP3300_SDBRDG_X, 0);
+ mdelay(5);
}
-static int bridge_anx7625_post_power_on(u8 i2c_bus, struct edid *edid)
+struct panel_description *get_panel_from_cbfs(struct panel_description *desc)
{
- return anx7625_dp_start(i2c_bus, edid);
+ char cbfs_name[64];
+ static union {
+ u8 raw[4 * 1024];
+ struct panel_serializable_data s;
+ } buffer;
+
+ if (!desc->name)
+ return NULL;
+
+ snprintf(cbfs_name, sizeof(cbfs_name), "panel-%s", desc->name);
+ if (cbfs_load(cbfs_name, buffer.raw, sizeof(buffer)))
+ desc->s = &buffer.s;
+ else
+ printk(BIOS_ERR, "Missing %s in CBFS.\n", cbfs_name);
+
+ return desc->s ? desc : NULL;
}
-/* Display function */
-static void backlight_control(void)
+static struct panel_description *get_active_panel(void)
{
- /* Disable backlight before turning on bridge */
- gpio_output(GPIO_AP_EDP_BKLTEN, 0);
- gpio_output(GPIO_BL_PWM_1V8, 0);
- gpio_output(GPIO_EN_PP3300_DISP_X, 1);
+ if (CONFIG(BOARD_GOOGLE_KINGLER_COMMON))
+ if (CONFIG(BOARD_GOOGLE_STEELIX) && board_id() < 2)
+ return get_ps8640_description();
+ else
+ return get_anx7625_description();
+ else if (CONFIG(BOARD_GOOGLE_KRABBY_COMMON))
+ return get_ps8640_description();
+ else if (CONFIG(BOARD_GOOGLE_STARYU_COMMON))
+ return get_panel_description();
+ else
+ return NULL;
}
-static const struct edp_bridge anx7625_bridge = {
- .power_on = bridge_anx7625_power_on,
- .get_edid = bridge_anx7625_get_edid,
- .post_power_on = bridge_anx7625_post_power_on,
-};
-
-static const struct edp_bridge ps8640_bridge = {
- .power_on = bridge_ps8640_power_on,
- .get_edid = bridge_ps8640_get_edid,
- .post_power_on = bridge_ps8640_post_power_on,
-};
-
int configure_display(void)
{
- struct edid edid;
- const u8 i2c_bus = I2C0;
- const struct edp_bridge *bridge = NULL;
- uint32_t board_version = board_id();
-
- if (CONFIG(BOARD_GOOGLE_KINGLER_COMMON))
- if (CONFIG(BOARD_GOOGLE_STEELIX) && board_version < 2)
- bridge = &ps8640_bridge;
- else
- bridge = &anx7625_bridge;
- else if (CONFIG(BOARD_GOOGLE_KRABBY_COMMON))
- bridge = &ps8640_bridge;
+ const struct panel_description *panel = get_active_panel();
- if (!bridge)
+ if (!panel)
return -1;
printk(BIOS_INFO, "%s: Starting display init\n", __func__);
- mtk_i2c_bus_init(i2c_bus, I2C_SPEED_FAST);
-
/* Set up backlight control pins as output pin and power-off by default */
backlight_control();
- assert(bridge->power_on);
- bridge->power_on();
-
- assert(bridge->get_edid);
- if (bridge->get_edid(i2c_bus, &edid) < 0) {
- printk(BIOS_ERR, "%s: Failed to get edid\n", __func__);
- return -1;
- }
+ if (panel->power_on)
+ panel->power_on();
+ struct edid edid = panel->s->edid;
const char *name = edid.ascii_string;
if (name[0] == '\0')
name = "unknown name";
@@ -176,19 +154,22 @@ int configure_display(void)
MIPI_DSI_MODE_LPM |
MIPI_DSI_MODE_EOT_PACKET);
- if (mtk_dsi_init(mipi_dsi_flags, MIPI_DSI_FMT_RGB888, 4, &edid, NULL) < 0) {
+ if (mtk_dsi_init(mipi_dsi_flags, MIPI_DSI_FMT_RGB888, 4, &edid,
+ panel->s->init) < 0) {
printk(BIOS_ERR, "%s: Failed in DSI init\n", __func__);
return -1;
}
- assert(bridge->post_power_on);
- if (bridge->post_power_on(i2c_bus, &edid) < 0) {
+ if (panel->post_power_on && panel->post_power_on(BRIDGE_I2C, &edid) < 0) {
printk(BIOS_ERR, "%s: Failed to post power on bridge\n", __func__);
return -1;
}
mtk_ddp_mode_set(&edid);
- fb_new_framebuffer_info_from_edid(&edid, (uintptr_t)0);
+ struct fb_info *info = fb_new_framebuffer_info_from_edid(&edid,
+ (uintptr_t)0);
+ if (info)
+ fb_set_orientation(info, panel->orientation);
return 0;
}
diff --git a/src/mainboard/google/corsola/display.h b/src/mainboard/google/corsola/display.h
index 929ddf7002..afff4bf30f 100644
--- a/src/mainboard/google/corsola/display.h
+++ b/src/mainboard/google/corsola/display.h
@@ -4,14 +4,37 @@
#define __MAINBOARD_GOOGLE_CORSOLA_DISPLAY_H__
#include <edid.h>
+#include <mipi/panel.h>
+#include <soc/i2c.h>
-struct edp_bridge {
- void (*power_on)(void);
- int (*get_edid)(u8 i2c_bus, struct edid *edid);
+#define BRIDGE_I2C I2C0
+#define PMIC_TPS65132_I2C I2C6
+#define PMIC_TPS65132_SLAVE 0x3E
+
+struct panel_description {
+ void (*power_on)(void); /* Callback to turn on panel */
int (*post_power_on)(u8 i2c_bus, struct edid *edid);
+ const char *name; /* Panel name in CBFS */
+ struct panel_serializable_data *s;
+ enum lb_fb_orientation orientation;
};
int configure_display(void);
uint32_t panel_id(void);
+/* Return the mipi panel description from given panel id */
+struct panel_description *get_panel_description(void);
+
+/* Return the ANX7625 bridge description */
+struct panel_description *get_anx7625_description(void);
+
+/* Return the PS8640 bridge description */
+struct panel_description *get_ps8640_description(void);
+
+/* Load panel serializable data from CBFS */
+struct panel_description *get_panel_from_cbfs(struct panel_description *desc);
+
+void tps65132s_program_eeprom(void);
+int panel_pmic_reg_mask(u32 bus, u8 chip, u8 addr, u8 val, u8 mask);
+
#endif
diff --git a/src/mainboard/google/corsola/panel_anx7625.c b/src/mainboard/google/corsola/panel_anx7625.c
new file mode 100644
index 0000000000..7b50e476ec
--- /dev/null
+++ b/src/mainboard/google/corsola/panel_anx7625.c
@@ -0,0 +1,61 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <console/console.h>
+#include <delay.h>
+#include <drivers/analogix/anx7625/anx7625.h>
+#include <edid.h>
+#include <gpio.h>
+#include <soc/i2c.h>
+
+#include "display.h"
+#include "gpio.h"
+
+static void bridge_anx7625_power_on(void)
+{
+ /* Turn on bridge */
+ gpio_output(GPIO_EDPBRDG_RST_L, 0);
+ gpio_output(GPIO_EN_PP1000_EDPBRDG, 1);
+ gpio_output(GPIO_EN_PP1800_EDPBRDG, 1);
+ gpio_output(GPIO_EN_PP3300_EDPBRDG, 1);
+ mdelay(14);
+ gpio_output(GPIO_EDPBRDG_PWREN, 1);
+ mdelay(80);
+ gpio_output(GPIO_EDPBRDG_RST_L, 1);
+}
+
+static int bridge_anx7625_get_edid(u8 i2c_bus, struct edid *edid)
+{
+ if (anx7625_init(i2c_bus) < 0) {
+ printk(BIOS_ERR, "%s: Can't init ANX7625 bridge\n", __func__);
+ return -1;
+ }
+ if (anx7625_dp_get_edid(i2c_bus, edid) < 0) {
+ printk(BIOS_ERR, "%s: Can't get panel's edid\n", __func__);
+ return -1;
+ }
+ return 0;
+}
+
+static int bridge_anx7625_post_power_on(u8 i2c_bus, struct edid *edid)
+{
+ return anx7625_dp_start(i2c_bus, edid);
+}
+
+static struct panel_serializable_data anx7625_data;
+
+static struct panel_description anx7625_bridge = {
+ .s = &anx7625_data,
+ .post_power_on = bridge_anx7625_post_power_on,
+ .orientation = LB_FB_ORIENTATION_NORMAL,
+};
+
+struct panel_description *get_anx7625_description(void)
+{
+ mtk_i2c_bus_init(BRIDGE_I2C, I2C_SPEED_FAST);
+ bridge_anx7625_power_on();
+ if (bridge_anx7625_get_edid(BRIDGE_I2C, &anx7625_bridge.s->edid) < 0) {
+ printk(BIOS_ERR, "Can't get panel's edid\n");
+ return NULL;
+ }
+ return &anx7625_bridge;
+}
diff --git a/src/mainboard/google/corsola/panel_ps8640.c b/src/mainboard/google/corsola/panel_ps8640.c
new file mode 100644
index 0000000000..bb1e4eb7ce
--- /dev/null
+++ b/src/mainboard/google/corsola/panel_ps8640.c
@@ -0,0 +1,79 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <console/console.h>
+#include <delay.h>
+#include <drivers/parade/ps8640/ps8640.h>
+#include <edid.h>
+#include <gpio.h>
+#include <soc/i2c.h>
+#include <soc/regulator.h>
+
+#include "display.h"
+#include "gpio.h"
+
+static void bridge_ps8640_power_on(void)
+{
+ /*
+ * PS8640 power-on sequence is described in chapter 14, PS8640_DS_V1.4_20200210.docx
+ * - set VDD12 to be 1.2V
+ * - delay 100us
+ * - set VDD33 to be 3.3V
+ * - pull hign PD#
+ * - pull down RST#
+ * - delay 2ms
+ * - pull high RST#
+ * - delay more than 50ms (55ms for margin)
+ * - pull down RST#
+ * - delay more than 50ms (55ms for margin)
+ * - pull high RST#
+ */
+
+ /* Set VRF12 to 1.2V and VCN33 to 3.3V */
+ mainboard_set_regulator_voltage(MTK_REGULATOR_VRF12, 1200000);
+ udelay(100);
+ mainboard_set_regulator_voltage(MTK_REGULATOR_VCN33, 3300000);
+ udelay(200);
+
+ /* Turn on bridge */
+ gpio_output(GPIO_EDPBRDG_PWREN, 1);
+ gpio_output(GPIO_EDPBRDG_RST_L, 0);
+ mdelay(2);
+ gpio_output(GPIO_EDPBRDG_RST_L, 1);
+ mdelay(55);
+ gpio_output(GPIO_EDPBRDG_RST_L, 0);
+ mdelay(55);
+ gpio_output(GPIO_EDPBRDG_RST_L, 1);
+}
+
+static int bridge_ps8640_get_edid(u8 i2c_bus, struct edid *edid)
+{
+ const u8 chip = 0x8;
+
+ if (ps8640_init(i2c_bus, chip) < 0) {
+ printk(BIOS_ERR, "%s: Can't init PS8640 bridge\n", __func__);
+ return -1;
+ }
+ if (ps8640_get_edid(i2c_bus, chip, edid) < 0) {
+ printk(BIOS_ERR, "%s: Can't get panel's edid\n", __func__);
+ return -1;
+ }
+ return 0;
+}
+
+static struct panel_serializable_data ps8640_data;
+
+static struct panel_description ps8640_bridge = {
+ .s = &ps8640_data,
+ .orientation = LB_FB_ORIENTATION_NORMAL,
+};
+
+struct panel_description *get_ps8640_description(void)
+{
+ mtk_i2c_bus_init(BRIDGE_I2C, I2C_SPEED_FAST);
+ bridge_ps8640_power_on();
+ if (bridge_ps8640_get_edid(BRIDGE_I2C, &ps8640_bridge.s->edid) < 0) {
+ printk(BIOS_ERR, "Can't get panel's edid\n");
+ return NULL;
+ }
+ return &ps8640_bridge;
+}
diff --git a/src/mainboard/google/corsola/panel_starmie.c b/src/mainboard/google/corsola/panel_starmie.c
new file mode 100644
index 0000000000..ffb7b65cd2
--- /dev/null
+++ b/src/mainboard/google/corsola/panel_starmie.c
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <delay.h>
+#include <gpio.h>
+#include <soc/regulator.h>
+
+#include "display.h"
+#include "gpio.h"
+
+static void mipi_panel_power_on(void)
+{
+ tps65132s_program_eeprom();
+ mainboard_set_regulator_voltage(MTK_REGULATOR_VIO18, 1800000);
+ mdelay(1);
+ gpio_output(GPIO_EN_PP3300_DISP_X, 1);
+ gpio_output(GPIO_EN_PP3300_SDBRDG_X, 1);
+ mdelay(1);
+ /* DISP_RST_1V8_L */
+ gpio_output(GPIO_EDPBRDG_RST_L, 1);
+ mdelay(1);
+ gpio_output(GPIO_EDPBRDG_RST_L, 0);
+ udelay(20);
+ gpio_output(GPIO_EDPBRDG_RST_L, 1);
+}
+
+static struct panel_description starmie_panels[] = {
+ [8] = {
+ .power_on = mipi_panel_power_on,
+ .name = "STA_ILI9882T",
+ .orientation = LB_FB_ORIENTATION_LEFT_UP,
+ },
+ [10] = {
+ .power_on = mipi_panel_power_on,
+ .name = "STA_HIMAX83102_J02",
+ .orientation = LB_FB_ORIENTATION_LEFT_UP,
+ },
+};
+
+struct panel_description *get_panel_description(void)
+{
+ uint32_t id = panel_id() & 0xF;
+ if (id >= ARRAY_SIZE(starmie_panels))
+ return NULL;
+
+ return get_panel_from_cbfs(&starmie_panels[id]);
+}