target: msm8996: add display target APIs for 8996
Add display target APIs to handle the panel selection,
LDO control, backlight, GPIO, clock configuration
and GCDB display entry/exit.
Change-Id: I10621d5c7d55061e8f8dd4d8f0be55c73b9002d5
diff --git a/target/msm8996/include/target/display.h b/target/msm8996/include/target/display.h
new file mode 100644
index 0000000..eddc0c8
--- /dev/null
+++ b/target/msm8996/include/target/display.h
@@ -0,0 +1,96 @@
+/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef _TARGET_DISPLAY_H
+#define _TARGET_DISPLAY_H
+
+/*---------------------------------------------------------------------------*/
+/* HEADER files */
+/*---------------------------------------------------------------------------*/
+#include <display_resource.h>
+
+/*---------------------------------------------------------------------------*/
+/* Target Physical configuration */
+/*---------------------------------------------------------------------------*/
+
+static const uint32_t panel_strength_ctrl[] = {
+ 0xFF, 0x06,
+ 0xFF, 0x06,
+ 0xFF, 0x06,
+ 0xFF, 0x06,
+ 0xFF, 0x00
+};
+
+static const uint32_t panel_regulator_settings[] = {
+ 0x1d, 0x1d, 0x1d, 0x1d, 0x1d
+};
+
+static const char panel_lane_config[] = {
+ 0x00, 0x00, 0x10, 0x0f,
+ 0x00, 0x00, 0x10, 0x0f,
+ 0x00, 0x00, 0x10, 0x0f,
+ 0x00, 0x00, 0x10, 0x0f,
+ 0x00, 0x00, 0x10, 0x8f,
+};
+
+static const char panel_bist_ctrl[] = { };
+
+static const uint32_t panel_physical_ctrl[] = { };
+/*---------------------------------------------------------------------------*/
+/* Other Configuration */
+/*---------------------------------------------------------------------------*/
+#define DISPLAY_CMDLINE_PREFIX " mdss_mdp.panel="
+
+#define MIPI_FB_ADDR 0x82400000
+
+#define MIPI_HSYNC_PULSE_WIDTH 16
+#define MIPI_HSYNC_BACK_PORCH_DCLK 32
+#define MIPI_HSYNC_FRONT_PORCH_DCLK 76
+
+#define MIPI_VSYNC_PULSE_WIDTH 2
+#define MIPI_VSYNC_BACK_PORCH_LINES 2
+#define MIPI_VSYNC_FRONT_PORCH_LINES 4
+
+#define PWM_BL_LPG_CHAN_ID 4 /* lpg_out<3> */
+
+#define HDMI_PANEL_NAME "hdmi"
+#define HDMI_CONTROLLER_STRING "hdmi:0"
+
+/*---------------------------------------------------------------------------*/
+/* Functions */
+/*---------------------------------------------------------------------------*/
+int target_display_pre_on();
+int target_display_pre_off();
+int target_display_post_on();
+int target_display_post_off();
+int target_cont_splash_screen();
+int target_display_get_base_offset(uint32_t base);
+void target_force_cont_splash_disable(uint8_t override);
+uint8_t target_panel_auto_detect_enabled();
+
+#endif
diff --git a/target/msm8996/init.c b/target/msm8996/init.c
index 18bc82b..6667314 100644
--- a/target/msm8996/init.c
+++ b/target/msm8996/init.c
@@ -282,6 +282,33 @@
/* This is filled from board.c */
}
+static uint8_t splash_override;
+/* Returns 1 if target supports continuous splash screen. */
+int target_cont_splash_screen()
+{
+ uint8_t splash_screen = 0;
+ if(!splash_override) {
+ switch(board_hardware_id())
+ {
+ case HW_PLATFORM_SURF:
+ case HW_PLATFORM_MTP:
+ case HW_PLATFORM_FLUID:
+ dprintf(SPEW, "Target_cont_splash=1\n");
+ splash_screen = 1;
+ break;
+ default:
+ dprintf(SPEW, "Target_cont_splash=0\n");
+ splash_screen = 0;
+ }
+ }
+ return splash_screen;
+}
+
+void target_force_cont_splash_disable(uint8_t override)
+{
+ splash_override = override;
+}
+
/* Detect the modem type */
void target_baseband_detect(struct board_data *board)
{
diff --git a/target/msm8996/oem_panel.c b/target/msm8996/oem_panel.c
new file mode 100644
index 0000000..9f2b600
--- /dev/null
+++ b/target/msm8996/oem_panel.c
@@ -0,0 +1,251 @@
+/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <debug.h>
+#include <string.h>
+#include <err.h>
+#include <smem.h>
+#include <msm_panel.h>
+#include <board.h>
+#include <mipi_dsi.h>
+#include <qtimer.h>
+#include <platform.h>
+
+#include "include/panel.h"
+#include "target/display.h"
+#include "panel_display.h"
+#include <mipi_dsi.h>
+
+/*---------------------------------------------------------------------------*/
+/* GCDB Panel Database */
+/*---------------------------------------------------------------------------*/
+#include "include/panel_sharp_wqxga_dualdsi_video.h"
+#include "include/panel_jdi_qhd_dualdsi_video.h"
+#include "include/panel_jdi_qhd_dualdsi_cmd.h"
+
+/*---------------------------------------------------------------------------*/
+/* static panel selection variable */
+/*---------------------------------------------------------------------------*/
+enum {
+ SHARP_WQXGA_DUALDSI_VIDEO_PANEL,
+ JDI_QHD_DUALDSI_VIDEO_PANEL,
+ JDI_QHD_DUALDSI_CMD_PANEL,
+ UNKNOWN_PANEL
+};
+
+/*
+ * The list of panels that are supported on this target.
+ * Any panel in this list can be selected using fastboot oem command.
+ */
+static struct panel_list supp_panels[] = {
+ {"sharp_wqxga_dualdsi_video", SHARP_WQXGA_DUALDSI_VIDEO_PANEL},
+ {"jdi_qhd_dualdsi_video", JDI_QHD_DUALDSI_VIDEO_PANEL},
+ {"jdi_qhd_dualdsi_cmd", JDI_QHD_DUALDSI_CMD_PANEL},
+};
+
+static uint32_t panel_id;
+
+int oem_panel_rotation()
+{
+ return NO_ERROR;
+}
+
+int oem_panel_on()
+{
+ if (panel_id == JDI_QHD_DUALDSI_CMD_PANEL) {
+ /* needs extra delay to avoid unexpected artifacts */
+ mdelay(JDI_QHD_DUALDSI_CMD_PANEL_ON_DELAY);
+
+ }
+ return NO_ERROR;
+}
+
+int oem_panel_off()
+{
+ return NO_ERROR;
+}
+
+static bool init_panel_data(struct panel_struct *panelstruct,
+ struct msm_panel_info *pinfo,
+ struct mdss_dsi_phy_ctrl *phy_db)
+{
+ int pan_type;
+
+ switch (panel_id) {
+ case SHARP_WQXGA_DUALDSI_VIDEO_PANEL:
+ pan_type = PANEL_TYPE_DSI;
+ pinfo->lcd_reg_en = 0;
+ panelstruct->paneldata = &sharp_wqxga_dualdsi_video_panel_data;
+ panelstruct->paneldata->panel_node_id =
+ "qcom,mdss_dsi_sharp_wqxga_video_0";
+ panelstruct->paneldata->slave_panel_node_id =
+ "qcom,mdss_dsi_sharp_wqxga_video_1";
+ panelstruct->paneldata->panel_operating_mode = 11;
+ panelstruct->paneldata->panel_with_enable_gpio = 0;
+
+ panelstruct->panelres = &sharp_wqxga_dualdsi_video_panel_res;
+ panelstruct->color = &sharp_wqxga_dualdsi_video_color;
+ panelstruct->videopanel = &sharp_wqxga_dualdsi_video_video_panel;
+ panelstruct->commandpanel = &sharp_wqxga_dualdsi_video_command_panel;
+ panelstruct->state = &sharp_wqxga_dualdsi_video_state;
+ panelstruct->laneconfig = &sharp_wqxga_dualdsi_video_lane_config;
+ panelstruct->paneltiminginfo
+ = &sharp_wqxga_dualdsi_video_timing_info;
+ panelstruct->panelresetseq
+ = &sharp_wqxga_dualdsi_video_reset_seq;
+ panelstruct->backlightinfo = &sharp_wqxga_dualdsi_video_backlight;
+
+ pinfo->labibb = &sharp_wqxga_dualdsi_video_labibb;
+
+ pinfo->mipi.panel_on_cmds
+ = sharp_wqxga_dualdsi_video_on_command;
+ pinfo->mipi.num_of_panel_on_cmds
+ = SHARP_WQXGA_DUALDSI_VIDEO_ON_COMMAND;
+ pinfo->mipi.panel_off_cmds
+ = sharp_wqxga_dualdsi_video_off_command;
+ pinfo->mipi.num_of_panel_off_cmds
+ = SHARP_WQXGA_DUALDSI_VIDEO_OFF_COMMAND;
+ memcpy(phy_db->timing,
+ sharp_wqxga_dualdsi_thulium_video_timings,
+ MAX_TIMING_CONFIG * sizeof(uint32_t));
+ pinfo->mipi.tx_eot_append = true;
+ break;
+ case JDI_QHD_DUALDSI_VIDEO_PANEL:
+ pan_type = PANEL_TYPE_DSI;
+ pinfo->lcd_reg_en = 1;
+ panelstruct->paneldata->panel_node_id =
+ "qcom,dsi_jdi_qhd_video_0";
+ panelstruct->paneldata->slave_panel_node_id =
+ "qcom,dsi_jdi_qhd_video_1";
+ panelstruct->paneldata = &jdi_qhd_dualdsi_video_panel_data;
+
+ panelstruct->panelres = &jdi_qhd_dualdsi_video_panel_res;
+ panelstruct->color = &jdi_qhd_dualdsi_video_color;
+ panelstruct->videopanel = &jdi_qhd_dualdsi_video_video_panel;
+ panelstruct->commandpanel = &jdi_qhd_dualdsi_video_command_panel;
+ panelstruct->state = &jdi_qhd_dualdsi_video_state;
+ panelstruct->laneconfig = &jdi_qhd_dualdsi_video_lane_config;
+ panelstruct->paneltiminginfo
+ = &jdi_qhd_dualdsi_video_timing_info;
+ panelstruct->panelresetseq
+ = &jdi_qhd_dualdsi_video_reset_seq;
+ panelstruct->backlightinfo = &jdi_qhd_dualdsi_video_backlight;
+ pinfo->mipi.panel_on_cmds
+ = jdi_qhd_dualdsi_video_on_command;
+ pinfo->mipi.num_of_panel_on_cmds
+ = JDI_QHD_DUALDSI_VIDEO_ON_COMMAND;
+ pinfo->mipi.panel_off_cmds
+ = jdi_qhd_dualdsi_video_off_command;
+ pinfo->mipi.num_of_panel_off_cmds
+ = JDI_QHD_DUALDSI_VIDEO_OFF_COMMAND;
+ memcpy(phy_db->timing,
+ jdi_qhd_dualdsi_thulium_cmd_timings,
+ MAX_TIMING_CONFIG * sizeof(uint32_t));
+ break;
+ case JDI_QHD_DUALDSI_CMD_PANEL:
+ pan_type = PANEL_TYPE_DSI;
+ pinfo->lcd_reg_en = 1;
+ panelstruct->paneldata = &jdi_qhd_dualdsi_cmd_panel_data;
+ panelstruct->paneldata->panel_node_id =
+ "qcom,mdss_dsi_jdi_qhd_dualmipi0_cmd";
+ panelstruct->paneldata->slave_panel_node_id =
+ "qcom,mdss_dsi_jdi_qhd_dualmipi1_cmd";
+
+ panelstruct->panelres = &jdi_qhd_dualdsi_cmd_panel_res;
+ panelstruct->color = &jdi_qhd_dualdsi_cmd_color;
+ panelstruct->videopanel = &jdi_qhd_dualdsi_cmd_video_panel;
+ panelstruct->commandpanel = &jdi_qhd_dualdsi_cmd_command_panel;
+ panelstruct->state = &jdi_qhd_dualdsi_cmd_state;
+ panelstruct->laneconfig = &jdi_qhd_dualdsi_cmd_lane_config;
+ panelstruct->paneltiminginfo
+ = &jdi_qhd_dualdsi_cmd_timing_info;
+ panelstruct->panelresetseq
+ = &jdi_qhd_dualdsi_cmd_reset_seq;
+ panelstruct->backlightinfo = &jdi_qhd_dualdsi_cmd_backlight;
+ pinfo->mipi.panel_on_cmds
+ = jdi_qhd_dualdsi_cmd_on_command;
+ pinfo->mipi.num_of_panel_on_cmds
+ = JDI_QHD_DUALDSI_CMD_ON_COMMAND;
+ pinfo->mipi.panel_off_cmds
+ = jdi_qhd_dualdsi_cmd_off_command;
+ pinfo->mipi.num_of_panel_off_cmds
+ = JDI_QHD_DUALDSI_CMD_OFF_COMMAND;
+ memcpy(phy_db->timing,
+ jdi_qhd_dualdsi_thulium_video_timings,
+ MAX_TIMING_CONFIG * sizeof(uint32_t));
+ break;
+ default:
+ case UNKNOWN_PANEL:
+ pan_type = PANEL_TYPE_UNKNOWN;
+ break;
+ }
+ return pan_type;
+}
+
+int oem_panel_select(const char *panel_name, struct panel_struct *panelstruct,
+ struct msm_panel_info *pinfo,
+ struct mdss_dsi_phy_ctrl *phy_db)
+{
+ uint32_t hw_id = board_hardware_id();
+ int32_t panel_override_id;
+
+ phy_db->pll_type = DSI_PLL_TYPE_THULIUM;
+
+ if (panel_name) {
+ panel_override_id = panel_name_to_id(supp_panels,
+ ARRAY_SIZE(supp_panels), panel_name);
+
+ if (panel_override_id < 0) {
+ dprintf(CRITICAL, "Not able to search the panel:%s\n",
+ panel_name + strspn(panel_name, " "));
+ } else if (panel_override_id < UNKNOWN_PANEL) {
+ /* panel override using fastboot oem command */
+ panel_id = panel_override_id;
+
+ dprintf(INFO, "OEM panel override:%s\n",
+ panel_name + strspn(panel_name, " "));
+ goto panel_init;
+ }
+ }
+
+ switch (hw_id) {
+ case HW_PLATFORM_MTP:
+ case HW_PLATFORM_FLUID:
+ case HW_PLATFORM_SURF:
+ panel_id = SHARP_WQXGA_DUALDSI_VIDEO_PANEL;
+ break;
+ default:
+ dprintf(CRITICAL, "Display not enabled for %d HW type\n"
+ , hw_id);
+ return PANEL_TYPE_UNKNOWN;
+ }
+
+panel_init:
+ return init_panel_data(panelstruct, pinfo, phy_db);
+}
diff --git a/target/msm8996/target_display.c b/target/msm8996/target_display.c
new file mode 100644
index 0000000..f9f3a5b
--- /dev/null
+++ b/target/msm8996/target_display.c
@@ -0,0 +1,515 @@
+/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <debug.h>
+#include <string.h>
+#include <smem.h>
+#include <err.h>
+#include <msm_panel.h>
+#include <mipi_dsi.h>
+#include <pm8x41.h>
+#include <pm8x41_wled.h>
+#include <qpnp_wled.h>
+#include <board.h>
+#include <mdp5.h>
+#include <endian.h>
+#include <regulator.h>
+#include <qtimer.h>
+#include <arch/defines.h>
+#include <platform/gpio.h>
+#include <platform/clock.h>
+#include <platform/iomap.h>
+#include <target/display.h>
+#include <mipi_dsi_autopll_thulium.h>
+
+#include "include/panel.h"
+#include "include/display_resource.h"
+#include "gcdb_display.h"
+
+#define GPIO_STATE_LOW 0
+#define GPIO_STATE_HIGH 2
+#define RESET_GPIO_SEQ_LEN 3
+
+#define PWM_DUTY_US 13
+#define PWM_PERIOD_US 27
+#define PMIC_WLED_SLAVE_ID 3
+#define PMIC_MPP_SLAVE_ID 2
+
+#define MAX_POLL_READS 15
+#define POLL_TIMEOUT_US 1000
+
+#define STRENGTH_SIZE_IN_BYTES_8996 10
+#define REGULATOR_SIZE_IN_BYTES_8996 5
+#define LANE_SIZE_IN_BYTES_8996 20
+
+/*---------------------------------------------------------------------------*/
+/* GPIO configuration */
+/*---------------------------------------------------------------------------*/
+static struct gpio_pin reset_gpio = {
+ "msmgpio", 8, 3, 1, 0, 1
+};
+
+static struct gpio_pin lcd_reg_en = { /* boost regulator */
+ "pmi8994_gpios", 8, 3, 1, 0, 1
+};
+
+static struct gpio_pin bklt_gpio = { /* lcd_bklt_reg_en */
+ "pm8994_gpios", 14, 3, 1, 0, 1
+};
+
+static uint32_t thulium_dsi_pll_lock_status(uint32_t pll_base, uint32_t off,
+ uint32_t bit)
+{
+ uint32_t cnt, status;
+
+ /* check pll lock first */
+ for (cnt = 0; cnt < MAX_POLL_READS; cnt++) {
+ status = readl(pll_base + off);
+ dprintf(SPEW, "%s: pll_base=%x cnt=%d status=%x\n",
+ __func__, pll_base, cnt, status);
+ status &= BIT(bit); /* bit 5 */
+ if (status)
+ break;
+ udelay(POLL_TIMEOUT_US);
+ }
+
+ return status;
+}
+
+static uint32_t thulium_dsi_pll_enable_seq(uint32_t phy_base, uint32_t pll_base)
+{
+ uint32_t pll_locked;
+
+ writel(0x01, phy_base + 0x48);
+ dmb();
+
+ pll_locked = thulium_dsi_pll_lock_status(pll_base, 0xcc, 5);
+ if (pll_locked)
+ pll_locked = thulium_dsi_pll_lock_status(pll_base, 0xcc, 0);
+
+ if (!pll_locked)
+ dprintf(ERROR, "%s: DSI PLL lock failed\n", __func__);
+ else
+ dprintf(SPEW, "%s: DSI PLL lock Success\n", __func__);
+
+ return pll_locked;
+}
+
+static int thulium_wled_backlight_ctrl(uint8_t enable)
+{
+ qpnp_wled_enable_backlight(enable);
+ qpnp_ibb_enable(enable);
+ return NO_ERROR;
+}
+
+static int thulium_pwm_backlight_ctrl(uint8_t enable)
+{
+ uint8_t slave_id = 3; /* lpg at pmi */
+
+ if (enable) {
+ /* lpg channel 4 */
+
+ /* LPG_ENABLE_CONTROL */
+ pm8x41_lpg_write_sid(slave_id, PWM_BL_LPG_CHAN_ID, 0x46, 0x0);
+ mdelay(100);
+
+ /* LPG_VALUE_LSB, duty cycle = 0x80/0x200 = 1/4 */
+ pm8x41_lpg_write_sid(slave_id, PWM_BL_LPG_CHAN_ID, 0x44, 0x80);
+ /* LPG_VALUE_MSB */
+ pm8x41_lpg_write_sid(slave_id, PWM_BL_LPG_CHAN_ID, 0x45, 0x00);
+ /* LPG_PWM_SYNC */
+ pm8x41_lpg_write_sid(slave_id, PWM_BL_LPG_CHAN_ID, 0x47, 0x01);
+
+ /* LPG_PWM_SIZE_CLK, */
+ pm8x41_lpg_write_sid(slave_id, PWM_BL_LPG_CHAN_ID, 0x41, 0x13);
+ /* LPG_PWM_FREQ_PREDIV */
+ pm8x41_lpg_write_sid(slave_id, PWM_BL_LPG_CHAN_ID, 0x42, 0x02);
+ /* LPG_PWM_TYPE_CONFIG */
+ pm8x41_lpg_write_sid(slave_id, PWM_BL_LPG_CHAN_ID, 0x43, 0x20);
+ /* LPG_ENABLE_CONTROL */
+ pm8x41_lpg_write_sid(slave_id, PWM_BL_LPG_CHAN_ID, 0x46, 0x04);
+
+ /* SEC_ACCESS */
+ pm8x41_lpg_write_sid(slave_id, PWM_BL_LPG_CHAN_ID, 0xD0, 0xA5);
+ /* DTEST4, OUT_HI */
+ pm8x41_lpg_write_sid(slave_id, PWM_BL_LPG_CHAN_ID, 0xE5, 0x01);
+ /* LPG_ENABLE_CONTROL */
+ pm8x41_lpg_write_sid(slave_id, PWM_BL_LPG_CHAN_ID, 0x46, 0xA4);
+ } else {
+ /* LPG_ENABLE_CONTROL */
+ pm8x41_lpg_write_sid(slave_id, PWM_BL_LPG_CHAN_ID, 0x46, 0x0);
+ }
+
+ return NO_ERROR;
+}
+
+static void lcd_reg_enable(void)
+{
+ uint8_t slave_id = 2; /* gpio at pmi */
+
+ struct pm8x41_gpio gpio = {
+ .direction = PM_GPIO_DIR_OUT,
+ .function = PM_GPIO_FUNC_HIGH,
+ .vin_sel = 2, /* VIN_2 */
+ .output_buffer = PM_GPIO_OUT_CMOS,
+ .out_strength = PM_GPIO_OUT_DRIVE_MED,
+ };
+
+ pm8x41_gpio_config_sid(slave_id, lcd_reg_en.pin_id, &gpio);
+ pm8x41_gpio_set_sid(slave_id, lcd_reg_en.pin_id, 1);
+}
+
+static void lcd_reg_disable(void)
+{
+ uint8_t slave_id = 2; /* gpio at pmi */
+
+ pm8x41_gpio_set_sid(slave_id, lcd_reg_en.pin_id, 0);
+}
+
+static void lcd_bklt_reg_enable(void)
+{
+ struct pm8x41_gpio gpio = {
+ .direction = PM_GPIO_DIR_OUT,
+ .function = PM_GPIO_FUNC_HIGH,
+ .vin_sel = 2, /* VIN_2 */
+ .output_buffer = PM_GPIO_OUT_CMOS,
+ .out_strength = PM_GPIO_OUT_DRIVE_LOW,
+ };
+
+ pm8x41_gpio_config(bklt_gpio.pin_id, &gpio);
+ pm8x41_gpio_set(bklt_gpio.pin_id, 1);
+}
+
+static void lcd_bklt_reg_disable(void)
+{
+ pm8x41_gpio_set(bklt_gpio.pin_id, 0);
+}
+
+int target_backlight_ctrl(struct backlight *bl, uint8_t enable)
+{
+ uint32_t ret = NO_ERROR;
+ struct pm8x41_mpp mpp;
+ int rc;
+
+ if (!bl) {
+ dprintf(CRITICAL, "backlight structure is not available\n");
+ return ERR_INVALID_ARGS;
+ }
+
+ switch (bl->bl_interface_type) {
+ case BL_WLED:
+ /* Enable MPP4 */
+ pmi8994_config_mpp_slave_id(PMIC_MPP_SLAVE_ID);
+ mpp.base = PM8x41_MMP4_BASE;
+ mpp.vin = MPP_VIN2;
+ if (enable) {
+ pm_pwm_enable(false);
+ rc = pm_pwm_config(PWM_DUTY_US, PWM_PERIOD_US);
+ if (rc < 0) {
+ mpp.mode = MPP_HIGH;
+ } else {
+ mpp.mode = MPP_DTEST1;
+ pm_pwm_enable(true);
+ }
+ pm8x41_config_output_mpp(&mpp);
+ pm8x41_enable_mpp(&mpp, MPP_ENABLE);
+ } else {
+ pm_pwm_enable(false);
+ pm8x41_enable_mpp(&mpp, MPP_DISABLE);
+ }
+ /* Need delay before power on regulators */
+ mdelay(20);
+ /* Enable WLED backlight control */
+ ret = thulium_wled_backlight_ctrl(enable);
+ break;
+ case BL_PWM:
+ /* Enable MPP1 */
+ pmi8994_config_mpp_slave_id(PMIC_MPP_SLAVE_ID);
+ mpp.base = PM8x41_MMP1_BASE;
+ mpp.vin = MPP_VIN2;
+ mpp.mode = MPP_DTEST4;
+ if (enable) {
+ pm8x41_config_output_mpp(&mpp);
+ pm8x41_enable_mpp(&mpp, MPP_ENABLE);
+ } else {
+ pm8x41_enable_mpp(&mpp, MPP_DISABLE);
+ }
+ /* Need delay before power on regulators */
+ mdelay(20);
+ ret = thulium_pwm_backlight_ctrl(enable);
+ break;
+ default:
+ dprintf(CRITICAL, "backlight type:%d not supported\n",
+ bl->bl_interface_type);
+ return ERR_NOT_SUPPORTED;
+ }
+
+ return ret;
+}
+
+int target_panel_clock(uint8_t enable, struct msm_panel_info *pinfo)
+{
+ uint32_t flags;
+ uint32_t ret = NO_ERROR;
+ uint32_t board_version = board_soc_version();
+
+ if (pinfo->dest == DISPLAY_2) {
+ flags = MMSS_DSI_CLKS_FLAG_DSI1;
+ if (pinfo->mipi.dual_dsi)
+ flags |= MMSS_DSI_CLKS_FLAG_DSI0;
+ } else {
+ flags = MMSS_DSI_CLKS_FLAG_DSI0;
+ if (pinfo->mipi.dual_dsi)
+ flags |= MMSS_DSI_CLKS_FLAG_DSI1;
+ }
+
+ if (!enable) {
+ /* stop pll */
+ writel(0x0, pinfo->mipi.phy_base + 0x48);
+ dmb();
+
+ mmss_dsi_clock_disable(flags);
+ goto clks_disable;
+ }
+
+ if (board_version == 0x20000 || board_version == 0x20001)
+ video_gdsc_enable();
+ mmss_gdsc_enable();
+ mmss_bus_clock_enable();
+ mdp_clock_enable();
+ mdss_dsi_auto_pll_thulium_config(pinfo);
+
+ if (!thulium_dsi_pll_enable_seq(pinfo->mipi.phy_base,
+ pinfo->mipi.pll_base)) {
+ ret = ERROR;
+ dprintf(CRITICAL, "PLL failed to lock!\n");
+ goto clks_disable;
+ }
+ mmss_dsi_clock_enable(DSI0_PHY_PLL_OUT, flags);
+ return NO_ERROR;
+
+clks_disable:
+ mdp_clock_disable();
+ mmss_bus_clock_disable();
+ mmss_gdsc_disable();
+ if (board_version == 0x20000 || board_version == 0x20001)
+ video_gdsc_disable();
+
+ return ret;
+}
+
+int target_panel_reset(uint8_t enable, struct panel_reset_sequence *resetseq,
+ struct msm_panel_info *pinfo)
+{
+ uint32_t i = 0;
+
+ if (enable) {
+ gpio_tlmm_config(reset_gpio.pin_id, 0,
+ reset_gpio.pin_direction, reset_gpio.pin_pull,
+ reset_gpio.pin_strength, reset_gpio.pin_state);
+ /* reset */
+ for (i = 0; i < RESET_GPIO_SEQ_LEN; i++) {
+ if (resetseq->pin_state[i] == GPIO_STATE_LOW)
+ gpio_set(reset_gpio.pin_id, GPIO_STATE_LOW);
+ else
+ gpio_set(reset_gpio.pin_id, GPIO_STATE_HIGH);
+ mdelay(resetseq->sleep[i]);
+ }
+ lcd_bklt_reg_enable();
+ } else {
+ lcd_bklt_reg_disable();
+ gpio_set(reset_gpio.pin_id, 0);
+ }
+
+ return NO_ERROR;
+}
+
+static void wled_init(struct msm_panel_info *pinfo)
+{
+ struct qpnp_wled_config_data config = {0};
+ struct labibb_desc *labibb;
+ int display_type = 0;
+
+ labibb = pinfo->labibb;
+
+ if (labibb)
+ display_type = labibb->amoled_panel;
+
+ config.display_type = display_type;
+ config.lab_init_volt = 4600000; /* fixed, see pmi register */
+ config.ibb_init_volt = 1400000; /* fixed, see pmi register */
+
+ if (labibb && labibb->force_config) {
+ config.lab_min_volt = labibb->lab_min_volt;
+ config.lab_max_volt = labibb->lab_max_volt;
+ config.ibb_min_volt = labibb->ibb_min_volt;
+ config.ibb_max_volt = labibb->ibb_max_volt;
+ config.pwr_up_delay = labibb->pwr_up_delay;
+ config.pwr_down_delay = labibb->pwr_down_delay;
+ config.ibb_discharge_en = labibb->ibb_discharge_en;
+ } else {
+ /* default */
+ config.pwr_up_delay = 3;
+ config.pwr_down_delay = 3;
+ config.ibb_discharge_en = 1;
+ if (display_type) { /* amoled */
+ config.lab_min_volt = 4600000;
+ config.lab_max_volt = 4600000;
+ config.ibb_min_volt = 4000000;
+ config.ibb_max_volt = 4000000;
+ } else { /* lcd */
+ config.lab_min_volt = 5500000;
+ config.lab_max_volt = 5500000;
+ config.ibb_min_volt = 5500000;
+ config.ibb_max_volt = 5500000;
+ }
+ }
+
+ dprintf(SPEW, "%s: %d %d %d %d %d %d %d %d %d %d\n", __func__,
+ config.display_type,
+ config.lab_min_volt, config.lab_max_volt,
+ config.ibb_min_volt, config.ibb_max_volt,
+ config.lab_init_volt, config.ibb_init_volt,
+ config.pwr_up_delay, config.pwr_down_delay,
+ config.ibb_discharge_en);
+
+
+ /* QPNP WLED init for display backlight */
+ pm8x41_wled_config_slave_id(PMIC_WLED_SLAVE_ID);
+
+ qpnp_wled_init(&config);
+}
+
+int target_ldo_ctrl(uint8_t enable, struct msm_panel_info *pinfo)
+{
+ uint32_t val = BIT(1) | BIT(13) | BIT(27);
+
+ if (enable) {
+ regulator_enable(val);
+ mdelay(10);
+ wled_init(pinfo);
+ qpnp_ibb_enable(true); /* +5V and -5V */
+ mdelay(50);
+
+ if (pinfo->lcd_reg_en)
+ lcd_reg_enable();
+ } else {
+ if (pinfo->lcd_reg_en)
+ lcd_reg_disable();
+
+ regulator_disable(val);
+ }
+
+ return NO_ERROR;
+}
+
+int target_display_pre_on()
+{
+ writel(0xC0000CCC, MDP_CLK_CTRL0);
+ writel(0xC0000CCC, MDP_CLK_CTRL1);
+ writel(0x00CCCCCC, MDP_CLK_CTRL2);
+ writel(0x000000CC, MDP_CLK_CTRL6);
+ writel(0x0CCCC0C0, MDP_CLK_CTRL3);
+ writel(0xCCCCC0C0, MDP_CLK_CTRL4);
+ writel(0xCCCCC0C0, MDP_CLK_CTRL5);
+ writel(0x00CCC000, MDP_CLK_CTRL7);
+
+ return NO_ERROR;
+}
+
+int target_dsi_phy_config(struct mdss_dsi_phy_ctrl *phy_db)
+{
+ memcpy(phy_db->strength, panel_strength_ctrl, STRENGTH_SIZE_IN_BYTES_8996 *
+ sizeof(uint32_t));
+ memcpy(phy_db->regulator, panel_regulator_settings,
+ REGULATOR_SIZE_IN_BYTES_8996 * sizeof(uint32_t));
+ memcpy(phy_db->laneCfg, panel_lane_config, LANE_SIZE_IN_BYTES_8996);
+ return NO_ERROR;
+}
+
+
+bool target_display_panel_node(char *panel_name, char *pbuf, uint16_t buf_size)
+{
+ int prefix_string_len = strlen(DISPLAY_CMDLINE_PREFIX);
+ bool ret = true;
+
+ panel_name += strspn(panel_name, " ");
+
+ if (!strcmp(panel_name, HDMI_PANEL_NAME)) {
+ if (buf_size < (prefix_string_len + LK_OVERRIDE_PANEL_LEN +
+ strlen(HDMI_CONTROLLER_STRING))) {
+ dprintf(CRITICAL, "command line argument is greater than buffer size\n");
+ return false;
+ }
+
+ strlcpy(pbuf, DISPLAY_CMDLINE_PREFIX, buf_size);
+ buf_size -= prefix_string_len;
+ strlcat(pbuf, LK_OVERRIDE_PANEL, buf_size);
+ buf_size -= LK_OVERRIDE_PANEL_LEN;
+ strlcat(pbuf, HDMI_CONTROLLER_STRING, buf_size);
+ } else {
+ ret = gcdb_display_cmdline_arg(panel_name, pbuf, buf_size);
+ }
+
+ return ret;
+}
+
+void target_display_init(const char *panel_name)
+{
+ char cont_splash = '\0';
+
+ set_panel_cmd_string(panel_name, &cont_splash);
+ panel_name += strspn(panel_name, " ");
+ if (!strcmp(panel_name, NO_PANEL_CONFIG)
+ || !strcmp(panel_name, SIM_VIDEO_PANEL)
+ || !strcmp(panel_name, SIM_DUALDSI_VIDEO_PANEL)
+ || !strcmp(panel_name, SIM_CMD_PANEL)
+ || !strcmp(panel_name, SIM_DUALDSI_CMD_PANEL)) {
+ dprintf(INFO, "Selected panel: %s\nSkip panel configuration\n",
+ panel_name);
+ return;
+ } else if (!strcmp(panel_name, HDMI_PANEL_NAME)) {
+ return;
+ }
+
+ if (gcdb_display_init(panel_name, MDP_REV_50, (void *)MIPI_FB_ADDR)) {
+ target_force_cont_splash_disable(true);
+ msm_display_off();
+ }
+
+ if (cont_splash == '0') {
+ dprintf(INFO, "Forcing continuous splash disable\n");
+ target_force_cont_splash_disable(true);
+ }
+}
+
+void target_display_shutdown(void)
+{
+ gcdb_display_shutdown();
+}