platform: msm_shared: enable different panel configuration modes

Add support to specify multiple working configurations for a given
panel. Choose the default configuration through target specific oem panel
module. Add support to select non-default configuration, if supported by
given panel, through "fastboot oem select-display-panel". Add support to
convey selected lk config to kernel by modifying kernel command line.

Ex:
fastboot oem select-display-panel nt35597_wqxga_dsc_video
fastboot oem select-display-panel nt35597_wqxga_dsc_video:cfg[0..2]
fastboot oem select-display-panel nt35597_wqxga_dsc_video:cfg[0..2]#sim

fastboot oem select-display-panel nt35597_wqxga_dsc_cmd
fastboot oem select-display-panel nt35597_wqxga_dsc_cmd:cfg[0..2]
fastboot oem select-display-panel nt35597_wqxga_dsc_cmd:cfg[0..2]#sim

Change-Id: I39f4434b5d8f81229dfc95990b558efaab382c8d
diff --git a/dev/gcdb/display/gcdb_display.c b/dev/gcdb/display/gcdb_display.c
index a847aaa..26bbe90 100644
--- a/dev/gcdb/display/gcdb_display.c
+++ b/dev/gcdb/display/gcdb_display.c
@@ -487,6 +487,20 @@
 	pan_type = oem_panel_select(panel_name, &panelstruct, &(panel.panel_info),
 				 &dsi_video_mode_phy_db);
 
+	if ((panel.panel_info.lm_split[0] > 0) &&
+	    (panel.panel_info.lm_split[1] > 0))
+		panelstruct.paneldata->panel_operating_mode |= DUAL_PIPE_FLAG;
+
+	if (panelstruct.paneldata->panel_operating_mode & DUAL_PIPE_FLAG) {
+		if ((panel.panel_info.lm_split[0] <= 0) ||
+		    (panel.panel_info.lm_split[1] <= 0)) {
+			panel.panel_info.lm_split[0] =
+				panelstruct.panelres->panel_width / 2;
+			panel.panel_info.lm_split[1] =
+				panel.panel_info.lm_split[0];
+		}
+	}
+
 	if (pan_type == PANEL_TYPE_DSI) {
 		target_dsi_phy_config(&dsi_video_mode_phy_db);
 		mdss_dsi_check_swap_status();
diff --git a/dev/gcdb/display/gcdb_display.h b/dev/gcdb/display/gcdb_display.h
index aaed691..a4f1685 100755
--- a/dev/gcdb/display/gcdb_display.h
+++ b/dev/gcdb/display/gcdb_display.h
@@ -76,6 +76,8 @@
 	uint32_t sim_mode;
 	char dsi_config[DSI_CFG_SIZE];
 	uint32_t dsi_pll_src;
+	/* If dual-DSI, slave cfg will use 2nd index */
+	int cfg_num[2]; /* -ve number means no overide */
 };
 
 enum {
diff --git a/dev/gcdb/display/gcdb_display_param.c b/dev/gcdb/display/gcdb_display_param.c
index 7d189a5..44b3454 100644
--- a/dev/gcdb/display/gcdb_display_param.c
+++ b/dev/gcdb/display/gcdb_display_param.c
@@ -38,7 +38,7 @@
 #include "fastboot_oem_display.h"
 
 struct oem_panel_data oem_data = {{'\0'}, {'\0'}, false, false, false, SIM_NONE,
-	"single_dsi", DSI_PLL_DEFAULT};
+	"single_dsi", DSI_PLL_DEFAULT, {-1, -1}};
 
 static int panel_name_to_dt_string(struct panel_lookup_list supp_panels[],
 			  uint32_t supp_panels_size,
@@ -186,8 +186,20 @@
 		for (i = 0; (ch + i) < ch_tmp; i++)
 			oem_data.sec_panel[i] = *(ch + i);
 		oem_data.sec_panel[i] = '\0';
+
+		/* Topology configuration for secondary panel */
+		ch_tmp = strstr((char *) ch, ":cfg");
+		if (ch_tmp)
+			oem_data.cfg_num[1] = atoi((const char*)(ch_tmp + 4));
+	} else {
+		oem_data.sec_panel[0] = '\0';
 	}
 
+	/* Topology configuration for primary panel */
+	ch_tmp = strstr((char *) panel_name, ":cfg");
+	if (ch_tmp && (!ch || (ch && (ch_tmp < ch))))
+		oem_data.cfg_num[0] = atoi((const char*)(ch_tmp + 4));
+
 	/* Skip LK configuration */
 	ch = strstr((char *) panel_name, ":skip");
 	oem_data.skip = ch ? true : false;
@@ -222,7 +234,6 @@
 	/* disable cont splash when booting in simulator mode */
 	if (oem_data.sim_mode)
 		oem_data.cont_splash = false;
-
 }
 
 static bool mdss_dsi_set_panel_node(char *panel_name, char **dsi_id,
@@ -284,6 +295,8 @@
 	int panel_mode = SPLIT_DISPLAY_FLAG | DUAL_PIPE_FLAG | DST_SPLIT_FLAG;
 	int prefix_string_len = strlen(DISPLAY_CMDLINE_PREFIX);
 	char *sctl_string, *pll_src_string = NULL;
+	char prim_cfg_name[10]="\0", slave_cfg_name[10]="\0"; /* config[0-99] */
+	char *display_cmd_line = pbuf;
 
 	panelstruct = mdss_dsi_get_panel_data();
 
@@ -332,7 +345,7 @@
 
 	if (((panel_mode & SPLIT_DISPLAY_FLAG) ||
 	     (panel_mode & DST_SPLIT_FLAG)) && slave_panel_node == NULL) {
-		dprintf(CRITICAL, "slave node not present in dual dsi case\n");
+		dprintf(CRITICAL, "slave node not present in split-dsi case\n");
 		return false;
 	}
 
@@ -413,6 +426,40 @@
 		}
 	}
 
+	dprintf(SPEW, "dsi_cfg:%s mdp_cfg[0]=%d mdp_cfg[1]=%d\n",
+		oem_data.dsi_config, oem_data.cfg_num[0], oem_data.cfg_num[1]);
+
+	if ((oem_data.cfg_num[0] >= 0) && (oem_data.cfg_num[0] < 100)) {
+		snprintf(prim_cfg_name, sizeof(prim_cfg_name),
+			":config%d", oem_data.cfg_num[0]);
+		arg_size += strlen(prim_cfg_name);
+	} else if (panelstruct.config != NULL) {
+		/*
+		 * if oem command wasn't set then take topology config
+		 * used by per target oem panel driver if available.
+		 */
+		snprintf(prim_cfg_name, sizeof(prim_cfg_name),
+			":%s", panelstruct.config->config_name);
+		arg_size += strlen(prim_cfg_name);
+	}
+
+	/* in split-dsi, primary and slave panel share same topology config */
+	if (!strcmp(oem_data.dsi_config, "split_dsi"))
+		snprintf(slave_cfg_name, sizeof(slave_cfg_name),
+			"%s", prim_cfg_name);
+
+	if (!strcmp(oem_data.dsi_config, "dual_dsi")) {
+		if ((oem_data.cfg_num[1] >= 0) && (oem_data.cfg_num[1] < 100)) {
+			snprintf(slave_cfg_name, sizeof(slave_cfg_name),
+				":config%d", oem_data.cfg_num[1]);
+			arg_size += strlen(slave_cfg_name);
+		}
+		/*
+		 * In dual-dsi, secondary or slave panels isn't supported
+		 * in bootloader so "else" case like above is not possible.
+		 */
+	}
+
 	if (buf_size < arg_size) {
 		dprintf(CRITICAL, "display command line buffer is small\n");
 		ret = false;
@@ -433,6 +480,13 @@
 		pbuf += panel_node_len;
 		buf_size -= panel_node_len;
 
+		/* writeout primary topology config */
+		if (strlen(prim_cfg_name) > 0) {
+			strlcpy(pbuf, prim_cfg_name, buf_size);
+			pbuf += strlen(prim_cfg_name);
+			buf_size -= strlen(prim_cfg_name);
+		}
+
 		strlcpy(pbuf, sctl_string, buf_size);
 		pbuf += strlen(sctl_string);
 		buf_size -= strlen(sctl_string);
@@ -441,6 +495,13 @@
 		pbuf += slave_panel_node_len;
 		buf_size -= slave_panel_node_len;
 
+		/* writeout slave panel, split-dsi, or secondary panel, dual-dsi, topology config */
+		if (strlen(slave_cfg_name) > 0) {
+			strlcpy(pbuf, slave_cfg_name, buf_size);
+			pbuf += strlen(slave_cfg_name);
+			buf_size -= strlen(slave_cfg_name);
+		}
+
 		strlcpy(pbuf, DSI_CFG_STRING, buf_size);
 		pbuf += DSI_CFG_STRING_LEN;
 		buf_size -= DSI_CFG_STRING_LEN;
@@ -464,6 +525,9 @@
 			pbuf += strlen(sim_mode_string);
 			buf_size -= strlen(sim_mode_string);
 		}
+
+		dprintf(INFO, "display kernel cmdline:%s\n",
+			display_cmd_line);
 	}
 	return ret;
 }
diff --git a/dev/gcdb/display/include/panel.h b/dev/gcdb/display/include/panel.h
index c9aee8b..05a79e2 100755
--- a/dev/gcdb/display/include/panel.h
+++ b/dev/gcdb/display/include/panel.h
@@ -219,7 +219,17 @@
 	uint32_t block_prediction;
 	uint32_t ich_reset_override;
 	uint32_t ich_reset_value;
-	uint32_t data_path_mode;
+};
+
+struct topology_config {
+	char *config_name; /* matches with kernel cmdline */
+	/*
+	 * lm_split: -ve value means that lm_split is not used.
+	 *           If lm_split is used then DUAL_PIPE flag will be added.
+	 */
+	int lm_split[2];
+	int num_dsc_enc; /* how many encoder to use */
+	struct dsc_parameters *dsc;
 };
 
 #endif /*_PANEL_H_ */
diff --git a/dev/gcdb/display/include/panel_nt35597_wqxga_dsc_cmd.h b/dev/gcdb/display/include/panel_nt35597_wqxga_dsc_cmd.h
index b059bb3..084b983 100644
--- a/dev/gcdb/display/include/panel_nt35597_wqxga_dsc_cmd.h
+++ b/dev/gcdb/display/include/panel_nt35597_wqxga_dsc_cmd.h
@@ -332,8 +332,23 @@
 /*---------------------------------------------------------------------------*/
 /* DSC									     */
 /*---------------------------------------------------------------------------*/
-static const struct dsc_parameters nt35597_wqxga_dsc_cmd_paras = {
-	1, 0, 0, 16, 720, 8, 8, 2, 1, 0, 0, 0
+struct dsc_parameters nt35597_wqxga_dsc_cmd_params0 = {
+	1, 0, 0, 16, 720, 8, 8, 2, 1, 0, 0
+};
+
+/* 1LM + 1 DSC_ENC */
+struct topology_config nt35597_wqxga_dsc_cmd_config0 = {
+	"config0", {-1, -1}, 1, &nt35597_wqxga_dsc_cmd_params0
+};
+
+/* 2LM + 3D Mux + 1 DSC_ENC */
+struct topology_config nt35597_wqxga_dsc_cmd_config1 = {
+	"config1", {720, 720}, 1, &nt35597_wqxga_dsc_cmd_params0
+};
+
+/* 2LM + 2 DSC_ENC + DSC_MERGE */
+struct topology_config nt35597_wqxga_dsc_cmd_config2 = {
+	"config2", {720, 720}, 2, &nt35597_wqxga_dsc_cmd_params0
 };
 
 #endif
diff --git a/dev/gcdb/display/include/panel_nt35597_wqxga_dsc_video.h b/dev/gcdb/display/include/panel_nt35597_wqxga_dsc_video.h
index 382d75c..afcebfc 100644
--- a/dev/gcdb/display/include/panel_nt35597_wqxga_dsc_video.h
+++ b/dev/gcdb/display/include/panel_nt35597_wqxga_dsc_video.h
@@ -319,8 +319,23 @@
 /*---------------------------------------------------------------------------*/
 /* DSC									     */
 /*---------------------------------------------------------------------------*/
-static const struct dsc_parameters nt35597_wqxga_dsc_video_paras = {
-	1, 0, 0, 16, 720, 8, 8, 2, 1, 0, 0, 0
+struct dsc_parameters nt35597_wqxga_dsc_video_params0 = {
+	1, 0, 0, 16, 720, 8, 8, 2, 1, 0, 0
+};
+
+/* 1LM + 1 DSC_ENC */
+struct topology_config nt35597_wqxga_dsc_video_config0 = {
+	"config0", {-1, -1}, 1, &nt35597_wqxga_dsc_video_params0
+};
+
+/* 2LM + 3D Mux + 1 DSC_ENC */
+struct topology_config nt35597_wqxga_dsc_video_config1 = {
+	"config1", {720, 720}, 1, &nt35597_wqxga_dsc_video_params0
+};
+
+/* 2LM + 2 DSC_ENC + DSC_MERGE */
+struct topology_config nt35597_wqxga_dsc_video_config2 = {
+	"config2", {720, 720}, 2, &nt35597_wqxga_dsc_video_params0
 };
 
 #endif
diff --git a/dev/gcdb/display/panel_display.c b/dev/gcdb/display/panel_display.c
index 1c0a82a..88d2006 100755
--- a/dev/gcdb/display/panel_display.c
+++ b/dev/gcdb/display/panel_display.c
@@ -148,6 +148,8 @@
 	pinfo->xres += (pinfo->border_left + pinfo->border_right);
 	pinfo->yres += (pinfo->border_top + pinfo->border_bottom);
 
+	dprintf(INFO, "panel_operating_mode=0x%x\n",
+		pstruct->paneldata->panel_operating_mode);
 	if (pstruct->paneldata->panel_operating_mode & DUAL_PIPE_FLAG)
 		pinfo->lcdc.dual_pipe = 1;
 	if (pstruct->paneldata->panel_operating_mode & PIPE_SWAP_FLAG)
@@ -156,6 +158,14 @@
 		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;
+
+	dprintf(SPEW, "dual_pipe=%d pipe_swap=%d split_display=%d dst_split=%d\n",
+		pinfo->lcdc.dual_pipe, pinfo->lcdc.pipe_swap,
+		pinfo->lcdc.split_display, pinfo->lcdc.dst_split);
 
 	/* Color setting*/
 	pinfo->lcdc.border_clr = pstruct->color->border_color;
@@ -194,10 +204,6 @@
 	pinfo->mipi.vc = pstruct->paneldata->dsi_virtualchannel_id;
 	pinfo->mipi.frame_rate = pstruct->paneldata->panel_framerate;
 	pinfo->mipi.stream = pstruct->paneldata->dsi_stream;
-	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;
 	pinfo->mipi.mode_gpio_state = pstruct->paneldata->mode_gpio_state;
 	pinfo->mipi.bitclock = pstruct->paneldata->panel_bitclock_freq;
 	if (pinfo->mipi.bitclock) {
@@ -246,28 +252,36 @@
 	pinfo->fbc.comp_ratio = 1;
 
 	if (pinfo->compression_mode == COMPRESSION_DSC) {
-		struct dsc_desc *dsc = NULL;
+		struct dsc_desc *dsc = &pinfo->dsc;
+		struct dsc_parameters *dsc_params = NULL;
 
-		pinfo->dsc.major = pstruct->dsc_paras.major;
-		pinfo->dsc.minor = pstruct->dsc_paras.minor;
-		pinfo->dsc.pps_id = pstruct->dsc_paras.pps_id;
-		pinfo->dsc.slice_height = pstruct->dsc_paras.slice_height;
-		pinfo->dsc.slice_width = pstruct->dsc_paras.slice_width;
-		pinfo->dsc.bpp = pstruct->dsc_paras.bpp;
-		pinfo->dsc.bpc = pstruct->dsc_paras.bpc;
-		pinfo->dsc.slice_per_pkt = pstruct->dsc_paras.slice_per_pkt;
-		pinfo->dsc.ich_reset_value = pstruct->dsc_paras.ich_reset_value;
-		pinfo->dsc.ich_reset_override = pstruct->dsc_paras.ich_reset_override;
-		pinfo->dsc.block_pred_enable = pstruct->dsc_paras.block_prediction;
-		pinfo->dsc.enable_422 = 0;
-		pinfo->dsc.convert_rgb = 1;
-		pinfo->dsc.vbr_enable = 0;
+		if (!pstruct->config) {
+			dprintf(CRITICAL, "ERROR: DSC cannot be used without topology_config\n");
+			return ERR_NOT_ALLOWED;
+		}
+		dsc_params = pstruct->config->dsc;
+		if (!dsc_params) {
+			dprintf(CRITICAL, "ERROR: DSC params are NULL\n");
+			return ERR_INVALID_ARGS;
+		}
 
-		dsc = &pinfo->dsc;
-		if (dsc) {
-			if (dsc->parameter_calc)
-                                dsc->parameter_calc(pinfo);
-                }
+		dsc->major = dsc_params->major;
+		dsc->minor = dsc_params->minor;
+		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->ich_reset_value = dsc_params->ich_reset_value;
+		dsc->ich_reset_override = dsc_params->ich_reset_override;
+		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);
 	} else if (pinfo->compression_mode == COMPRESSION_FBC) {
 		pinfo->fbc.enabled = pstruct->fbcinfo.enabled;
 		if (pinfo->fbc.enabled) {
diff --git a/dev/gcdb/display/panel_display.h b/dev/gcdb/display/panel_display.h
index a998fc2..ed99a98 100755
--- a/dev/gcdb/display/panel_display.h
+++ b/dev/gcdb/display/panel_display.h
@@ -53,7 +53,7 @@
 /*---------------------------------------------------------------------------*/
 /* struct definition                                                         */
 /*---------------------------------------------------------------------------*/
-struct panel_struct{
+struct panel_struct {
 	struct panel_config         *paneldata;
 	struct panel_resolution     *panelres;
 	struct color_info           *color;
@@ -65,7 +65,7 @@
 	struct panel_reset_sequence *panelresetseq;
 	struct backlight            *backlightinfo;
 	struct fb_compression	    fbcinfo;
-	struct dsc_parameters	    dsc_paras;
+	struct topology_config	    *config;
 };
 
 struct panel_list {