diff options
-rw-r--r-- | src/mainboard/google/corsola/Makefile.inc | 4 | ||||
-rw-r--r-- | src/mainboard/google/corsola/display.c | 215 | ||||
-rw-r--r-- | src/mainboard/google/corsola/display.h | 29 | ||||
-rw-r--r-- | src/mainboard/google/corsola/panel_anx7625.c | 61 | ||||
-rw-r--r-- | src/mainboard/google/corsola/panel_ps8640.c | 79 | ||||
-rw-r--r-- | src/mainboard/google/corsola/panel_starmie.c | 46 |
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]); +} |