summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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]);
+}