Ravi kumar has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/39614 )
Change subject: sc7180: Add display dsi interface programming [Patch 2 of 3] ......................................................................
sc7180: Add display dsi interface programming [Patch 2 of 3]
This change adds support for sc7180 dsi interface host programming and target specific hardware resource (ex: dsi-edp bridge/backlight) configuration.
Change-Id: Ie64354ce8bc2a64b891fb9478fbca38d6ec4c321 Signed-off-by: Vinod Polimera vpolimer@codeaurora.org --- A src/soc/qualcomm/sc7180/display/dsi.c A src/soc/qualcomm/sc7180/display/dsi_panel_display.c A src/soc/qualcomm/sc7180/display/target_sc7180.c A src/soc/qualcomm/sc7180/include/soc/display/mipi_dsi.h A src/soc/qualcomm/sc7180/include/soc/display/panel_display.h A src/soc/qualcomm/sc7180/include/soc/display/target_sc7180.h 6 files changed, 1,710 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/14/39614/1
diff --git a/src/soc/qualcomm/sc7180/display/dsi.c b/src/soc/qualcomm/sc7180/display/dsi.c new file mode 100644 index 0000000..6967ff5 --- /dev/null +++ b/src/soc/qualcomm/sc7180/display/dsi.c @@ -0,0 +1,890 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2020 Qualcomm Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <arch/mmio.h> +#include <endian.h> +#include <console/console.h> +#include <delay.h> +#include <string.h> +#include <stdlib.h> +#include <soc/mdss_6_2_0.h> +#include <soc/display/msm_panel.h> +#include <soc/display/mipi_dsi.h> +#include <soc/display/dsi_phy.h> + +mdss_dsi_phy_ftable phy_intf; + +void mdss_dsi_panel_shutdown(struct msm_panel_info *pinfo); + +int mdss_dsi_host_init(struct mipi_panel_info *mipi, + uint32_t dual_dsi, + uint32_t broadcast); + +int mdss_dsi_panel_initialize(struct mipi_panel_info *mipi, + uint32_t broadcast); + +int mdss_dsi_reset(struct mipi_panel_info *mipi, uint32_t dual_dsi); + +int mdss_dsi_clear_intr(struct mipi_panel_info *mipi, uint32_t dual_dsi); + +int mdss_dsi_set_intr(uint32_t ctl_base); + +void mdss_dsi_clock_config(uint32_t ctl_base); + + +static int mdss_dsi_cmd_dma_trigger_for_panel(char dual_dsi, + uint32_t ctl_base, + uint32_t sctl_base) +{ + uint32_t ReadValue; + uint32_t count = 0; + int status = 0; + uint32_t base = dual_dsi ? sctl_base : ctl_base; + + mdss_dsi_set_intr(ctl_base); + writel(0x1, ctl_base + CMD_MODE_DMA_SW_TRIGGER); + dsb(); + + if (dual_dsi) { + mdss_dsi_set_intr(sctl_base); + writel(0x1, sctl_base + CMD_MODE_DMA_SW_TRIGGER); + dsb(); + } + + ReadValue = readl(base + INT_CTRL) & 0x00000001; + + while (ReadValue != 0x00000001) { + ReadValue = readl(base + INT_CTRL) & 0x00000001; + count++; + if (count > 0xffff) { + status = FAIL; + printk(BIOS_ERR, + "Panel CMD: count :%d command mode dma test failed\n",count); + printk(BIOS_ERR, + "Panel CMD: read value = %x, addr=%x\n", + ReadValue, (base + INT_CTRL)); + return status; + } + } + + writel((readl(base + INT_CTRL) | 0x01000001), base + INT_CTRL); + return status; +} + +static int mdss_dsi_wait4_video_done(uint32_t ctl_base) +{ + unsigned long read; + unsigned long count = 0; + int status = 0; + + /* If video mode is not enabled, return here */ + if ((readl(ctl_base + CTRL) & BIT(1)) == 0) + return 0; + + read = readl(ctl_base + INT_CTRL); + + /* Enable VIDEO MODE DONE MASK and clear the interrupt */ + read = read | DSI_VIDEO_MODE_DONE_MASK | DSI_VIDEO_MODE_DONE_AK; + writel(read, ctl_base + INT_CTRL); + dsb(); + + do { + read = readl(ctl_base + INT_CTRL) & DSI_VIDEO_MODE_DONE_STAT; + count++; + + if (count > 0xffff) { + status = FAIL; + printk(BIOS_ERR,"Panel CMD: Did not receive video mode done""interrupt\n"); + return status; + } + + } while (!read); + + writel((readl(ctl_base + INT_CTRL) | 0x01000001), ctl_base + INT_CTRL); + printk(BIOS_INFO,"Panel wait_4_video_done: Received video mode done ack\n"); + + /* Skip BLLP 4ms */ + mdelay(4); + + return status; +} + +int mdss_dsi_cmds_tx(struct mipi_panel_info *mipi, + struct mipi_dsi_cmd *cmds, + int count, + char dual_dsi) +{ + + struct mipi_dsi_cmd *cm; + uint8_t pload[256]; + size_t off; + uint32_t size; + uint32_t len; + uint32_t ctl_base, sctl_base; + bool use_tpg = true; + int data = 0; + int ret = 0; + int i = 0; + int j = 0; + uint32_t *bp = NULL; + + /* if dest controller is not specified, default to DSI0 */ + if (!mipi) { + ctl_base = MIPI_DSI0_BASE; + sctl_base = MIPI_DSI1_BASE; + } else { + ctl_base = mipi->ctl_base; + sctl_base = mipi->sctl_base; + } + + /* Align pload at 8 byte boundary */ + off = (size_t) pload; + off &= 0x07; + + if (off) + off = 8 - off; + + off += (size_t) pload; + cm = cmds; + + for (i = 0; i < count; i++) { + /* Wait for VIDEO_MODE_DONE */ + ret = mdss_dsi_wait4_video_done(ctl_base); + + if (ret) + goto wait4video_error; + + /* The payload size has to be a multiple of 4 */ + size = cm->size; + size &= 0x03; + + if (size) + size = 4 - size; + + size += cm->size; + memcpy((uint8_t *)off, (cm->payload), size); + + if (use_tpg == false) { + writel(off, ctl_base + DMA_CMD_OFFSET); + writel(size, ctl_base + DMA_CMD_LENGTH); + + if (dual_dsi) { + writel(off, sctl_base + DMA_CMD_OFFSET); + writel(size, sctl_base + DMA_CMD_LENGTH); + } + + dsb(); + } + else { + data = 0; + bp = (uint32_t *)off; + len = ALIGN(size, 4); + + if (len > DMA_TPG_FIFO_LEN) { + cm++; + continue; + } + + data = BIT(16) | BIT(17); /* select CMD_DMA_PATTERN_SEL to 3 */ + data |= BIT(2); /* select CMD_DMA_FIFO_MODE to 1 */ + data |= BIT(1); + + writel(data, ctl_base + TEST_PATTERN_GEN_CTRL); + + for (j = 0; j < len; j += 4) { + writel(*bp, ctl_base + TEST_PATTERN_GEN_CMD_DMA_INIT_VAL); + wmb(); /* Ensure write happens before next command */ + bp++; + } + + if ((len % 8) != 0) + writel(0x0, ctl_base + TEST_PATTERN_GEN_CMD_DMA_INIT_VAL); + + writel(len, ctl_base + DMA_CMD_LENGTH); + wmb(); /* make sure DMA length is programmed */ + + writel(0x01, ctl_base + CMD_MODE_DMA_SW_TRIGGER); + wmb(); /* make sure DMA trigger happens */ + + + } + + ret += mdss_dsi_cmd_dma_trigger_for_panel(dual_dsi, ctl_base, sctl_base); + + /* Reset the DMA TPG FIFO */ + writel(0x1, ctl_base + TPG_DMA_FIFO_RESET); + wmb(); /* make sure FIFO reset happens */ + + writel(0x0, ctl_base + TPG_DMA_FIFO_RESET); + wmb(); /* make sure FIFO reset happens */ + + /* Disable CMD_DMA_TPG */ + writel(0x0, ctl_base + TEST_PATTERN_GEN_CTRL); + + if (cm->wait) + mdelay(cm->wait); + else + udelay(80); + + cm++; + } + +wait4video_error: + return ret; +} + +int mdss_dsi_cmds_rx(struct mipi_panel_info *mipi, + uint32_t **rp, + int rp_len, + int rdbk_len) +{ + uint32_t *lp, data; + uint32_t *dp; + int i, off; + int rlen, res; + uint32_t ctl_base; + + /* if dest controller is not specified, default to DSI0 */ + if (!mipi) + ctl_base = MIPI_DSI0_BASE; + else + ctl_base = mipi->ctl_base; + + if (rdbk_len > rp_len) + return 0; + + if (rdbk_len <= 2) + rlen = 4; /* short read */ + else + rlen = MIPI_DSI_MRPS + 6; /* 4 bytes header + 2bytes crc */ + + if (rlen > MIPI_DSI_REG_LEN) + return 0; + + res = rlen & 0x03; + + rlen += res; /* 4 byte align */ + lp = *rp; + + rlen += 3; + rlen >>= 2; + + if (rlen > 4) + rlen = 4; /* 4 x 32 bits registers only */ + + off = RDBK_DATA0; + off += ((rlen - 1) * 4); + + for (i = 0; i < rlen; i++) { + data = readl(ctl_base + off); + *lp = ntohl(data); /* to network byte order */ + lp++; + + off -= 4; + } + + if (rdbk_len > 2) { + /* First 4 bytes + paded bytes will be header next + * len bytes would be payload + */ + for (i = 0; i < rdbk_len; i++) { + dp = *rp; + dp[i] = dp[(res + i) >> 2]; + } + } + return rdbk_len; +} + +static void mdss_dsi_force_clk_lane_hs(struct mipi_panel_info *mipi, + uint32_t dual_dsi) +{ + uint32_t tmp; + + if (dual_dsi) { + tmp = readl(mipi->sctl_base + LANE_CTL); + tmp |= BIT(28); + writel(tmp, mipi->sctl_base + LANE_CTL); + } + + tmp = readl(mipi->ctl_base + LANE_CTL); + tmp |= BIT(28); + writel(tmp, mipi->ctl_base + LANE_CTL); +} + +int mdss_dsi_host_init(struct mipi_panel_info *mipi, uint32_t + dual_dsi, uint32_t broadcast) +{ + uint8_t DMA_STREAM1 = 0; // for mdp display processor path + uint8_t EMBED_MODE1 = 1; // from frame buffer + uint8_t POWER_MODE2 = 1; // from frame buffer + uint8_t PACK_TYPE1 = 0; // long packet + uint8_t VC1 = 0; + uint8_t DT1 = 0; // non embedded mode + uint8_t WC1 = 0; // for non embedded mode only + uint8_t DLNx_EN; + uint32_t timing_ctl = 0; + uint32_t ctrl_mode = BIT(8)|BIT(0); //Enable DSI and CLKlane. + uint32_t tmp = 0; + + switch (mipi->num_of_lanes) { + default: + case 1: + DLNx_EN = 1; // 1 lane + break; + + case 2: + DLNx_EN = 3; // 2 lane + break; + + case 3: + DLNx_EN = 7; // 3 lane + break; + + case 4: + DLNx_EN = 0x0F; /* 4 lanes */ + break; + } + + timing_ctl = ((mipi->t_clk_post << 8) | mipi->t_clk_pre); + + if (mipi->cmds_post_tg) { + /* + * Need to send pixel data before sending the ON commands + * so need to configure controller to VIDEO MODE. + */ + ctrl_mode |= BIT(1); + } + else + { + //Default is command mode to send cmds. + ctrl_mode |= BIT(2); + } + + if (dual_dsi) { + writel(0x0001, mipi->sctl_base + SOFT_RESET); + writel(0x0000, mipi->sctl_base + SOFT_RESET); + + /* Turn on all DSI Clks */ + writel((0 << 16) | 0x3f, mipi->sctl_base + CLK_CTRL); + writel(DMA_STREAM1 << 8 | 0x04, mipi->sctl_base + TRIG_CTRL); + + writel(0 << 30 | DLNx_EN << 4 | ctrl_mode, mipi->sctl_base + CTRL); + + writel(broadcast << 31 | EMBED_MODE1 << 28 | POWER_MODE2 << 26 + | PACK_TYPE1 << 24 | VC1 << 22 | DT1 << 16 | WC1, + mipi->sctl_base + COMMAND_MODE_DMA_CTRL); + + writel(timing_ctl, mipi->sctl_base + TIMING_CTL); + + if ((mipi->mode == DSI_CMD_MODE) && + (readl(mipi->sctl_base) >= DSI_HW_REV_241)) { + tmp = readl(mipi->sctl_base + COMMAND_MODE_MDP_CTRL2); + tmp |= BIT(16); /* enable burst mode */ + writel(tmp, mipi->sctl_base + COMMAND_MODE_MDP_CTRL2); + } + + writel(((mipi->rx_eot_ignore & 0x1) << 4) | + (mipi->tx_eot_append & 0x1), + mipi->sctl_base + EOT_PACKET_CTRL); + } + + /* Turn on all DSI Clks */ + writel((0 << 16) | 0x3f, mipi->ctl_base + CLK_CTRL); + writel(DMA_STREAM1 << 8 | 0x04, mipi->ctl_base + TRIG_CTRL); + + writel(0 << 30 | DLNx_EN << 4 | ctrl_mode, mipi->ctl_base + CTRL); + writel(broadcast << 31 | EMBED_MODE1 << 28 | POWER_MODE2 << 26 + | PACK_TYPE1 << 24 | VC1 << 22 | DT1 << 16 | WC1, + mipi->ctl_base + COMMAND_MODE_DMA_CTRL); + + writel(timing_ctl, mipi->ctl_base + TIMING_CTL); + + if ((mipi->mode == DSI_CMD_MODE) && + (readl(mipi->ctl_base) >= DSI_HW_REV_241)) { + tmp = readl(mipi->ctl_base + COMMAND_MODE_MDP_CTRL2); + tmp |= BIT(16); /* enable burst mode */ + writel(tmp, mipi->ctl_base + COMMAND_MODE_MDP_CTRL2); + } + + writel(((mipi->rx_eot_ignore & 0x1) << 4) | (mipi->tx_eot_append & 0x1), + mipi->ctl_base + EOT_PACKET_CTRL); + + return 0; +} + +int mdss_dsi_clear_intr(struct mipi_panel_info *mipi, uint32_t dual_dsi) +{ + uint32_t uIntrStatusReg = readl(mipi->ctl_base + INT_CTRL); + + /* Get CMD mode DMA Done and map to generic HAL interface. */ + uIntrStatusReg = HWIO_OUT_FLD(uIntrStatusReg, INT_CTRL, DSI_CMD_MODE_DMA_DONE_AK, 1); + + /* Get CMD mode MDP Done and map to generic HAL interface. */ + uIntrStatusReg = HWIO_OUT_FLD(uIntrStatusReg, INT_CTRL, DSI_CMD_MODE_MDP_DONE_AK, 1); + + /* Get Video mode Done and map to generic HAL interface. */ + uIntrStatusReg = HWIO_OUT_FLD(uIntrStatusReg, INT_CTRL, DSI_VIDEO_MODE_DONE_AK, 1); + + /* Get the BTA done and map to generic HAL interface. clear the interrupt status bit */ + uIntrStatusReg = HWIO_OUT_FLD(uIntrStatusReg, INT_CTRL, DSI_BTA_DONE_AK, 1); + + uIntrStatusReg = HWIO_OUT_FLD(uIntrStatusReg, INT_CTRL, DSI_ERROR_AK, 1); + + writel(uIntrStatusReg, mipi->ctl_base + INT_CTRL); + writel(0x13FF3BFF, mipi->ctl_base + ERR_INT_MASK0); + + if (dual_dsi) { + writel(uIntrStatusReg, mipi->sctl_base + INT_CTRL); + writel(0x13FF3BFF, mipi->sctl_base + ERR_INT_MASK0); + } + + return 0; +} + +int mdss_dsi_set_intr(uint32_t ctl_base) +{ + uint32_t uRegVal = 0; + + /* Map CMD mode DMA Done to HW interrupts. */ + uRegVal = HWIO_OUT_FLD(uRegVal, INT_CTRL, DSI_CMD_MODE_DMA_DONE_MASK, 1); + + /* Map CMD mode MDP Done to HW interrupts. */ + uRegVal = HWIO_OUT_FLD(uRegVal, INT_CTRL, DSI_CMD_MODE_MDP_DONE_MASK, 1); + + /* Map Video mode Done to HW interrupts. */ + uRegVal = HWIO_OUT_FLD(uRegVal, INT_CTRL, DSI_VIDEO_MODE_DONE_MASK, 1); + + /* If any Error interrupt has been enabled? */ + uRegVal = HWIO_OUT_FLD(uRegVal, INT_CTRL, DSI_ERROR_MASK, 1); + + /* If need to enable DSI_BTA_DONE */ + uRegVal = HWIO_OUT_FLD(uRegVal, INT_CTRL, DSI_BTA_DONE_MASK, 1); + + writel(uRegVal, ctl_base + INT_CTRL); + + return 0; +} +int mdss_dsi_reset(struct mipi_panel_info *mipi, uint32_t dual_dsi) +{ + /* Disable DSI Controller, DSI lane states, + * DSI command-mode and DSI video-mode engines + */ + writel(0x0, mipi->ctl_base + CTRL); + + // DSI soft reset + writel(0x0001, mipi->ctl_base + SOFT_RESET); + writel(0x0000, mipi->ctl_base + SOFT_RESET); + + // set hs timer count speed + writel(0x0004EA60, mipi->ctl_base + HS_TIMER_CTRL); + + // dma fifo reset + writel(0x0001, mipi->ctl_base + TPG_DMA_FIFO_RESET); + writel(0x0000, mipi->ctl_base + TPG_DMA_FIFO_RESET); + + if (dual_dsi) { + /* Disable DSI Controller, DSI lane states, + * DSI command-mode and DSI video-mode engines + */ + writel(0x0, mipi->sctl_base + CTRL); + + // DSI soft reset + writel(0x0001, mipi->sctl_base + SOFT_RESET); + writel(0x0000, mipi->sctl_base + SOFT_RESET); + + // set hs timer count speed + writel(0x0004EA60, mipi->sctl_base + HS_TIMER_CTRL); + + // dma fifo reset + writel(0x0001, mipi->sctl_base + TPG_DMA_FIFO_RESET); + writel(0x0000, mipi->sctl_base + TPG_DMA_FIFO_RESET); + } + + return NO_ERROR; +} + +void mdss_dsi_panel_shutdown(struct msm_panel_info *pinfo) +{ + unsigned long read_val = 0; + uint32_t ctl_base = pinfo->mipi.ctl_base; + uint32_t sctl_base = pinfo->mipi.sctl_base; + + if (pinfo->mipi.panel_off_cmds) { + /* + * Once MDP TG is disabled, reset of DSI controller is + * needed before we send panel OFF commands. + */ + if (pinfo->type == MIPI_VIDEO_PANEL) { + read_val = readl(ctl_base + CTRL); + + writel((read_val & ~BIT(0)), ctl_base + CTRL); + writel(0x0001, ctl_base + SOFT_RESET); + dsb(); + + writel(0x0000, ctl_base + SOFT_RESET); + dsb(); + + /* Enable cmd mode only */ + writel(((read_val & ~BIT(1)) | BIT(2)),ctl_base + CTRL); + } + + if (pinfo->mipi.broadcast) { + if (pinfo->type == MIPI_VIDEO_PANEL) { + read_val = readl(sctl_base + CTRL); + writel((read_val & ~BIT(0)),sctl_base + CTRL); + + writel(0x0001, sctl_base + SOFT_RESET); + dsb(); + + writel(0x0000, sctl_base + SOFT_RESET); + dsb(); + + writel(((read_val & ~BIT(1)) | BIT(2)), + sctl_base + CTRL); + } + } + mdss_dsi_cmds_tx(&pinfo->mipi, pinfo->mipi.panel_off_cmds, + pinfo->mipi.num_of_panel_off_cmds, + pinfo->mipi.broadcast); + } +} + +int mdss_dsi_panel_initialize(struct mipi_panel_info *mipi, + uint32_t broadcast) +{ + int status = 0; + uint32_t ctrl_mode = 0; + + if (!mipi->panel_on_cmds) + goto end; + + ctrl_mode = readl(mipi->ctl_base + CTRL); + + /* Enable command mode before sending the commands. */ + writel(ctrl_mode | 0x04, mipi->ctl_base + CTRL); + + if (broadcast) + writel(ctrl_mode | 0x04, mipi->sctl_base + CTRL); + + mdelay(500); + + status = mdss_dsi_cmds_tx(mipi, + mipi->panel_on_cmds, + mipi->num_of_panel_on_cmds, + broadcast); + + writel(ctrl_mode, mipi->ctl_base + CTRL); + + if (broadcast) + writel(ctrl_mode, mipi->sctl_base + CTRL); + +end: + return status; +} + + + +int mdss_dsi_video_mode_config(struct msm_panel_info *pinfo, + uint16_t disp_width, + uint16_t disp_height, + uint16_t img_width, + uint16_t img_height, + uint16_t hsync_porch0_fp, + uint16_t hsync_porch0_bp, + uint16_t vsync_porch0_fp, + uint16_t vsync_porch0_bp, + uint16_t hsync_width, + uint16_t vsync_width, + uint16_t dst_format, + uint16_t traffic_mode, + uint8_t lane_en, + uint8_t pulse_mode_hsa_he, + uint32_t low_pwr_stop_mode, + uint8_t eof_bllp_pwr, + uint8_t interleav, + uint32_t ctl_base) +{ + int status = 0; + int last_line_interleave_en = 0; + struct dsc_desc *dsc = NULL; + + if (pinfo->compression_mode == COMPRESSION_DSC) + dsc = &pinfo->dsc; + + /*Check if EOF_BLLP_PWR_MODE bit is set*/ + if (eof_bllp_pwr & 0x8) + last_line_interleave_en = 1; + + mdss_dsi_clock_config(ctl_base); + + writel(((disp_width + hsync_porch0_bp) << 16) | hsync_porch0_bp, + ctl_base + VIDEO_MODE_ACTIVE_H); + + writel(((disp_height + vsync_porch0_bp) << 16) | (vsync_porch0_bp), + ctl_base + VIDEO_MODE_ACTIVE_V); + + if (mdp_get_revision() >= MDSS_MDP_HW_REV_620) { + writel(((disp_height + vsync_porch0_fp + + vsync_porch0_bp - 1) << 16) | + (disp_width + hsync_porch0_fp + + hsync_porch0_bp - 1), + + ctl_base + VIDEO_MODE_TOTAL); + } + else { + writel(((disp_height + vsync_porch0_fp + + vsync_porch0_bp) << 16) | + (disp_width + hsync_porch0_fp + + hsync_porch0_bp), + ctl_base + VIDEO_MODE_TOTAL); + } + + writel((hsync_width << 16) | 0, ctl_base + VIDEO_MODE_HSYNC); + writel(0 << 16 | 0, ctl_base + VIDEO_MODE_VSYNC); + writel(vsync_width << 16 | 0, ctl_base + VIDEO_MODE_VSYNC_VPOS); + + writel(low_pwr_stop_mode << 15 | eof_bllp_pwr << 12 | traffic_mode << 8 | dst_format << 4 | 0x0, + ctl_base + VIDEO_MODE_CTRL); + + writel(0x0004EA60, ctl_base + HS_TIMER_CTRL); + + writel(interleav << 30 | 0 << 24 | 0 << 20 | lane_en << 4 + | 0x103, ctl_base + CTRL); + + if (dsc) { + if (dsc->dsi_dsc_config) + dsc->dsi_dsc_config(pinfo->mipi.ctl_base, + DSI_VIDEO_MODE, dsc); + } + + return status; +} + +int mdss_dsi_config(struct msm_fb_panel_data *panel) +{ + int ret = NO_ERROR; + struct msm_panel_info *pinfo; + struct mipi_panel_info *mipi; + struct dsc_desc *dsc = NULL; + struct mipi_dsi_cmd cmd; + + if (!panel) + return ERROR; + + pinfo = &(panel->panel_info); + mipi = &(pinfo->mipi); + + + if (pinfo->compression_mode == COMPRESSION_DSC) { + dsc = &pinfo->dsc; + if (dsc) { + if (dsc->dsc2buf) + dsc->dsc2buf(pinfo); + } + } + + printk(BIOS_INFO, "ctl_base=0x%08x, phy_base=0x%08x\n", mipi->ctl_base,mipi->phy_base); + + mdss_dsi_reset(mipi, mipi->dual_dsi); + + if (mdss_dsi_phy_intf_setup(DSI_PLL_TYPE_10NM, &phy_intf) != NO_ERROR) { + printk(BIOS_ERR, "mdss_dsi_phy_intf_setup returned error\n"); + return ERROR; + } + + if (phy_intf.dsi_phy_init != NULL) + phy_intf.dsi_phy_init(pinfo); + else { + printk(BIOS_ERR, "dsi_phy_init is NULL\n"); + return ERROR; + } + + ret = mdss_dsi_host_init(mipi, + mipi->dual_dsi, + mipi->broadcast); + if (ret) { + printk(BIOS_ERR, "dsi host init error\n"); + goto error; + } + + if (panel->pre_init_func) { + ret = panel->pre_init_func(); + if (ret) { + printk(BIOS_ERR, "pre_init_func error\n"); + goto error; + } + } + + if (mipi->force_clk_lane_hs) + mdss_dsi_force_clk_lane_hs(mipi, mipi->dual_dsi); + + if (!mipi->cmds_post_tg) { + ret = mdss_dsi_panel_initialize(mipi, mipi->broadcast); + if (ret) { + printk(BIOS_ERR, "dsi panel init error\n"); + goto error; + } + } + + if (dsc) { + cmd.size = DCS_HDR_LEN + DSC_PPS_LEN; + cmd.payload = dsc->pps_buf; + cmd.wait = 0x10; + mdss_dsi_cmds_tx(mipi, &cmd, 1, mipi->broadcast); + } + + if (pinfo->rotate && panel->rotate) + pinfo->rotate(); + + /* Reset DSI Interrupt/Error registers */ + mdss_dsi_clear_intr(mipi, mipi->dual_dsi); + +error: + return ret; +} + +int mdss_dsi_post_on(struct msm_fb_panel_data *panel) +{ + int ret = 0; + struct msm_panel_info *pinfo = &(panel->panel_info); + + if (pinfo->mipi.cmds_post_tg) { + ret = mdss_dsi_panel_initialize(&pinfo->mipi, + pinfo->mipi.broadcast); + if (ret) + printk(BIOS_ERR, "dsi panel init error\n"); + } + + return ret; +} + +int mdss_dsi_cmd_mode_config(struct msm_panel_info *pinfo, + uint16_t disp_width, + uint16_t disp_height, + uint16_t img_width, + uint16_t img_height, + uint16_t dst_format, + uint8_t ystride, + uint8_t lane_en, + uint8_t interleav, + uint32_t ctl_base) +{ + uint16_t dst_fmt = 0; + struct dsc_desc *dsc = NULL; + unsigned int data; + uint32_t uRegVal = 0; + + switch (dst_format) { + case DSI_VIDEO_DST_FORMAT_RGB565: + dst_fmt = DSI_CMD_DST_FORMAT_RGB565; + break; + + case DSI_VIDEO_DST_FORMAT_RGB666: + case DSI_VIDEO_DST_FORMAT_RGB666_LOOSE: + dst_fmt = DSI_CMD_DST_FORMAT_RGB666; + break; + + case DSI_VIDEO_DST_FORMAT_RGB888: + dst_fmt = DSI_CMD_DST_FORMAT_RGB888; + break; + + default: + printk(BIOS_ERR, "unsupported dst format\n"); + return ERROR; + } + + mdss_dsi_clock_config(ctl_base); + + writel(0, ctl_base + CTRL); + writel(0x03f03fe0, ctl_base + ERR_INT_MASK0); + + mdss_dsi_set_intr(ctl_base); + + writel(dst_fmt, ctl_base + COMMAND_MODE_MDP_CTRL); + + if (pinfo->compression_mode == COMPRESSION_DSC) + dsc = &pinfo->dsc; + + if (dsc) { + data = dsc->bytes_per_pkt; + + if (pinfo->mipi.insert_dcs_cmd) + data++; + + data <<= 16; + data |= 0x039; + writel(data, ctl_base + COMMAND_MODE_MDP_STREAM0_CTRL); + writel(data, ctl_base + COMMAND_MODE_MDP_STREAM1_CTRL); + + data = dsc->pic_height << 16; + data |= dsc->pclk_per_line; + writel(data, ctl_base + COMMAND_MODE_MDP_STREAM0_TOTAL); + writel(data, ctl_base + COMMAND_MODE_MDP_STREAM1_TOTAL); + + if (dsc->dsi_dsc_config) + dsc->dsi_dsc_config(pinfo->mipi.ctl_base, + DSI_CMD_MODE, dsc); + } + else { + + writel((img_width * ystride + 1) << 16 | 0x0039, + ctl_base + COMMAND_MODE_MDP_STREAM0_CTRL); + writel((img_width * ystride + 1) << 16 | 0x0039, + ctl_base + COMMAND_MODE_MDP_STREAM1_CTRL); + writel(img_height << 16 | img_width, + ctl_base + COMMAND_MODE_MDP_STREAM0_TOTAL); + writel(img_height << 16 | img_width, + ctl_base + COMMAND_MODE_MDP_STREAM1_TOTAL); + } + + uRegVal = readl(ctl_base+COMMAND_MODE_MDP_DCS_CMD_CTRL); + uRegVal = HWIO_OUT_FLD(uRegVal, COMMAND_MODE_MDP_DCS_CMD_CTRL, INSERT_DCS_COMMAND, 0x01); + + writel(uRegVal, ctl_base + COMMAND_MODE_MDP_DCS_CMD_CTRL); + writel(interleav << 30 | 0 << 24 | 0 << 20 | lane_en << 4 | 0x105, ctl_base + CTRL); + + uRegVal = 0; + uRegVal = HWIO_OUT_FLD( uRegVal, COMMAND_MODE_DMA_CTRL, EMBEDDED_MODE, 0x01); + uRegVal = HWIO_OUT_FLD( uRegVal, COMMAND_MODE_DMA_CTRL, POWER_MODE, 0x01); //Low power Mode + + writel(uRegVal, ctl_base + COMMAND_MODE_DMA_CTRL); + writel(BIT(28), ctl_base + MISR_CMD_CTRL); //enable MISR cmd ctrl. + + return 0; +} + +void mdss_dsi_clock_config(uint32_t ctl_base) +{ + /* Default to all clock off */ + uint32_t uClkCtrlReg = 0; + + /* Clock for AHI Bus Master, for DMA out from memory */ + uClkCtrlReg = HWIO_OUT_FLD( uClkCtrlReg, CLK_CTRL, DSI_AHBM_SCLK_ON, 1); + uClkCtrlReg = HWIO_OUT_FLD( uClkCtrlReg, CLK_CTRL, DSI_FORCE_ON_DYN_AHBM_HCLK, 1); + + /* Clock for MDP/DSI, for DMA out from MDP */ + uClkCtrlReg = HWIO_OUT_FLD( uClkCtrlReg, CLK_CTRL, DSI_PCLK_ON, 1); + + /* Clock for rest of DSI */ + uClkCtrlReg = HWIO_OUT_FLD( uClkCtrlReg, CLK_CTRL, DSI_AHBS_HCLK_ON, 1); + uClkCtrlReg = HWIO_OUT_FLD( uClkCtrlReg, CLK_CTRL, DSI_DSICLK_ON, 1); + + uClkCtrlReg = HWIO_OUT_FLD( uClkCtrlReg, CLK_CTRL, DSI_BYTECLK_ON, 1); + uClkCtrlReg = HWIO_OUT_FLD( uClkCtrlReg, CLK_CTRL, DSI_ESCCLK_ON, 1); + + writel(uClkCtrlReg, ctl_base + CLK_CTRL); + +} + + diff --git a/src/soc/qualcomm/sc7180/display/dsi_panel_display.c b/src/soc/qualcomm/sc7180/display/dsi_panel_display.c new file mode 100644 index 0000000..35efa9a --- /dev/null +++ b/src/soc/qualcomm/sc7180/display/dsi_panel_display.c @@ -0,0 +1,472 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2020 Qualcomm Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <arch/mmio.h> +#include <stdlib.h> +#include <console/console.h> +#include <string.h> +#include <soc/mdss_6_2_0.h> +#include <soc/display/panel.h> +#include <soc/display/msm_panel.h> +#include <soc/display/mipi_dsi.h> +#include <soc/display/panel_display.h> +#include <soc/display/target_sc7180.h> + +int dsi_video_panel_config(struct msm_panel_info *pinfo, + struct lcdc_panel_info *plcdc); + +int dsi_cmd_panel_config(struct msm_panel_info *pinfo, + struct lcdc_panel_info *plcdc); + +static int dsi_platform_base_offset_adjust(uint32_t base) +{ + return target_display_get_base_offset(base); +} + +static int dsi_panel_ctl_base_setup(struct msm_panel_info *pinfo, + char *panel_destination) +{ + int base_offset = 0, + base1_offset = 0, + base_phy_offset = 0, + base1_phy_offset = 0; + + /* + * Base offsets may vary for few platforms. Add the difference to get + * proper base offset for the respective platform. + */ + base_offset = dsi_platform_base_offset_adjust(MIPI_DSI0_BASE); + base1_offset = dsi_platform_base_offset_adjust(MIPI_DSI1_BASE); + base_phy_offset = dsi_platform_base_offset_adjust(DSI0_PHY_BASE); + base1_phy_offset = dsi_platform_base_offset_adjust(DSI1_PHY_BASE); + + if (!strcmp(panel_destination, "DISPLAY_1")) { + pinfo->dest = DISPLAY_1; + pinfo->mipi.ctl_base = MIPI_DSI0_BASE + base_offset; + pinfo->mipi.phy_base = DSI0_PHY_BASE + base_phy_offset; + pinfo->mipi.sctl_base = MIPI_DSI1_BASE + base1_offset; + pinfo->mipi.sphy_base = DSI1_PHY_BASE + base1_phy_offset; + + if (pinfo->mipi.use_dsi1_pll) { + printk(BIOS_ERR, + "%s: Invalid combination: DSI0 controller +" + "DSI1 PLL, using DSI0 PLL\n", __func__); + pinfo->mipi.use_dsi1_pll = 0; + } + + } else if (!strcmp(panel_destination, "DISPLAY_2")) { + pinfo->dest = DISPLAY_2; + pinfo->mipi.ctl_base = MIPI_DSI1_BASE + base1_offset; + pinfo->mipi.phy_base = DSI1_PHY_BASE + base1_phy_offset; + pinfo->mipi.sctl_base = MIPI_DSI0_BASE + base_offset; + pinfo->mipi.sphy_base = DSI0_PHY_BASE + base_phy_offset; + + } else { + pinfo->dest = DISPLAY_UNKNOWN; + printk(BIOS_ERR, "%s: Unknown panel destination: %d\n", + __func__, pinfo->dest); + return ERROR; + } + + return NO_ERROR; +} + +int dsi_panel_init(struct msm_panel_info *pinfo, + struct panel_struct *pstruct) +{ + int ret = NO_ERROR; + /* Resolution setting*/ + pinfo->xres = pstruct->panelres->panel_width; + pinfo->yres = pstruct->panelres->panel_height; + pinfo->lcdc.h_back_porch = pstruct->panelres->hback_porch; + pinfo->lcdc.h_front_porch = pstruct->panelres->hfront_porch; + pinfo->lcdc.h_pulse_width = pstruct->panelres->hpulse_width; + pinfo->lcdc.v_back_porch = pstruct->panelres->vback_porch; + pinfo->lcdc.v_front_porch = pstruct->panelres->vfront_porch; + pinfo->lcdc.v_pulse_width = pstruct->panelres->vpulse_width; + pinfo->lcdc.hsync_skew = pstruct->panelres->hsync_skew; + + pinfo->border_top = pstruct->panelres->vtop_border; + pinfo->border_bottom = pstruct->panelres->vbottom_border; + pinfo->border_left = pstruct->panelres->hleft_border; + pinfo->border_right = pstruct->panelres->hright_border; + + printk(BIOS_INFO, "%s: left=%d right=%d top=%d bottom=%d\n", __func__, + pinfo->border_left, pinfo->border_right, + pinfo->border_top, pinfo->border_bottom); + + pinfo->xres += (pinfo->border_left + pinfo->border_right); + pinfo->yres += (pinfo->border_top + pinfo->border_bottom); + + if (pstruct->paneldata->panel_operating_mode & DUAL_PIPE_FLAG) + pinfo->lcdc.dual_pipe = 1; + + if (pstruct->paneldata->panel_operating_mode & PIPE_SWAP_FLAG) + pinfo->lcdc.pipe_swap = 1; + + if (pstruct->paneldata->panel_operating_mode & SPLIT_DISPLAY_FLAG) + pinfo->lcdc.split_display = 1; + + if (pstruct->paneldata->panel_operating_mode & DST_SPLIT_FLAG) + pinfo->lcdc.dst_split = 1; + + if (pstruct->paneldata->panel_operating_mode & DUAL_DSI_FLAG) + pinfo->mipi.dual_dsi = 1; + + if (pstruct->paneldata->panel_operating_mode & USE_DSI1_PLL_FLAG) + pinfo->mipi.use_dsi1_pll = 1; + + /* Color setting*/ + pinfo->lcdc.border_clr = pstruct->color->border_color; + pinfo->lcdc.underflow_clr = pstruct->color->underflow_color; + pinfo->mipi.rgb_swap = pstruct->color->color_order; + pinfo->bpp = pstruct->color->color_format; + + switch (pinfo->bpp) { + case BPP_16: + pinfo->mipi.dst_format = DSI_VIDEO_DST_FORMAT_RGB565; + break; + case BPP_18: + if (pstruct->color->pixel_packing) + pinfo->mipi.dst_format = DSI_VIDEO_DST_FORMAT_RGB666_LOOSE; + else + pinfo->mipi.dst_format = DSI_VIDEO_DST_FORMAT_RGB666; + break; + case BPP_24: + default: + pinfo->mipi.dst_format = DSI_VIDEO_DST_FORMAT_RGB888; + break; + } + + /* Panel generic info */ + pinfo->mipi.mode = pstruct->paneldata->panel_type; + + if (pinfo->mipi.mode) + pinfo->type = MIPI_CMD_PANEL; + else + pinfo->type = MIPI_VIDEO_PANEL; + + pinfo->clk_rate = pstruct->paneldata->panel_clockrate; + pinfo->orientation = pstruct->paneldata->panel_orientation; + pinfo->mipi.interleave_mode = pstruct->paneldata->interleave_mode; + pinfo->mipi.broadcast = pstruct->paneldata->panel_broadcast_mode; + pinfo->mipi.vc = pstruct->paneldata->dsi_virtualchannel_id; + pinfo->mipi.frame_rate = pstruct->paneldata->panel_framerate; + pinfo->mipi.stream = pstruct->paneldata->dsi_stream; + pinfo->mipi.mode_gpio_state = pstruct->paneldata->mode_gpio_state; + pinfo->mipi.bitclock = pstruct->paneldata->panel_bitclock_freq; + + if (pinfo->mipi.bitclock) { + /* panel_clockrate is depcrated in favor of bitclock_freq */ + pinfo->clk_rate = pinfo->mipi.bitclock; + } + + pinfo->mipi.use_enable_gpio = pstruct->paneldata->panel_with_enable_gpio; + + ret = dsi_panel_ctl_base_setup(pinfo, + pstruct->paneldata->panel_destination); + + if (ret) + return ret; + + /* Video Panel configuration */ + pinfo->mipi.pulse_mode_hsa_he = pstruct->videopanel->hsync_pulse; + pinfo->mipi.hfp_power_stop = pstruct->videopanel->hfp_power_mode; + pinfo->mipi.hbp_power_stop = pstruct->videopanel->hbp_power_mode; + pinfo->mipi.hsa_power_stop = pstruct->videopanel->hsa_power_mode; + pinfo->mipi.eof_bllp_power_stop = pstruct->videopanel->bllp_eof_power_mode; + pinfo->mipi.bllp_power_stop = pstruct->videopanel->bllp_power_mode; + pinfo->mipi.traffic_mode = pstruct->videopanel->traffic_mode; + pinfo->mipi.eof_bllp_power = pstruct->videopanel->bllp_eof_power; + + /* Command Panel configuration */ + pinfo->mipi.insert_dcs_cmd = pstruct->commandpanel->tedcs_command; + pinfo->mipi.wr_mem_continue = pstruct->commandpanel->tevsync_continue_lines; + pinfo->mipi.wr_mem_start = pstruct->commandpanel->tevsync_rdptr_irqline; + pinfo->mipi.te_sel = pstruct->commandpanel->tepin_select; + pinfo->autorefresh_enable = pstruct->commandpanel->autorefresh_enable; + pinfo->autorefresh_framenum = pstruct->commandpanel->autorefresh_framenumdiv; + + /* Data lane configuraiton */ + pinfo->mipi.num_of_lanes = pstruct->laneconfig->dsi_lanes; + pinfo->mipi.data_lane0 = pstruct->laneconfig->lane0_state; + pinfo->mipi.data_lane1 = pstruct->laneconfig->lane1_state; + pinfo->mipi.data_lane2 = pstruct->laneconfig->lane2_state; + pinfo->mipi.data_lane3 = pstruct->laneconfig->lane3_state; + pinfo->mipi.lane_swap = pstruct->laneconfig->dsi_lanemap; + pinfo->mipi.force_clk_lane_hs = pstruct->laneconfig->force_clk_lane_hs; + + pinfo->mipi.t_clk_post = pstruct->paneltiminginfo->tclk_post; + pinfo->mipi.t_clk_pre = pstruct->paneltiminginfo->tclk_pre; + pinfo->mipi.mdp_trigger = pstruct->paneltiminginfo->dsi_mdp_trigger; + pinfo->mipi.dma_trigger = pstruct->paneltiminginfo->dsi_dma_trigger; + + if (pinfo->compression_mode == COMPRESSION_DSC) { + struct dsc_desc *dsc = &pinfo->dsc; + struct dsc_parameters *dsc_params = NULL; + + if (!pstruct->config) { + printk(BIOS_ERR, + "ERROR: DSC cannot be used without topology_config\n"); + return ERROR; + } + dsc_params = pstruct->config->dsc; + if (!dsc_params) { + printk(BIOS_ERR, "ERROR: DSC params are NULL\n"); + return ERROR; + } + + dsc->major = dsc_params->major; + dsc->minor = dsc_params->minor; + dsc->scr_rev = dsc_params->scr_rev; + dsc->pps_id = dsc_params->pps_id; + dsc->slice_height = dsc_params->slice_height; + dsc->slice_width = dsc_params->slice_width; + dsc->bpp = dsc_params->bpp; + dsc->bpc = dsc_params->bpc; + dsc->slice_per_pkt = dsc_params->slice_per_pkt; + dsc->block_pred_enable = dsc_params->block_prediction; + dsc->enable_422 = 0; + dsc->convert_rgb = 1; + dsc->vbr_enable = 0; + + if (dsc->parameter_calc) + dsc->parameter_calc(pinfo); + } + + pinfo->pre_on = dsi_panel_pre_on; + pinfo->pre_off = dsi_panel_pre_off; + pinfo->on = dsi_panel_post_on; + pinfo->off = dsi_panel_post_off; + pinfo->rotate = dsi_panel_rotation; + pinfo->config = dsi_panel_config; + + return NO_ERROR; +} + +/* Panel Callbacks */ +int dsi_panel_pre_on(void) +{ + return target_display_pre_on(); +} + +int dsi_panel_pre_off(void) +{ + return target_display_pre_off(); +} + +int dsi_panel_post_on(void) +{ + int ret = NO_ERROR; + + ret = target_display_post_on(); + if (ret) + return ret; + + return oem_panel_on(); +} + +int dsi_panel_post_off(void) +{ + int ret = NO_ERROR; + + ret = target_display_post_off(); + if (ret) + return ret; + + return oem_panel_off(); +} + +int dsi_panel_rotation(void) +{ + return oem_panel_rotation(); +} + +int dsi_video_panel_config(struct msm_panel_info *pinfo, + struct lcdc_panel_info *plcdc) +{ + int ret = NO_ERROR; + uint8_t lane_enable = 0; + uint32_t panel_width = pinfo->xres; + uint32_t final_xres, final_yres, final_width; + uint32_t final_height, final_hbp, final_hfp, final_vbp; + uint32_t final_vfp, final_hpw, final_vpw, low_pwr_stop; + struct dsc_desc *dsc = NULL; + + if (pinfo->mipi.dual_dsi) + panel_width = panel_width / 2; + + if (pinfo->mipi.data_lane0) + lane_enable |= (1 << 0); + if (pinfo->mipi.data_lane1) + lane_enable |= (1 << 1); + if (pinfo->mipi.data_lane2) + lane_enable |= (1 << 2); + if (pinfo->mipi.data_lane3) + lane_enable |= (1 << 3); + + if (pinfo->compression_mode == COMPRESSION_DSC) { + dsc = &pinfo->dsc; + panel_width = dsc->pclk_per_line; + } + + final_xres = panel_width; + final_width = panel_width + pinfo->lcdc.xres_pad; + final_yres = pinfo->yres; + final_height = pinfo->yres + pinfo->lcdc.yres_pad; + final_hbp = pinfo->lcdc.h_back_porch; + final_hfp = pinfo->lcdc.h_front_porch; + final_vbp = pinfo->lcdc.v_back_porch; + final_vfp = pinfo->lcdc.v_front_porch; + final_hpw = pinfo->lcdc.h_pulse_width; + final_vpw = pinfo->lcdc.v_pulse_width; + low_pwr_stop = (pinfo->mipi.hfp_power_stop << 8) | + (pinfo->mipi.hbp_power_stop << 4) | + pinfo->mipi.hsa_power_stop; + + ret = mdss_dsi_video_mode_config(pinfo, + final_width, final_height, + final_xres, final_yres, + final_hfp, final_hbp + final_hpw, + final_vfp, final_vbp + final_vpw, + final_hpw, final_vpw, + pinfo->mipi.dst_format, + pinfo->mipi.traffic_mode, + lane_enable, + pinfo->mipi.pulse_mode_hsa_he, + low_pwr_stop, + pinfo->mipi.eof_bllp_power, + pinfo->mipi.interleave_mode, + pinfo->mipi.ctl_base); + + if (pinfo->mipi.dual_dsi) + ret = mdss_dsi_video_mode_config(pinfo, + final_width, final_height, + final_xres, final_yres, + final_hfp, final_hbp + final_hpw, + final_vfp, final_vbp + final_vpw, + final_hpw, final_vpw, + pinfo->mipi.dst_format, + pinfo->mipi.traffic_mode, + lane_enable, + pinfo->mipi.pulse_mode_hsa_he, + low_pwr_stop, + pinfo->mipi.eof_bllp_power, + pinfo->mipi.interleave_mode, + pinfo->mipi.sctl_base); + + return ret; +} + +int dsi_cmd_panel_config(struct msm_panel_info *pinfo, + struct lcdc_panel_info *plcdc) +{ + int ret = NO_ERROR; + uint8_t lane_en = 0; + uint8_t ystride = pinfo->bpp / 8; + uint32_t panel_width = pinfo->xres; + struct dsc_desc *dsc = NULL; + uint32_t final_xres, final_yres, final_width; + uint32_t final_height; + + if (pinfo->mipi.dual_dsi) + panel_width = panel_width / 2; + + if (pinfo->mipi.data_lane0) + lane_en |= (1 << 0); + + if (pinfo->mipi.data_lane1) + lane_en |= (1 << 1); + + if (pinfo->mipi.data_lane2) + lane_en |= (1 << 2); + + if (pinfo->mipi.data_lane3) + lane_en |= (1 << 3); + + if (pinfo->compression_mode == COMPRESSION_DSC) { + dsc = &pinfo->dsc; + panel_width = dsc->pclk_per_line; + } + + final_xres = panel_width; + final_width = panel_width + pinfo->lcdc.xres_pad; + final_yres = pinfo->yres; + final_height = pinfo->yres + pinfo->lcdc.yres_pad; + + ret = mdss_dsi_cmd_mode_config(pinfo, final_width, final_height, + final_xres, final_yres, + pinfo->mipi.dst_format, + ystride, lane_en, + pinfo->mipi.interleave_mode, + pinfo->mipi.ctl_base); + + if (pinfo->mipi.dual_dsi) + ret = mdss_dsi_cmd_mode_config(pinfo, final_width, final_height, + final_xres, final_yres, + pinfo->mipi.dst_format, + ystride, lane_en, + pinfo->mipi.interleave_mode, + pinfo->mipi.sctl_base); + + return ret; +} + + +int dsi_panel_config(void *pdata) +{ + struct msm_panel_info *pinfo = (struct msm_panel_info *)pdata; + struct lcdc_panel_info *plcdc = NULL; + int ret = NO_ERROR; + + if (pinfo == NULL) + return ERROR; + + plcdc = &(pinfo->lcdc); + if (plcdc == NULL) + return ERROR; + + + if (pinfo->mipi.mode == DSI_VIDEO_MODE) + ret = dsi_video_panel_config(pinfo, plcdc); + else + ret = dsi_cmd_panel_config(pinfo, plcdc); + + return ret; +} + +int32_t panel_name_to_id(struct panel_list supp_panels[], + uint32_t supp_panels_size, + const char *panel_name) +{ + uint32_t i; + int32_t panel_id = ERROR; + + if (!panel_name) { + printk(BIOS_ERR, "Invalid panel name\n"); + return panel_id; + } + + for (i = 0; i < supp_panels_size; i++) { + if (!strncmp(panel_name, supp_panels[i].name, + MAX_PANEL_ID_LEN)) { + panel_id = supp_panels[i].id; + break; + } + } + + return panel_id; +} + diff --git a/src/soc/qualcomm/sc7180/display/target_sc7180.c b/src/soc/qualcomm/sc7180/display/target_sc7180.c new file mode 100644 index 0000000..e79c4cb --- /dev/null +++ b/src/soc/qualcomm/sc7180/display/target_sc7180.c @@ -0,0 +1,112 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2020 Qualcomm Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <arch/mmio.h> +#include <lib.h> +#include <console/console.h> +#include <delay.h> +#include <device/device.h> +#include <edid.h> +#include <stdlib.h> +#include <string.h> +#include <soc/display/panel.h> +#include <soc/display/msm_panel.h> +#include <soc/mdss_6_2_0.h> +#include <soc/display/mipi_dsi.h> +#include <soc/display/panel_display.h> +#include <soc/display/target_sc7180.h> +#include <gpio.h> +#include <soc/gpio.h> + +#define STRENGTH_SIZE_IN_BYTES_SDM845 10 +#define REGULATOR_SIZE_IN_BYTES_SDM845 5 +#define LANE_SIZE_IN_BYTES_SDM845 20 + +int target_dsi_phy_config(struct mdss_dsi_phy_ctrl *phy_db) +{ + memcpy(phy_db->strength, panel_strength_ctrl, + STRENGTH_SIZE_IN_BYTES_SDM845 * sizeof(uint32_t)); + memcpy(phy_db->regulator, panel_regulator_settings, + REGULATOR_SIZE_IN_BYTES_SDM845 * sizeof(uint32_t)); + memcpy(phy_db->laneCfg, panel_lane_config, + LANE_SIZE_IN_BYTES_SDM845); + return NO_ERROR; +} + +int target_backlight_ctrl(uint8_t enable) +{ + + if (enable) { + gpio_configure(GPIO(12), GPIO_FUNC_GPIO, GPIO_NO_PULL, + GPIO_2MA, GPIO_OUTPUT_ENABLE); //BackLight enable GPIO + + gpio_set(GPIO(12), 1); + + } else { + gpio_set(GPIO(12), 1); + + } + return NO_ERROR; +} + +int target_panel_reset(uint8_t enable, struct panel_reset_sequence *resetseq, + struct msm_panel_info *pinfo) +{ + return NO_ERROR; + +} + +int target_set_switch_gpio(int enable) +{ + printk(BIOS_INFO, "%s: Turn bridge gpio's on\n", __func__); + if (enable) { + gpio_configure(GPIO(14), GPIO_FUNC_GPIO, GPIO_NO_PULL, + GPIO_2MA, GPIO_OUTPUT_ENABLE); //Bridge Enable GPIO + + gpio_set(GPIO(14), 1); + + gpio_configure(GPIO(106), GPIO_FUNC_GPIO, GPIO_NO_PULL, + GPIO_8MA, GPIO_OUTPUT_ENABLE); //PP3300 EDP power supply + + gpio_set(GPIO(106), 1); + } else { + gpio_set(GPIO(14), 1); + gpio_set(GPIO(106), 1); + } + return NO_ERROR; +} + +int target_display_pre_on(void) +{ + return NO_ERROR; +} + +int target_display_pre_off(void) +{ + return NO_ERROR; +} +int target_display_post_on(void) +{ + return NO_ERROR; +} +int target_display_post_off(void) +{ + return NO_ERROR; +} +int target_display_get_base_offset(uint32_t base) +{ + return 0; +} + diff --git a/src/soc/qualcomm/sc7180/include/soc/display/mipi_dsi.h b/src/soc/qualcomm/sc7180/include/soc/display/mipi_dsi.h new file mode 100644 index 0000000..b3eebf8 --- /dev/null +++ b/src/soc/qualcomm/sc7180/include/soc/display/mipi_dsi.h @@ -0,0 +1,96 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (c) 2018 Qualcomm Technologies + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _PLATFORM_MSM_SHARED_MIPI_DSI_H_ +#define _PLATFORM_MSM_SHARED_MIPI_DSI_H_ + +#include <soc/display/msm_panel.h> + +#define PASS 0 +#define FAIL 1 +#define DSI_VIDEO_MODE_DONE_MASK BIT(17) +#define DSI_VIDEO_MODE_DONE_AK BIT(16) +#define DSI_VIDEO_MODE_DONE_STAT BIT(16) +/********************************************************** + DSI register configuration options + **********************************************************/ +#define MIPI_DSI_MRPS 0x04 /* Maximum Return Packet Size */ +#define MIPI_DSI_REG_LEN 16 /* 4 x 4 bytes register */ +#define TIMING_FLUSH 0x1E4 +#define TIMING_DB_MODE 0x1E8 +#define DSI_HW_REV_241 0x20040001 /* SDM845 */ +#define RDBK_DATA0 0x06C +#define DSI_VIDEO_DST_FORMAT_RGB565 0 +#define DSI_VIDEO_DST_FORMAT_RGB666 1 +#define DSI_VIDEO_DST_FORMAT_RGB666_LOOSE 2 +#define DSI_VIDEO_DST_FORMAT_RGB888 3 +#define DSI_CMD_DST_FORMAT_RGB111 0 +#define DSI_CMD_DST_FORMAT_RGB332 3 +#define DSI_CMD_DST_FORMAT_RGB444 4 +#define DSI_CMD_DST_FORMAT_RGB565 6 +#define DSI_CMD_DST_FORMAT_RGB666 7 +#define DSI_CMD_DST_FORMAT_RGB888 8 + +struct mipi_dsi_cmd { + uint32_t size; + char *payload; + int wait; +}; + +enum { + DSI_VIDEO_MODE, + DSI_CMD_MODE, +}; + +int mdss_dsi_config(struct msm_fb_panel_data *panel); +int mdss_dsi_video_mode_config(struct msm_panel_info *pinfo, + uint16_t disp_width, + uint16_t disp_height, + uint16_t img_width, + uint16_t img_height, + uint16_t hsync_porch0_fp, + uint16_t hsync_porch0_bp, + uint16_t vsync_porch0_fp, + uint16_t vsync_porch0_bp, + uint16_t hsync_width, + uint16_t vsync_width, + uint16_t dst_format, + uint16_t traffic_mode, + uint8_t lane_en, + uint8_t pulse_mode_hsa_he, + uint32_t low_pwr_stop_mode, + uint8_t eof_bllp_pwr, + uint8_t interleav, + uint32_t ctl_base); + +int mdss_dsi_cmd_mode_config(struct msm_panel_info *pinfo, + uint16_t disp_width, + uint16_t disp_height, + uint16_t img_width, + uint16_t img_height, + uint16_t dst_format, + uint8_t ystride, + uint8_t lane_en, + uint8_t interleav, + uint32_t ctl_base); + +int mdss_dsi_cmds_tx(struct mipi_panel_info *mipi, + struct mipi_dsi_cmd *cmds, int count, char dual_dsi); +int mdss_dsi_cmds_rx(struct mipi_panel_info *mipi, uint32_t **rp, int rp_len, + int rdbk_len); +int mdss_dsi_post_on(struct msm_fb_panel_data *panel); + +#endif + diff --git a/src/soc/qualcomm/sc7180/include/soc/display/panel_display.h b/src/soc/qualcomm/sc7180/include/soc/display/panel_display.h new file mode 100644 index 0000000..a36e31b --- /dev/null +++ b/src/soc/qualcomm/sc7180/include/soc/display/panel_display.h @@ -0,0 +1,78 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (c) 2018 Qualcomm Technologies + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _PANEL_DISPLAY_H_ +#define _PANEL_DISPLAY_H_ +/*---------------------------------------------------------------------------*/ +/* MACRO definition */ +/*---------------------------------------------------------------------------*/ +#define BPP_16 16 +#define BPP_18 18 +#define BPP_24 24 +#define TIMING_SIZE 48 +#define REGULATOR_SIZE 28 +#define DUAL_DSI_FLAG 0x1 +#define DUAL_PIPE_FLAG 0x2 +#define PIPE_SWAP_FLAG 0x4 +#define SPLIT_DISPLAY_FLAG 0x8 +#define DST_SPLIT_FLAG 0x10 +#define USE_DSI1_PLL_FLAG 0x20 +#define MAX_PANEL_ID_LEN 64 +#include <soc/display/panel.h> +/*---------------------------------------------------------------------------*/ +/* struct definition */ +/*---------------------------------------------------------------------------*/ +struct panel_struct { + struct panel_config *paneldata; + struct panel_resolution *panelres; + struct color_info *color; + struct videopanel_info *videopanel; + struct commandpanel_info *commandpanel; + struct command_state *state; + struct lane_configuration *laneconfig; + struct panel_timing *paneltiminginfo; + struct panel_reset_sequence *panelresetseq; + struct backlight *backlightinfo; + struct topology_config *config; +}; + +struct panel_list { + char name[MAX_PANEL_ID_LEN]; + uint32_t id; +}; + +/*---------------------------------------------------------------------------*/ +/* API */ +/*---------------------------------------------------------------------------*/ +int dsi_panel_init(struct msm_panel_info *pinfo, + struct panel_struct *pstruct); +int dsi_panel_pre_on(void); +int dsi_panel_post_on(void); +int dsi_panel_pre_off(void); +int dsi_panel_post_off(void); +int dsi_panel_rotation(void); +int dsi_panel_config(void *cfg); +int oem_panel_rotation(void); +int oem_panel_on(void); +int oem_panel_off(void); + +/* OEM support API */ +int32_t panel_name_to_id(struct panel_list supp_panels[], + uint32_t supp_panels_size, const char *panel_name); + +int oem_panel_select(const char *panel_name, struct panel_struct *panelstruct, + struct msm_panel_info *pinfo, struct mdss_dsi_phy_ctrl *phy_db); +#endif + diff --git a/src/soc/qualcomm/sc7180/include/soc/display/target_sc7180.h b/src/soc/qualcomm/sc7180/include/soc/display/target_sc7180.h new file mode 100644 index 0000000..1ca9c1d --- /dev/null +++ b/src/soc/qualcomm/sc7180/include/soc/display/target_sc7180.h @@ -0,0 +1,62 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (c) 2020 Qualcomm Technologies + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _TARGET_DISPLAY_H +#define _TARGET_DISPLAY_H + +#include <soc/display/panel.h> +#include <soc/display/msm_panel.h> + +/*---------------------------------------------------------------------------*/ +/* Target Physical configuration */ +/*---------------------------------------------------------------------------*/ +static const uint32_t panel_strength_ctrl[] = { + 0x55, 0x03, + 0x55, 0x03, + 0x55, 0x03, + 0x55, 0x03, + 0x55, 0x00 +}; + +static const uint32_t panel_regulator_settings[] = { + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d +}; + +static const char panel_lane_config[] = { + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, +}; + +static const char panel_bist_ctrl[] = { }; +static const uint32_t panel_physical_ctrl[] = { }; + +/*---------------------------------------------------------------------------*/ +/* Functions */ +/*---------------------------------------------------------------------------*/ +int target_display_pre_on(void); +int target_display_pre_off(void); +int target_display_post_on(void); +int target_display_post_off(void); +int target_display_get_base_offset(uint32_t base); +int target_backlight_ctrl(uint8_t enable); +int target_set_switch_gpio(int enable_dsi2hdmibridge); +int target_panel_reset(uint8_t enable, struct panel_reset_sequence *resetseq, + struct msm_panel_info *pinfo); +int target_dsi_phy_config(struct mdss_dsi_phy_ctrl *phy_db); +#endif +