diff options
author | Vinod Polimera <vpolimer@codeaurora.org> | 2021-03-16 18:37:40 +0530 |
---|---|---|
committer | Julius Werner <jwerner@chromium.org> | 2021-08-03 21:22:26 +0000 |
commit | e8cd480046b2f8660c52d5503d5cc0cd4a5cd002 (patch) | |
tree | a736c1e6fe9c69b11a90c2be2fc53c737e82c05d | |
parent | 8ca68cf2ae8d172c237cf05d37f2b5c5a2775f9f (diff) |
sc7180: Add display support for mipi panels
- configure TROGDOR_HAS_MIPI_PANEL to "n" by default, it can be updated for mipi panels.
- add simple rm69299 panel as an example to append new mipi panels.
- use existing edid struct to update mipi panel parameters.
- add dsi command tx interface for mipi panel on commands.
Change-Id: Id698265a4e2399ad1c26e026e9a5f8ecd305467f
Signed-off-by: Vinod Polimera <vpolimer@codeaurora.org>
Signed-off-by: Julius Werner <jwerner@chromium.org>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/52662
Reviewed-by: Shelley Chen <shchen@google.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
-rw-r--r-- | src/mainboard/google/trogdor/Kconfig | 4 | ||||
-rw-r--r-- | src/mainboard/google/trogdor/Makefile.inc | 1 | ||||
-rw-r--r-- | src/mainboard/google/trogdor/mainboard.c | 38 | ||||
-rw-r--r-- | src/mainboard/google/trogdor/panel_driver.c | 45 | ||||
-rw-r--r-- | src/soc/qualcomm/sc7180/display/dsi.c | 152 | ||||
-rw-r--r-- | src/soc/qualcomm/sc7180/include/soc/display/mipi_dsi.h | 11 | ||||
-rw-r--r-- | src/soc/qualcomm/sc7180/include/soc/display/panel.h | 17 |
7 files changed, 245 insertions, 23 deletions
diff --git a/src/mainboard/google/trogdor/Kconfig b/src/mainboard/google/trogdor/Kconfig index 1ef8398cc6..ad86a5344a 100644 --- a/src/mainboard/google/trogdor/Kconfig +++ b/src/mainboard/google/trogdor/Kconfig @@ -12,6 +12,10 @@ config TROGDOR_HAS_BRIDGE_BACKLIGHT default y if BOARD_GOOGLE_HOMESTAR default n +config TROGDOR_HAS_MIPI_PANEL + bool + default n + config TROGDOR_HAS_FINGERPRINT bool default y if BOARD_GOOGLE_COACHZ diff --git a/src/mainboard/google/trogdor/Makefile.inc b/src/mainboard/google/trogdor/Makefile.inc index 9a71ea5197..f42e1476c7 100644 --- a/src/mainboard/google/trogdor/Makefile.inc +++ b/src/mainboard/google/trogdor/Makefile.inc @@ -15,6 +15,7 @@ romstage-y += boardid.c romstage-y += chromeos.c ramstage-y += mainboard.c +ramstage-y += panel_driver.c ifneq ($(CONFIG_BOARD_GOOGLE_BUBS),y) ramstage-y += reset.c endif diff --git a/src/mainboard/google/trogdor/mainboard.c b/src/mainboard/google/trogdor/mainboard.c index 864bd6daa6..96751fede2 100644 --- a/src/mainboard/google/trogdor/mainboard.c +++ b/src/mainboard/google/trogdor/mainboard.c @@ -12,6 +12,7 @@ #include <soc/qupv3_config.h> #include <soc/qupv3_i2c.h> #include <soc/usb.h> +#include <types.h> #include "board.h" @@ -74,39 +75,52 @@ static void configure_display(void) gpio_output(GPIO_EN_PP3300_DX_EDP, 1); } -static void display_init(struct edid *edid) +static enum cb_err display_init(struct edid *edid, const struct panel_data *pinfo) { uint32_t dsi_bpp = 24; - uint32_t lanes = 4; + uint32_t lanes = pinfo ? pinfo->lanes : 4; if (mdss_dsi_config(edid, lanes, dsi_bpp)) - return; + return CB_ERR; + if (CONFIG(TROGDOR_HAS_MIPI_PANEL)) { + if (mdss_dsi_panel_initialize(pinfo)) + return CB_ERR; + } else { + sn65dsi86_bridge_configure(BRIDGE_BUS, BRIDGE_CHIP, edid, lanes, dsi_bpp); + } - sn65dsi86_bridge_configure(BRIDGE_BUS, BRIDGE_CHIP, edid, lanes, dsi_bpp); if (CONFIG(TROGDOR_HAS_BRIDGE_BACKLIGHT)) sn65dsi86_backlight_enable(BRIDGE_BUS, BRIDGE_CHIP); mdp_dsi_video_config(edid); mdss_dsi_video_mode_config(edid, dsi_bpp); mdp_dsi_video_on(); + + return CB_SUCCESS; } static void display_startup(void) { static struct edid ed; enum dp_pll_clk_src ref_clk = SN65_SEL_19MHZ; + const struct panel_data *pinfo = NULL; - i2c_init(QUPV3_0_SE2, I2C_SPEED_FAST); /* EDP Bridge I2C */ if (display_init_required()) { - configure_display(); - mdelay(250); /* Delay for the panel to be up */ - sn65dsi86_bridge_init(BRIDGE_BUS, BRIDGE_CHIP, ref_clk); - if (sn65dsi86_bridge_read_edid(BRIDGE_BUS, BRIDGE_CHIP, &ed) < 0) - return; + if (CONFIG(TROGDOR_HAS_MIPI_PANEL)) { + pinfo = get_panel_config(&ed); + } else { + i2c_init(QUPV3_0_SE2, I2C_SPEED_FAST); /* EDP Bridge I2C */ + configure_display(); + mdelay(250); /* Delay for the panel to be up */ + sn65dsi86_bridge_init(BRIDGE_BUS, BRIDGE_CHIP, ref_clk); + if (sn65dsi86_bridge_read_edid(BRIDGE_BUS, BRIDGE_CHIP, &ed) < 0) + return; + } printk(BIOS_INFO, "display init!\n"); - display_init(&ed); - fb_new_framebuffer_info_from_edid(&ed, (uintptr_t)0); + if (display_init(&ed, pinfo) == CB_SUCCESS) + fb_new_framebuffer_info_from_edid(&ed, (uintptr_t)0); + } else printk(BIOS_INFO, "Skipping display init.\n"); } diff --git a/src/mainboard/google/trogdor/panel_driver.c b/src/mainboard/google/trogdor/panel_driver.c new file mode 100644 index 0000000000..5da02098ec --- /dev/null +++ b/src/mainboard/google/trogdor/panel_driver.c @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <edid.h> +#include <string.h> +#include <types.h> +#include <soc/display/mipi_dsi.h> +#include <soc/display/panel.h> + +struct mipi_dsi_cmd visionox_init_cmds[] = { + {{0xFE, 0x00, 0x15, 0x80}, 0x4, 0}, + {{0xc2, 0x08, 0x15, 0x80}, 0x4, 0}, + {{0x35, 0x00, 0x15, 0x80}, 0x4, 0}, + {{0x51, 0xff, 0x15, 0x80}, 0x4, 0}, + {{0x11, 0x00, 0x05, 0x80}, 0x4, 150000}, + {{0x29, 0x00, 0x05, 0x80}, 0x4, 50000}, +}; + +static const struct edid visionox_edid = { + .ascii_string = "RM69299", + .manufacturer_name = "RM", + .panel_bits_per_color = 8, + .panel_bits_per_pixel = 24, + .mode = { + .pixel_clock = 158695, + .lvds_dual_channel = 0, + .refresh = 60, + .ha = 1080, .hbl = 64, .hso = 26, .hspw = 2, + .va = 2248, .vbl = 64, .vso = 56, .vspw = 4, + .phsync = '-', .pvsync = '-', + .x_mm = 74, .y_mm = 131, + }, +}; + +const struct panel_data panel_info = { + .lanes = 4, + .init_cmd = visionox_init_cmds, + .init_cmd_count = 6, +}; + +const struct panel_data *get_panel_config(struct edid *edid) +{ + memcpy(edid, &visionox_edid, sizeof(struct edid)); + edid_set_framebuffer_bits_per_pixel(edid, 32, 0); + return &panel_info; +} diff --git a/src/soc/qualcomm/sc7180/display/dsi.c b/src/soc/qualcomm/sc7180/display/dsi.c index 016531bda3..268200809a 100644 --- a/src/soc/qualcomm/sc7180/display/dsi.c +++ b/src/soc/qualcomm/sc7180/display/dsi.c @@ -2,10 +2,15 @@ #include <device/mmio.h> #include <console/console.h> +#include <assert.h> #include <edid.h> +#include <delay.h> +#include <symbols.h> #include <types.h> -#include <soc/display/mdssreg.h> +#include <string.h> #include <soc/display/mipi_dsi.h> +#include <soc/display/panel.h> +#include <soc/display/mdssreg.h> #include <soc/display/dsi_phy.h> #define DSI_DMA_STREAM1 0x0 @@ -17,6 +22,7 @@ #define DSI_WC1 0x0 #define DSI_EOF_BLLP_PWR 0x9 #define DSI_DMA_TRIGGER_SEL 0x4 +#define TRAFFIC_MODE 0x1 #define DSI_EN 0x1 #define DSI_CLKLN_EN 0x1 @@ -24,6 +30,11 @@ #define HS_TX_TO 0xEA60 #define TIMER_RESOLUTION 0x4 +#define DSI_PAYLOAD_BYTE_BOUND 8 +#define DSI_PAYLOAD_SIZE_ALIGN 4 +#define DSI_CMD_DMA_TPG_EN BIT(1) +#define DSI_TPG_DMA_FIFO_MODE BIT(2) +#define DSI_CMD_DMA_PATTERN_SEL (BIT(16) | BIT(17)) static void mdss_dsi_host_init(int num_of_lanes) { @@ -55,11 +66,13 @@ static void mdss_dsi_host_init(int num_of_lanes) */ ctrl_mode |= BIT(1); + mdss_dsi_clock_config(); write32(&dsi0->trig_ctrl, DSI_DMA_STREAM1 << 8 | DSI_DMA_TRIGGER_SEL); write32(&dsi0->ctrl, dlnx_en << 4 | ctrl_mode); write32(&dsi0->cmd_mode_dma_ctrl, - DSI_EMBED_MODE1 << 28 | DSI_POWER_MODE2 << 26 | - DSI_PACK_TYPE1 << 24 | DSI_VC1 << 22 | DSI_DT1 << 16 | DSI_WC1); + DSI_EMBED_MODE1 << 28 | DSI_POWER_MODE2 << 26 | + DSI_PACK_TYPE1 << 24 | DSI_VC1 << 22 | DSI_DT1 << 16 | DSI_WC1); + write32(&dsi0->eot_packet_ctrl, 0x1); } static void mdss_dsi_reset(void) @@ -106,8 +119,6 @@ void mdss_dsi_video_mode_config(struct edid *edid, uint32_t bpp) vfp = edid->mode.vso; vbp = edid->mode.vbl - edid->mode.vso; - mdss_dsi_clock_config(); - write32(&dsi0->video_mode_active_h, ((edid->mode.ha + hbp) << 16) | hbp); @@ -121,12 +132,12 @@ void mdss_dsi_video_mode_config(struct edid *edid, uint32_t bpp) (edid->mode.ha + hfp + hbp - 1)); - write32(&dsi0->video_mode_active_hsync, (edid->mode.hspw << 16) | 0); + write32(&dsi0->video_mode_active_hsync, (edid->mode.hspw << 16)); write32(&dsi0->video_mode_active_vsync, 0x0); - write32(&dsi0->video_mode_active_vsync_vpos, edid->mode.vspw << 16 | 0); + write32(&dsi0->video_mode_active_vsync_vpos, edid->mode.vspw << 16); write32(&dsi0->video_mode_ctrl, - DSI_EOF_BLLP_PWR << 12 | dst_format << 4); + DSI_EOF_BLLP_PWR << 12 | dst_format << 4 | TRAFFIC_MODE << 8); write32(&dsi0->hs_timer_ctrl, HS_TX_TO | TIMER_RESOLUTION << 16); @@ -153,9 +164,132 @@ void mdss_dsi_clock_config(void) setbits32(&dsi0->clk_ctrl, DSI_AHBM_SCLK_ON | DSI_FORCE_ON_DYN_AHBM_HCLK); /* Clock for MDP/DSI, for DMA out from MDP */ - setbits32(&dsi0->clk_ctrl, DSI_FORCE_ON_DYN_AHBM_HCLK); + setbits32(&dsi0->clk_ctrl, DSI_PCLK_ON); /* Clock for rest of DSI */ setbits32(&dsi0->clk_ctrl, DSI_AHBS_HCLK_ON | DSI_DSICLK_ON | DSI_BYTECLK_ON | DSI_ESCCLK_ON); } + +static void mdss_dsi_set_intr(void) +{ + write32(&dsi0->int_ctrl, 0x0); + + /* Enable all HW interrupts. */ + setbits32(&dsi0->int_ctrl, DSI_CMD_MODE_DMA_DONE_MASK | DSI_CMD_MODE_MDP_DONE_MASK | + DSI_VIDEO_MODE_DONE_MASK | DSI_ERROR_MASK | DSI_BTA_DONE_MASK); +} + +static int mdss_dsi_cmd_dma_trigger_for_panel(void) +{ + uint32_t read_value; + uint32_t count = 0; + int status = 0; + + mdss_dsi_set_intr(); + write32(&dsi0->cmd_mode_dma_sw_trigger, 0x1); + dsb(); + + read_value = read32(&dsi0->int_ctrl) & 0x1; + + while (read_value != 0x1) { + read_value = read32(&dsi0->int_ctrl) & 0x1; + count++; + if (count > 0xffff) { + status = -1; + printk(BIOS_ERR, + "Panel CMD: count :%d command mode dma test failed\n", count); + printk(BIOS_ERR, + "Panel CMD: read value = %x, addr=%p\n", + read_value, (&dsi0->int_ctrl)); + return status; + } + } + + write32(&dsi0->int_ctrl, (read32(&dsi0->int_ctrl) | 0x01000001)); + return status; +} + +static int mdss_dsi_cmds_tx(struct mipi_dsi_cmd *cmds, int count) +{ + struct mipi_dsi_cmd *cm; + uint8_t *pload = _dma_coherent; + uint32_t size; + int data = 0; + int ret = 0; + uint32_t *bp = NULL; + + cm = cmds; + + for (int i = 0; i < count; i++) { + /* The payload size has to be a multiple of 4 */ + size = ALIGN_UP(cm->size, DSI_PAYLOAD_SIZE_ALIGN); + assert(size < DSI_PAYLOAD_BYTE_BOUND); + memcpy(pload, (cm[i].payload), size); + + bp = (uint32_t *)pload; + + /* Enable custom pattern stored in TPG DMA FIFO */ + data = DSI_CMD_DMA_PATTERN_SEL; + + /* select CMD_DMA_FIFO_MODE to 1 */ + data |= DSI_TPG_DMA_FIFO_MODE; + data |= DSI_CMD_DMA_TPG_EN; + + write32(&dsi0->test_pattern_gen_ctrl, data); + for (int j = 0; j < size; j += 4) { + write32(&dsi0->test_pattern_gen_cmd_dma_init_val, *bp); + bp++; + } + + if ((size % 8) != 0) + write32(&dsi0->test_pattern_gen_cmd_dma_init_val, 0x0); + + write32(&dsi0->dma_cmd_length, size); + write32(&dsi0->cmd_mode_dma_sw_trigger, 0x1); + ret += mdss_dsi_cmd_dma_trigger_for_panel(); + + /* Reset the DMA TPG FIFO */ + write32(&dsi0->tpg_dma_fifo_reset, 0x1); + write32(&dsi0->tpg_dma_fifo_reset, 0x0); + + /* Disable CMD_DMA_TPG */ + write32(&dsi0->test_pattern_gen_ctrl, 0x0); + if (cm[i].delay_us) + udelay(cm[i].delay_us); + else + udelay(80); + } + + return ret; +} + +static void mdss_dsi_clear_intr(void) +{ + write32(&dsi0->int_ctrl, 0x0); + + /* Clear all the hardware interrupts */ + setbits32(&dsi0->int_ctrl, DSI_CMD_MODE_DMA_DONE_AK | DSI_CMD_MODE_MDP_DONE_AK | + DSI_VIDEO_MODE_DONE_AK | DSI_BTA_DONE_AK | DSI_ERROR_AK); + write32(&dsi0->err_int_mask0, 0x13FF3BFF); +} + +int mdss_dsi_panel_initialize(const struct panel_data *pinfo) +{ + int status = 0; + uint32_t ctrl_mode = 0; + struct mipi_dsi_cmd *cmds; + + assert((pinfo != NULL) && (pinfo->init_cmd != NULL)); + cmds = pinfo->init_cmd; + ctrl_mode = read32(&dsi0->ctrl); + + /* Enable command mode before sending the commands */ + write32(&dsi0->ctrl, ctrl_mode | 0x04); + + status = mdss_dsi_cmds_tx(cmds, pinfo->init_cmd_count); + write32(&dsi0->ctrl, ctrl_mode); + mdss_dsi_clear_intr(); + + return status; +} diff --git a/src/soc/qualcomm/sc7180/include/soc/display/mipi_dsi.h b/src/soc/qualcomm/sc7180/include/soc/display/mipi_dsi.h index 47fd3084c6..3b3dc513ab 100644 --- a/src/soc/qualcomm/sc7180/include/soc/display/mipi_dsi.h +++ b/src/soc/qualcomm/sc7180/include/soc/display/mipi_dsi.h @@ -3,6 +3,7 @@ #ifndef _SOC_DISPLAY_MIPI_DSI_H_ #define _SOC_DISPLAY_MIPI_DSI_H_ +#include <soc/display/panel.h> /********************************************************** DSI register configuration options **********************************************************/ @@ -14,6 +15,12 @@ #define DSI_VIDEO_DST_FORMAT_RGB666_LOOSE 2 #define DSI_VIDEO_DST_FORMAT_RGB888 3 +struct mipi_dsi_cmd { + char payload[4]; + uint32_t size; + int delay_us; +}; + enum { DSI_VIDEO_MODE, DSI_CMD_MODE, @@ -21,7 +28,7 @@ enum { enum cb_err mdss_dsi_config(struct edid *edid, uint32_t num_of_lanes, uint32_t bpp); void mdss_dsi_clock_config(void); -void mdss_dsi_video_mode_config(struct edid *edid, - uint32_t bpp); +void mdss_dsi_video_mode_config(struct edid *edid, uint32_t bpp); +int mdss_dsi_panel_initialize(const struct panel_data *pinfo); #endif diff --git a/src/soc/qualcomm/sc7180/include/soc/display/panel.h b/src/soc/qualcomm/sc7180/include/soc/display/panel.h new file mode 100644 index 0000000000..04a7a6ab06 --- /dev/null +++ b/src/soc/qualcomm/sc7180/include/soc/display/panel.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _PANEL_H_ +#define _PANEL_H_ + +#include <types.h> + +struct panel_data { + uint8_t lanes; + struct mipi_dsi_cmd *init_cmd; + uint32_t init_cmd_count; +}; + +void panel_power_on(void); +const struct panel_data *get_panel_config(struct edid *edid); + +#endif /*_PANEL_H_ */ |