msm_shared: mdp: fix incorrect SMP programming for apq8084

SMP programming on different versions of MDP5 can be different.
Current implementation of smp setup doesn't consider that and
may lead to occasional under-runs. Fix this by generalizing
smp setup for different targets.

Change-Id: Ie1a0948b723572393725d9cced52c175908f35a2
diff --git a/platform/msm_shared/include/mdp5.h b/platform/msm_shared/include/mdp5.h
index 149162f..8b68ca0 100644
--- a/platform/msm_shared/include/mdp5.h
+++ b/platform/msm_shared/include/mdp5.h
@@ -86,6 +86,8 @@
 #define MDSS_MDP_HW_REV_103    MDSS_MDP_REV(1, 3, 0) /* 8084 v1.0 */
 #define MDSS_MDP_HW_REV_200    MDSS_MDP_REV(2, 0, 0) /* 8092 v1.0 */
 
+#define MDSS_MAX_LINE_BUF_WIDTH 2048
+
 #define MDP_HW_REV                              REG_MDP(0x0100)
 #define MDP_INTR_EN                             REG_MDP(0x0110)
 #define MDP_INTR_CLEAR                          REG_MDP(0x0118)
@@ -143,16 +145,8 @@
 #define MDP_CLK_CTRL6                           REG_MDP(0x03C4)
 #define MDP_CLK_CTRL7                           REG_MDP(0x04D0)
 
-#define MMSS_MDP_CLIENT_ID_UNUSED               0x00000000
-#define MMSS_MDP_1_1_CLIENT_ID_RGB0             0x00000007
-#define MMSS_MDP_1_2_CLIENT_ID_RGB0             0x00000010
-#define MMSS_MDP_1_2_CLIENT_ID_RGB1             0x00000011
-
-#define MMSS_MDP_MAX_SMP_SIZE                   0x00001000
-#define MMSS_MDP_SMP_ALLOC_W_0                  REG_MDP(0x0180)
-#define MMSS_MDP_SMP_ALLOC_W_1                  REG_MDP(0x0184)
-#define MMSS_MDP_SMP_ALLOC_R_0                  REG_MDP(0x0230)
-#define MMSS_MDP_SMP_ALLOC_R_1                  REG_MDP(0x0234)
+#define MMSS_MDP_SMP_ALLOC_W_BASE               REG_MDP(0x0180)
+#define MMSS_MDP_SMP_ALLOC_R_BASE               REG_MDP(0x0230)
 
 #define MDP_QOS_REMAPPER_CLASS_0                REG_MDP(0x02E0)
 #define MDP_QOS_REMAPPER_CLASS_1                REG_MDP(0x02E4)
diff --git a/platform/msm_shared/mdp5.c b/platform/msm_shared/mdp5.c
index 2cbf408..50e1cd5 100644
--- a/platform/msm_shared/mdp5.c
+++ b/platform/msm_shared/mdp5.c
@@ -150,32 +150,62 @@
 	}
 }
 
-void mdss_smp_setup(struct msm_panel_info *pinfo)
+static uint32_t mdss_smp_alloc(uint32_t client_id, uint32_t smp_cnt,
+	uint32_t fixed_smp_cnt, uint32_t free_smp_offset)
 {
-	uint32_t smp_cnt = 0, reg_rgb0 = 0, reg_rgb1 = 0, shift = 0;
-	uint32_t xres, bpp;
-	uint32_t rgb0_client_id = MMSS_MDP_CLIENT_ID_UNUSED;
-	uint32_t rgb1_client_id = MMSS_MDP_1_2_CLIENT_ID_RGB1;
+	uint32_t i, j;
+	uint32_t reg_val = 0;
 	uint32_t mdss_mdp_rev = readl(MDP_HW_REV);
 
-	xres = pinfo->xres;
-	bpp = pinfo->bpp;
-
-	if (mdss_mdp_rev == MDSS_MDP_HW_REV_100
-		|| mdss_mdp_rev >= MDSS_MDP_HW_REV_102)
-		rgb0_client_id = MMSS_MDP_1_2_CLIENT_ID_RGB0;
-	else if (mdss_mdp_rev >= MDSS_MDP_HW_REV_101)
-		rgb0_client_id = MMSS_MDP_1_1_CLIENT_ID_RGB0;
-
-	if (pinfo->lcdc.dual_pipe) {
-		/* Each pipe driving half the screen */
-		xres /= 2;
+	for (i = fixed_smp_cnt, j = 0; i < smp_cnt; i++) {
+		/* max 3 MMB per register */
+		reg_val |= client_id << (((j++) % 3) * 8);
+		if ((j % 3) == 0) {
+			writel(reg_val, MMSS_MDP_SMP_ALLOC_W_BASE +
+				free_smp_offset);
+			writel(reg_val, MMSS_MDP_SMP_ALLOC_R_BASE +
+				free_smp_offset);
+			reg_val = 0;
+			free_smp_offset += 4;
+		}
 	}
 
-	smp_cnt = ((xres) * (bpp / 8) * 2) +
-		MMSS_MDP_MAX_SMP_SIZE - 1;
+	if (j % 3) {
+		writel(reg_val, MMSS_MDP_SMP_ALLOC_W_BASE + free_smp_offset);
+		writel(reg_val, MMSS_MDP_SMP_ALLOC_R_BASE + free_smp_offset);
+		free_smp_offset += 4;
+	}
 
-	smp_cnt /= MMSS_MDP_MAX_SMP_SIZE;
+	return free_smp_offset;
+}
+
+void mdss_smp_setup(struct msm_panel_info *pinfo)
+{
+	uint32_t rgb0_client_id, rgb1_client_id;
+	uint32_t bpp = 3, free_smp_offset = 0, xres = MDSS_MAX_LINE_BUF_WIDTH;
+	uint32_t smp_cnt, smp_size = 4096, fixed_smp_cnt = 0;
+	uint32_t mdss_mdp_rev = readl(MDP_HW_REV);
+
+	if ((mdss_mdp_rev >= MDSS_MDP_HW_REV_103) &&
+		(mdss_mdp_rev < MDSS_MDP_HW_REV_200)) {
+		smp_size = 8192;
+		fixed_smp_cnt = 2;
+		free_smp_offset = 0xC;
+	}
+
+	rgb1_client_id = 0x11; /* 17 */
+	if (MDSS_IS_MAJOR_MINOR_MATCHING(mdss_mdp_rev, MDSS_MDP_HW_REV_101))
+		rgb0_client_id = 0x7;
+	else
+		rgb0_client_id = 0x10; /* 16 */
+
+	/* Each pipe driving half the screen */
+	if (pinfo->lcdc.dual_pipe)
+		xres /= 2;
+
+	/* bpp = bytes per pixel of input image */
+	smp_cnt = (xres * bpp * 2) + smp_size - 1;
+	smp_cnt /= smp_size;
 
 	if (smp_cnt > 4) {
 		dprintf(CRITICAL, "ERROR: %s: Out of SMP's, cnt=%d! \n", __func__,
@@ -193,21 +223,11 @@
 		writel(smp_cnt * 0xc0, MDP_VP_0_RGB_1_BASE + REQPRIORITY_FIFO_WATERMARK2);
 	}
 
-	while((smp_cnt > 0) && !(shift > 16)) {
-		reg_rgb0 |= ((rgb0_client_id) << (shift));
-		reg_rgb1 |= ((rgb1_client_id) << (shift));
-		smp_cnt--;
-		shift += 8;
-	}
-
-	/* Allocate SMP blocks */
-	writel(reg_rgb0, MMSS_MDP_SMP_ALLOC_W_0);
-	writel(reg_rgb0, MMSS_MDP_SMP_ALLOC_R_0);
-
-	if (pinfo->lcdc.dual_pipe) {
-		writel(reg_rgb1, MMSS_MDP_SMP_ALLOC_W_1);
-		writel(reg_rgb1, MMSS_MDP_SMP_ALLOC_R_1);
-	}
+	free_smp_offset = mdss_smp_alloc(rgb0_client_id, smp_cnt,
+		fixed_smp_cnt, free_smp_offset);
+	if (pinfo->lcdc.dual_pipe)
+		mdss_smp_alloc(rgb1_client_id, smp_cnt, fixed_smp_cnt,
+			free_smp_offset);
 }
 
 void mdss_intf_tg_setup(struct msm_panel_info *pinfo, uint32_t intf_base)