HACK: drm: kirin960: Add DSI mode_valid hooks

This is still a bit of a hack, but its a better hack
then what we have right now.

This adds the valid mode checking to the DSI driver
which is the mode constraining component.

On the hikey board, we already have proper valid
mode calculations, so we don't need to use a whitelist,
but I've not worked out how to do the same logic
with the kirin960 driver yet.

So this patch imports the hack adv7511 valid modes
that we used in 4.9 (since we coudln't validate modes
behind a bridge in 4.9) and adds them in the dsi driver.

Signed-off-by: John Stultz <john.stultz@linaro.org>
Change-Id: Iaa1500585e42da4989e86afac5896ad6b2aa7dd5
diff --git a/drivers/gpu/drm/hisilicon/kirin960/dw_drm_dsi.c b/drivers/gpu/drm/hisilicon/kirin960/dw_drm_dsi.c
index 1ffde19f..f472bf6 100644
--- a/drivers/gpu/drm/hisilicon/kirin960/dw_drm_dsi.c
+++ b/drivers/gpu/drm/hisilicon/kirin960/dw_drm_dsi.c
@@ -1039,6 +1039,83 @@
 	dsi->enable = true;
 }
 
+static enum drm_mode_status dsi_encoder_phy_mode_valid(
+					struct drm_encoder *encoder,
+					const struct drm_display_mode *mode)
+{
+	/* XXX HACK whitelist for now, to move it out of
+	 * common adv7511 code.  This should be replaced by
+	 * something closer to dsi_encoder_phy_mode_valid()
+	 * found in in:
+	 *   drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
+	 */
+	DRM_DEBUG_DRIVER("Checking mode %ix%i@%i clock: %i...",
+			mode->hdisplay, mode->vdisplay,
+			drm_mode_vrefresh(mode), mode->clock);
+	if ((mode->hdisplay == 1920 && mode->vdisplay == 1080 && mode->clock == 148500) ||
+	    (mode->hdisplay == 1920 && mode->vdisplay == 1080 && mode->clock == 80192)  ||
+	    (mode->hdisplay == 1920 && mode->vdisplay == 1080 && mode->clock == 74250)  ||
+	    (mode->hdisplay == 1920 && mode->vdisplay == 1080 && mode->clock == 61855)  ||
+	    (mode->hdisplay == 1680 && mode->vdisplay == 1050 && mode->clock == 147116) ||
+	    (mode->hdisplay == 1680 && mode->vdisplay == 1050 && mode->clock == 146250) ||
+	    (mode->hdisplay == 1680 && mode->vdisplay == 1050 && mode->clock == 144589) ||
+	    (mode->hdisplay == 1600 && mode->vdisplay == 1200 && mode->clock == 160961) ||
+	    (mode->hdisplay == 1600 && mode->vdisplay == 900  && mode->clock == 118963) ||
+	    (mode->hdisplay == 1440 && mode->vdisplay == 900  && mode->clock == 126991) ||
+	    (mode->hdisplay == 1280 && mode->vdisplay == 1024 && mode->clock == 128946) ||
+	    (mode->hdisplay == 1280 && mode->vdisplay == 1024 && mode->clock == 98619)  ||
+	    (mode->hdisplay == 1280 && mode->vdisplay == 960  && mode->clock == 102081) ||
+	    (mode->hdisplay == 1280 && mode->vdisplay == 800  && mode->clock == 83496)  ||
+	    (mode->hdisplay == 1280 && mode->vdisplay == 720  && mode->clock == 74440)  ||
+	    (mode->hdisplay == 1280 && mode->vdisplay == 720  && mode->clock == 74250)  ||
+	    (mode->hdisplay == 1024 && mode->vdisplay == 768  && mode->clock == 78800)  ||
+	    (mode->hdisplay == 1024 && mode->vdisplay == 768  && mode->clock == 75000)  ||
+	    (mode->hdisplay == 1024 && mode->vdisplay == 768  && mode->clock == 81833)  ||
+	    (mode->hdisplay == 1024 && mode->vdisplay == 600  && mode->clock == 50250)  ||
+	    (mode->hdisplay == 800  && mode->vdisplay == 600  && mode->clock == 48907)  ||
+	    (mode->hdisplay == 800  && mode->vdisplay == 600  && mode->clock == 40000)  ||
+	    (mode->hdisplay == 800  && mode->vdisplay == 480  && mode->clock == 32000)) {
+		DRM_DEBUG_DRIVER("OK\n");
+		return MODE_OK;
+	}
+	DRM_DEBUG_DRIVER("BAD\n");
+	return MODE_BAD;
+}
+
+static enum drm_mode_status dsi_encoder_mode_valid(struct drm_encoder *encoder,
+					const struct drm_display_mode *mode)
+
+{
+	struct drm_crtc *crtc = NULL;
+	struct drm_display_mode adj_mode;
+	enum drm_mode_status ret;
+
+	/*
+	 * The crtc might adjust the mode, so go through the
+	 * possible crtcs (technically just one) and call
+	 * mode_fixup to figure out the adjusted mode before we
+	 * validate it.
+	 */
+	drm_for_each_crtc(crtc, encoder->dev) {
+		/*
+		 * reset adj_mode to the mode value each time,
+		 * so we don't adjust the mode twice
+		 */
+		drm_mode_copy(&adj_mode, mode);
+
+		/* XXX - skip this as we're just using a whitelist
+		crtc_funcs = crtc->helper_private;
+		if (crtc_funcs && crtc_funcs->mode_fixup)
+			if (!crtc_funcs->mode_fixup(crtc, mode, &adj_mode))
+				return MODE_BAD;
+		*/
+		ret = dsi_encoder_phy_mode_valid(encoder, &adj_mode);
+		if (ret != MODE_OK)
+			return ret;
+	}
+	return MODE_OK;
+}
+
 static void dsi_encoder_mode_set(struct drm_encoder *encoder,
 				 struct drm_display_mode *mode,
 				 struct drm_display_mode *adj_mode)
@@ -1058,6 +1135,7 @@
 
 static const struct drm_encoder_helper_funcs dw_encoder_helper_funcs = {
 	.atomic_check	= dsi_encoder_atomic_check,
+	.mode_valid	= dsi_encoder_mode_valid,
 	.mode_set	= dsi_encoder_mode_set,
 	.enable		= dsi_encoder_enable,
 	.disable	= dsi_encoder_disable
diff --git a/drivers/gpu/drm/hisilicon/kirin960/kirin_drm_dss.c b/drivers/gpu/drm/hisilicon/kirin960/kirin_drm_dss.c
index f2e43bd..0fa912c 100644
--- a/drivers/gpu/drm/hisilicon/kirin960/kirin_drm_dss.c
+++ b/drivers/gpu/drm/hisilicon/kirin960/kirin_drm_dss.c
@@ -292,6 +292,19 @@
 	drm_crtc_vblank_off(crtc);
 }
 
+static bool dss_crtc_mode_fixup(struct drm_crtc *crtc,
+				const struct drm_display_mode *mode,
+				struct drm_display_mode *adjusted_mode)
+{
+	struct dss_crtc *acrtc = to_dss_crtc(crtc);
+	struct dss_hw_ctx *ctx = acrtc->ctx;
+
+	adjusted_mode->clock =
+		clk_round_rate(ctx->dss_pxl0_clk, mode->clock * 1000) / 1000;
+	return true;
+}
+
+
 static void dss_crtc_mode_set_nofb(struct drm_crtc *crtc)
 {
 	struct dss_crtc *acrtc = to_dss_crtc(crtc);
@@ -333,6 +346,7 @@
 static const struct drm_crtc_helper_funcs dss_crtc_helper_funcs = {
 	.atomic_enable	= dss_crtc_atomic_enable,
 	.atomic_disable	= dss_crtc_atomic_disable,
+	.mode_fixup     = dss_crtc_mode_fixup,
 	.mode_set_nofb	= dss_crtc_mode_set_nofb,
 	.atomic_begin	= dss_crtc_atomic_begin,
 	.atomic_flush	= dss_crtc_atomic_flush,