diff mbox series

drm/ast: Create the driver for ASPEED proprietory Display-Port

Message ID 20211122103617.3496-1-kuohsiang_chou@aspeedtech.com (mailing list archive)
State New, archived
Headers show
Series drm/ast: Create the driver for ASPEED proprietory Display-Port | expand

Commit Message

KuoHsiang Chou Nov. 22, 2021, 10:36 a.m. UTC
1. The MCU FW controling ASPEED DP is loaded by BMC boot loader.
2. Driver starts after CR[3:1] == 111b that indicates Tx is ASTDP,
   and CRD1[5] has been asserted by BMVC boot loader.
3. EDID is prioritized by DP monitor.
4. DP's EDID has high priority to decide resolution supporting.

Signed-off-by: KuoHsiang Chou <kuohsiang_chou@aspeedtech.com>
---
 drivers/gpu/drm/ast/Makefile   |   2 +-
 drivers/gpu/drm/ast/ast_dp.c   | 286 +++++++++++++++++++++++++++++++++
 drivers/gpu/drm/ast/ast_drv.h  |  13 ++
 drivers/gpu/drm/ast/ast_main.c |   7 +-
 drivers/gpu/drm/ast/ast_mode.c |  50 +++++-
 drivers/gpu/drm/ast/ast_post.c |   4 +-
 6 files changed, 353 insertions(+), 9 deletions(-)
 create mode 100644 drivers/gpu/drm/ast/ast_dp.c

Comments

kernel test robot Nov. 25, 2021, 3:56 p.m. UTC | #1
Hi KuoHsiang,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on drm/drm-next]
[also build test WARNING on drm-intel/for-linux-next drm-tip/drm-tip drm-exynos/exynos-drm-next tegra-drm/drm/tegra/for-next v5.16-rc2 next-20211125]
[cannot apply to airlied/drm-next]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/KuoHsiang-Chou/drm-ast-Create-the-driver-for-ASPEED-proprietory-Display-Port/20211122-183830
base:   git://anongit.freedesktop.org/drm/drm drm-next
config: i386-randconfig-c021-20211123 (https://download.01.org/0day-ci/archive/20211125/202111252305.4CNMgIAc-lkp@intel.com/config)
compiler: gcc-9 (Debian 9.3.0-22) 9.3.0

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>


cocci warnings: (new ones prefixed by >>)
>> drivers/gpu/drm/ast/ast_dp.c:166:3-4: Unneeded semicolon

Please review and possibly fold the followup patch.

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
KuoHsiang Chou Dec. 3, 2021, 6:31 a.m. UTC | #2
Hi Thomas,

Hi Tomas,
Good day! 
May I get the review status, or is there anything I can do to improve it? Thanks!

Best Regards,
	Kuo-Hsiang Chou

-----Original Message-----
From: Kuo-Hsiang Chou 
Sent: Monday, November 22, 2021 6:36 PM
To: tzimmermann@suse.de; dri-devel@lists.freedesktop.org; linux-kernel@vger.kernel.org
Subject: [PATCH] drm/ast: Create the driver for ASPEED proprietory Display-Port

1. The MCU FW controling ASPEED DP is loaded by BMC boot loader.
2. Driver starts after CR[3:1] == 111b that indicates Tx is ASTDP,
   and CRD1[5] has been asserted by BMVC boot loader.
3. EDID is prioritized by DP monitor.
4. DP's EDID has high priority to decide resolution supporting.

Signed-off-by: KuoHsiang Chou <kuohsiang_chou@aspeedtech.com>
---
 drivers/gpu/drm/ast/Makefile   |   2 +-
 drivers/gpu/drm/ast/ast_dp.c   | 286 +++++++++++++++++++++++++++++++++
 drivers/gpu/drm/ast/ast_drv.h  |  13 ++
 drivers/gpu/drm/ast/ast_main.c |   7 +-
 drivers/gpu/drm/ast/ast_mode.c |  50 +++++-
 drivers/gpu/drm/ast/ast_post.c |   4 +-
 6 files changed, 353 insertions(+), 9 deletions(-)  create mode 100644 drivers/gpu/drm/ast/ast_dp.c

diff --git a/drivers/gpu/drm/ast/Makefile b/drivers/gpu/drm/ast/Makefile index 438a2d05b..9bd0756e0 100644
--- a/drivers/gpu/drm/ast/Makefile
+++ b/drivers/gpu/drm/ast/Makefile
@@ -3,6 +3,6 @@
 # Makefile for the drm device driver.  This driver provides support for the  # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
 
-ast-y := ast_drv.o ast_main.o ast_mm.o ast_mode.o ast_post.o ast_dp501.o
+ast-y := ast_drv.o ast_main.o ast_mm.o ast_mode.o ast_post.o 
+ast_dp501.o ast_dp.o
 
 obj-$(CONFIG_DRM_AST) := ast.o
diff --git a/drivers/gpu/drm/ast/ast_dp.c b/drivers/gpu/drm/ast/ast_dp.c new file mode 100644 index 000000000..537eaf4fa
--- /dev/null
+++ b/drivers/gpu/drm/ast/ast_dp.c
@@ -0,0 +1,286 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person 
+obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject 
+to
+ * the following conditions:
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
+EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
+MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT 
+SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR 
+ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT 
+OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 
+OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial 
+portions
+ * of the Software.
+ *
+ */
+/*
+ * Authors: KuoHsiang Chou <kuohsiang_chou@aspeedtech.com>  */
+
+#include <linux/firmware.h>
+#include <linux/delay.h>
+#include <drm/drm_print.h>
+#include "ast_drv.h"
+
+bool ast_dp_read_edid(struct drm_device *dev, u8 *ediddata) {
+	struct ast_private *ast = to_ast_private(dev);
+	u8 i = 0, j = 0;
+
+#ifdef DPControlPower
+	u8 bDPState_Change = false;
+
+	// Check DP power off or not.
+	if (ast->ASTDP_State & 0x10) {
+		// DP power on
+		ast_dp_PowerOnOff(dev, 1);
+		bDPState_Change = true;
+	}
+#endif
+
+	/*
+	 * CRD1[b5]: DP MCU FW is executing
+	 * CRDC[b0]: DP link success
+	 * CRDF[b0]: DP HPD
+	 * CRE5[b0]: Host reading EDID process is done
+	 */
+	if (!(ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD1, 0x20) &&
+		ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDC, 0x01) &&
+		ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDF, 0x01) &&
+		ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE5, 0x01))) { #ifdef 
+DPControlPower
+		// Set back power off
+		if (bDPState_Change)
+			ast_dp_PowerOnOff(dev, 0);
+#endif
+		return false;
+	}
+
+	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE5, 0x00, 0x00);
+
+	for (i = 0; i < 32; i++) {
+		/*
+		 * CRE4[7:0]: Read-Pointer for EDID (Unit: 4bytes); valid range: 0~64
+		 */
+		ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE4, 0x00, (u8) i);
+		j = 0;
+
+		/*
+		 * CRD7[b0]: valid flag for EDID
+		 * CRD6[b0]: mirror read pointer for EDID
+		 */
+		while ((ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD7, 0x01) != 0x01) ||
+			(ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD6, 0xFF) != i)) {
+			mdelay(j+1);
+
+			if (!(ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD1, 0x20) &&
+				ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDC, 0x01) &&
+				ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDF, 0x01))) {
+				ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE5, 0x00, 0x01);
+				return false;
+			}
+
+			j++;
+			if (j > 200) {
+				ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE5, 0x00, 0x01);
+				return false;
+			}
+		}
+
+		*(ediddata) = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD8, 0xFF);
+		*(ediddata + 1) = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD9, 0xFF);
+		*(ediddata + 2) = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDA, 0xFF);
+		*(ediddata + 3) = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDB, 
+0xFF);
+
+		if (i == 31) {
+			*(ediddata + 3) = *(ediddata + 3) + *(ediddata + 2);
+			*(ediddata + 2) = 0;
+		}
+
+		ediddata += 4;
+	}
+
+	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE5, 0x00, 0x01);
+
+#ifdef DPControlPower
+	// Set back power off
+	if (bDPState_Change)
+		ast_dp_PowerOnOff(dev, 0);
+#endif
+
+	return true;
+}
+
+/*
+ * Launch Aspeed DP
+ */
+bool ast_dp_launch(struct drm_device *dev, u8 bPower) {
+	u32 i = 0, j = 0, WaitCount = 1;
+	u8 bDPTX = 0;
+	u8 bDPExecute = 1;
+
+	struct ast_private *ast = to_ast_private(dev);
+	// S3 come back, need more time to wait BMC ready.
+	if (bPower)
+		WaitCount = 300;
+
+	// Fill
+	ast->tx_chip_type = AST_TX_NONE;
+
+	// Wait total count by different condition.
+	// This is a temp solution for DP check
+	for (j = 0; j < WaitCount; j++) {
+		bDPTX = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD1, 0x0E);
+
+		if (bDPTX)
+			break;
+
+		msleep(100);
+	}
+
+	// 0xE : ASTDP with DPMCU FW handling
+	if (bDPTX == 0x0E) {
+		// Wait one second then timeout.
+		i = 0;
+
+		while (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD1, 0x20) != 0x20) {
+			i++;
+			// wait 100 ms
+			msleep(100);
+
+			if (i >= 10) {
+				// DP would not be ready.
+				bDPExecute = 0;
+				break;
+			}
+		};
+
+		if (bDPExecute)
+			ast->tx_chip_type = AST_TX_ASTDP;
+	}
+
+	return true;
+}
+
+#ifdef DPControlPower
+
+void ast_dp_PowerOnOff(struct drm_device *dev, u8 Mode) {
+	struct ast_private *ast = to_ast_private(dev);
+	// Read and Turn off DP PHY sleep
+	u8 bE3 = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE3, 0x0F);
+
+	// Turn on DP PHY sleep
+	if (!Mode)
+		bE3 |= 0x10;
+
+	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE3, 0x00, bE3); // DP 
+Power on/off
+
+	// Save ASTDP power state
+	ast->ASTDP_State = bE3;
+}
+
+#endif
+
+void ast_dp_SetOnOff(struct drm_device *dev, u8 Mode) {
+	struct ast_private *ast = to_ast_private(dev);
+
+	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE3, 0x00, Mode); // 
+video on/off
+
+	// Save ASTDP power state
+	ast->ASTDP_State = Mode;
+
+    // If DP plug in and link successful then check video on / off status
+	if (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDC, 0x01) &&
+		ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDF, 0x01)) {
+		Mode <<= 4;
+		while (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDF, 0x10) != Mode) {
+			// wait 1 ms
+			mdelay(1);
+		}
+	}
+}
+
+void ast_dp_SetOutput(struct drm_crtc *crtc, struct ast_vbios_mode_info 
+*vbios_mode) {
+	struct ast_private *ast = to_ast_private(crtc->dev);
+
+	u32 ulRefreshRateIndex;
+	u8 ModeIdx;
+
+	ulRefreshRateIndex = vbios_mode->enh_table->refresh_rate_index - 1;
+
+	switch (crtc->mode.crtc_hdisplay) {
+	case 320:
+		ModeIdx = 0x11;
+		break;
+	case 400:
+		ModeIdx = 0x12;
+		break;
+	case 512:
+		ModeIdx = 0x13;
+		break;
+	case 640:
+		ModeIdx = (0x00 + (u8) ulRefreshRateIndex);
+		break;
+	case 800:
+		ModeIdx = (0x04 + (u8) ulRefreshRateIndex);
+		break;
+	case 1024:
+		ModeIdx = (0x09 + (u8) ulRefreshRateIndex);
+		break;
+	case 1152:
+		ModeIdx = 0x1F;
+		break;
+	case 1280:
+		if (crtc->mode.crtc_vdisplay == 800)
+			ModeIdx = (0x17 - (u8) ulRefreshRateIndex);	// For RB/Non-RB
+		else		// 1024
+			ModeIdx = (0x0D + (u8) ulRefreshRateIndex);
+		break;
+	case 1360:
+	case 1366:
+		ModeIdx = 0x1E;
+		break;
+	case 1440:
+		ModeIdx = (0x19 - (u8) ulRefreshRateIndex);	// For RB/Non-RB
+		break;
+	case 1600:
+		if (crtc->mode.crtc_vdisplay == 900)
+			ModeIdx = (0x1D - (u8) ulRefreshRateIndex);	// For RB/Non-RB
+		else		//1200
+			ModeIdx = 0x10;
+		break;
+	case 1680:
+		ModeIdx = (0x1B - (u8) ulRefreshRateIndex);	// For RB/Non-RB
+		break;
+	case 1920:
+		if (crtc->mode.crtc_vdisplay == 1080)
+			ModeIdx = 0x15;
+		else		//1200
+			ModeIdx = 0x14;
+		break;
+	default:
+		return;
+	}
+
+	/*
+	 * CRE0[7:0]: MISC0 ((0x00: 18-bpp) or (0x20: 24-bpp)
+	 * CRE1[7:0]: MISC1 (default: 0x00)
+	 * CRE2[7:0]: video format index (0x00 ~ 0x20 or 0x40 ~ 0x50)
+	 */
+	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE0, 0x00, 0x20);
+	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE1, 0x00, 0x00);
+	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE2, 0x00, ModeIdx); }
diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h index 2cfce7dc9..e56d5d57b 100644
--- a/drivers/gpu/drm/ast/ast_drv.h
+++ b/drivers/gpu/drm/ast/ast_drv.h
@@ -71,6 +71,7 @@ enum ast_tx_chip {
 	AST_TX_SIL164,
 	AST_TX_ITE66121,
 	AST_TX_DP501,
+	AST_TX_ASTDP,
 };
 
 #define AST_DRAM_512Mx16 0
@@ -175,6 +176,9 @@ struct ast_private {
 	u8 dp501_maxclk;
 	u8 *dp501_fw_addr;
 	const struct firmware *dp501_fw;	/* dp501 fw */
+
+    // ASTDP
+	u8 ASTDP_State;
 };
 
 static inline struct ast_private *to_ast_private(struct drm_device *dev) @@ -356,5 +360,14 @@ bool ast_backup_fw(struct drm_device *dev, u8 *addr, u32 size);  bool ast_dp501_read_edid(struct drm_device *dev, u8 *ediddata);
 u8 ast_get_dp501_max_clk(struct drm_device *dev);  void ast_init_3rdtx(struct drm_device *dev);
+/* aspeed DP */
+#define DPControlPower
+bool ast_dp_read_edid(struct drm_device *dev, u8 *ediddata); bool 
+ast_dp_launch(struct drm_device *dev, u8 bPower); #ifdef DPControlPower 
+void ast_dp_PowerOnOff(struct drm_device *dev, u8 Mode); #endif void 
+ast_dp_SetOnOff(struct drm_device *dev, u8 Mode); void 
+ast_dp_SetOutput(struct drm_crtc *crtc, struct ast_vbios_mode_info 
+*vbios_mode);
 
 #endif
diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c index 79a361867..de5d69888 100644
--- a/drivers/gpu/drm/ast/ast_main.c
+++ b/drivers/gpu/drm/ast/ast_main.c
@@ -212,7 +212,7 @@ static int ast_detect_chip(struct drm_device *dev, bool *need_post)
 		}
 		break;
 	}
-
+	ast->support_wide_screen = true;
 	/* Check 3rd Tx option (digital output afaik) */
 	ast->tx_chip_type = AST_TX_NONE;
 
@@ -230,7 +230,7 @@ static int ast_detect_chip(struct drm_device *dev, bool *need_post)
 			ast->tx_chip_type = AST_TX_SIL164;
 	}
 
-	if ((ast->chip == AST2300) || (ast->chip == AST2400)) {
+	if ((ast->chip == AST2300) || (ast->chip == AST2400) || (ast->chip == 
+AST2500)) {
 		/*
 		 * On AST2300 and 2400, look the configuration set by the SoC in
 		 * the SOC scratch register #1 bits 11:8 (interestingly marked @@ -254,7 +254,8 @@ static int ast_detect_chip(struct drm_device *dev, bool *need_post)
 		case 0x0c:
 			ast->tx_chip_type = AST_TX_DP501;
 		}
-	}
+	} else if (ast->chip == AST2600)
+		ast_dp_launch(&ast->base, 0);
 
 	/* Print stuff for diagnostic purposes */
 	switch(ast->tx_chip_type) {
diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index 6bfaefa01..d7347d510 100644
--- a/drivers/gpu/drm/ast/ast_mode.c
+++ b/drivers/gpu/drm/ast/ast_mode.c
@@ -987,20 +987,44 @@ static int ast_cursor_plane_init(struct ast_private *ast)  static void ast_crtc_dpms(struct drm_crtc *crtc, int mode)  {
 	struct ast_private *ast = to_ast_private(crtc->dev);
+	u8 ch = 0x03;
 
 	/* TODO: Maybe control display signal generation with
 	 *       Sync Enable (bit CR17.7).
 	 */
 	switch (mode) {
 	case DRM_MODE_DPMS_ON:
-	case DRM_MODE_DPMS_STANDBY:
-	case DRM_MODE_DPMS_SUSPEND:
+		ast_set_index_reg_mask(ast, AST_IO_SEQ_PORT,  0x01, 0xdf, 0);
+		ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb6, 0xfc, 0);
 		if (ast->tx_chip_type == AST_TX_DP501)
 			ast_set_dp501_video_output(crtc->dev, 1);
+
+		if (ast->tx_chip_type == AST_TX_ASTDP) { #ifdef DPControlPower
+			ast_dp_PowerOnOff(crtc->dev, 1);
+#endif
+			ast_wait_for_vretrace(ast);
+			ast_dp_SetOnOff(crtc->dev, 1);
+		}
+
+		ast_crtc_load_lut(ast, crtc);
 		break;
+	case DRM_MODE_DPMS_STANDBY:
+	case DRM_MODE_DPMS_SUSPEND:
 	case DRM_MODE_DPMS_OFF:
+		ch = mode;
 		if (ast->tx_chip_type == AST_TX_DP501)
 			ast_set_dp501_video_output(crtc->dev, 0);
+
+		if (ast->tx_chip_type == AST_TX_ASTDP) {
+			ast_dp_SetOnOff(crtc->dev, 0);
+#ifdef DPControlPower
+			ast_dp_PowerOnOff(crtc->dev, 0);
+#endif
+		}
+
+		ast_set_index_reg_mask(ast, AST_IO_SEQ_PORT,  0x01, 0xdf, 0x20);
+		ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb6, 0xfc, ch);
 		break;
 	}
 }
@@ -1044,6 +1068,8 @@ ast_crtc_helper_atomic_flush(struct drm_crtc *crtc,
 	struct ast_private *ast = to_ast_private(crtc->dev);
 	struct ast_crtc_state *ast_crtc_state = to_ast_crtc_state(crtc_state);
 	struct ast_crtc_state *old_ast_crtc_state = to_ast_crtc_state(old_crtc_state);
+struct ast_vbios_mode_info *vbios_mode_info =
+		&ast_crtc_state->vbios_mode_info;
 
 	/*
 	 * The gamma LUT has to be reloaded after changing the primary @@ -1051,6 +1077,10 @@ ast_crtc_helper_atomic_flush(struct drm_crtc *crtc,
 	 */
 	if (old_ast_crtc_state->format != ast_crtc_state->format)
 		ast_crtc_load_lut(ast, crtc);
+
+	//Set Aspeed Display-Port
+	if (ast->tx_chip_type == AST_TX_ASTDP)
+		ast_dp_SetOutput(crtc, vbios_mode_info);
 }
 
 static void
@@ -1225,7 +1255,16 @@ static int ast_get_modes(struct drm_connector *connector)
 			ast->dp501_maxclk = ast_get_dp501_max_clk(connector->dev);
 		else
 			kfree(edid);
+	} else if (ast->tx_chip_type == AST_TX_ASTDP) {
+		edid = kmalloc(128, GFP_KERNEL);
+		if (!edid)
+			return -ENOMEM;
+
+		flags = ast_dp_read_edid(connector->dev, (u8 *)edid);
+		if (!flags)
+			kfree(edid);
 	}
+
 	if (!flags)
 		edid = drm_get_edid(connector, &ast_connector->i2c->adapter);
 	if (edid) {
@@ -1256,10 +1295,12 @@ static enum drm_mode_status ast_mode_valid(struct drm_connector *connector,
 			return MODE_OK;
 		if ((mode->hdisplay == 1600) && (mode->vdisplay == 900))
 			return MODE_OK;
+		if ((mode->hdisplay == 1152) && (mode->vdisplay == 864))
+			return MODE_OK;
 
 		if ((ast->chip == AST2100) || (ast->chip == AST2200) ||
 		    (ast->chip == AST2300) || (ast->chip == AST2400) ||
-		    (ast->chip == AST2500)) {
+		    (ast->chip == AST2500) || (ast->chip == AST2600)) {
 			if ((mode->hdisplay == 1920) && (mode->vdisplay == 1080))
 				return MODE_OK;
 
@@ -1400,7 +1441,8 @@ int ast_mode_config_init(struct ast_private *ast)
 	    ast->chip == AST2200 ||
 	    ast->chip == AST2300 ||
 	    ast->chip == AST2400 ||
-	    ast->chip == AST2500) {
+	    ast->chip == AST2500 ||
+	    ast->chip == AST2600) {
 		dev->mode_config.max_width = 1920;
 		dev->mode_config.max_height = 2048;
 	} else {
diff --git a/drivers/gpu/drm/ast/ast_post.c b/drivers/gpu/drm/ast/ast_post.c index b5d92f652..0aa9cf0fb 100644
--- a/drivers/gpu/drm/ast/ast_post.c
+++ b/drivers/gpu/drm/ast/ast_post.c
@@ -379,7 +379,9 @@ void ast_post_gpu(struct drm_device *dev)
 	ast_enable_mmio(dev);
 	ast_set_def_ext_reg(dev);
 
-	if (ast->config_mode == ast_use_p2a) {
+	if (ast->chip == AST2600) {
+		ast_dp_launch(dev, 1);
+	} else if (ast->config_mode == ast_use_p2a) {
 		if (ast->chip == AST2500)
 			ast_post_chip_2500(dev);
 		else if (ast->chip == AST2300 || ast->chip == AST2400)
--
2.27.0
Thomas Zimmermann Dec. 3, 2021, 8:54 a.m. UTC | #3
Hi

Am 03.12.21 um 07:31 schrieb Kuo-Hsiang Chou:
> Hi Thomas,
> 
> Hi Tomas,
> Good day!
> May I get the review status, or is there anything I can do to improve it? Thanks!
> 
> Best Regards,
> 	Kuo-Hsiang Chou
> 
> -----Original Message-----
> From: Kuo-Hsiang Chou
> Sent: Monday, November 22, 2021 6:36 PM
> To: tzimmermann@suse.de; dri-devel@lists.freedesktop.org; linux-kernel@vger.kernel.org
> Subject: [PATCH] drm/ast: Create the driver for ASPEED proprietory Display-Port
> 
> 1. The MCU FW controling ASPEED DP is loaded by BMC boot loader.
> 2. Driver starts after CR[3:1] == 111b that indicates Tx is ASTDP,
>     and CRD1[5] has been asserted by BMVC boot loader.
> 3. EDID is prioritized by DP monitor.
> 4. DP's EDID has high priority to decide resolution supporting.
> 
> Signed-off-by: KuoHsiang Chou <kuohsiang_chou@aspeedtech.com>
> ---
>   drivers/gpu/drm/ast/Makefile   |   2 +-
>   drivers/gpu/drm/ast/ast_dp.c   | 286 +++++++++++++++++++++++++++++++++
>   drivers/gpu/drm/ast/ast_drv.h  |  13 ++
>   drivers/gpu/drm/ast/ast_main.c |   7 +-
>   drivers/gpu/drm/ast/ast_mode.c |  50 +++++-
>   drivers/gpu/drm/ast/ast_post.c |   4 +-
>   6 files changed, 353 insertions(+), 9 deletions(-)  create mode 100644 drivers/gpu/drm/ast/ast_dp.c
> 
> diff --git a/drivers/gpu/drm/ast/Makefile b/drivers/gpu/drm/ast/Makefile index 438a2d05b..9bd0756e0 100644
> --- a/drivers/gpu/drm/ast/Makefile
> +++ b/drivers/gpu/drm/ast/Makefile
> @@ -3,6 +3,6 @@
>   # Makefile for the drm device driver.  This driver provides support for the  # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
>   
> -ast-y := ast_drv.o ast_main.o ast_mm.o ast_mode.o ast_post.o ast_dp501.o
> +ast-y := ast_drv.o ast_main.o ast_mm.o ast_mode.o ast_post.o
> +ast_dp501.o ast_dp.o
>   
>   obj-$(CONFIG_DRM_AST) := ast.o
> diff --git a/drivers/gpu/drm/ast/ast_dp.c b/drivers/gpu/drm/ast/ast_dp.c new file mode 100644 index 000000000..537eaf4fa
> --- /dev/null
> +++ b/drivers/gpu/drm/ast/ast_dp.c
> @@ -0,0 +1,286 @@
> +/*
> + * Copyright 2012 Red Hat Inc.

You didn't even put in your company's copyright. So what am I supposed 
to do about this patch?

For the rest of the code, it's just bolted onto the existing connector. 
Which already has been hacked to support an DP port. I began redesigning 
the whole thing to support each connector individually. I'm not going to 
add more hacks to it.

Best regards
Thomas

> + *
> + * Permission is hereby granted, free of charge, to any person
> +obtaining a
> + * copy of this software and associated documentation files (the
> + * "Software"), to deal in the Software without restriction, including
> + * without limitation the rights to use, copy, modify, merge, publish,
> + * distribute, sub license, and/or sell copies of the Software, and to
> + * permit persons to whom the Software is furnished to do so, subject
> +to
> + * the following conditions:
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> +EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> +MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT
> +SHALL
> + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR
> +ANY CLAIM,
> + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
> +OR
> + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
> +OR THE
> + * USE OR OTHER DEALINGS IN THE SOFTWARE.
> + *
> + * The above copyright notice and this permission notice (including the
> + * next paragraph) shall be included in all copies or substantial
> +portions
> + * of the Software.
> + *
> + */
> +/*
> + * Authors: KuoHsiang Chou <kuohsiang_chou@aspeedtech.com>  */
> +
> +#include <linux/firmware.h>
> +#include <linux/delay.h>
> +#include <drm/drm_print.h>
> +#include "ast_drv.h"
> +
> +bool ast_dp_read_edid(struct drm_device *dev, u8 *ediddata) {
> +	struct ast_private *ast = to_ast_private(dev);
> +	u8 i = 0, j = 0;
> +
> +#ifdef DPControlPower
> +	u8 bDPState_Change = false;
> +
> +	// Check DP power off or not.
> +	if (ast->ASTDP_State & 0x10) {
> +		// DP power on
> +		ast_dp_PowerOnOff(dev, 1);
> +		bDPState_Change = true;
> +	}
> +#endif
> +
> +	/*
> +	 * CRD1[b5]: DP MCU FW is executing
> +	 * CRDC[b0]: DP link success
> +	 * CRDF[b0]: DP HPD
> +	 * CRE5[b0]: Host reading EDID process is done
> +	 */
> +	if (!(ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD1, 0x20) &&
> +		ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDC, 0x01) &&
> +		ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDF, 0x01) &&
> +		ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE5, 0x01))) { #ifdef
> +DPControlPower
> +		// Set back power off
> +		if (bDPState_Change)
> +			ast_dp_PowerOnOff(dev, 0);
> +#endif
> +		return false;
> +	}
> +
> +	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE5, 0x00, 0x00);
> +
> +	for (i = 0; i < 32; i++) {
> +		/*
> +		 * CRE4[7:0]: Read-Pointer for EDID (Unit: 4bytes); valid range: 0~64
> +		 */
> +		ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE4, 0x00, (u8) i);
> +		j = 0;
> +
> +		/*
> +		 * CRD7[b0]: valid flag for EDID
> +		 * CRD6[b0]: mirror read pointer for EDID
> +		 */
> +		while ((ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD7, 0x01) != 0x01) ||
> +			(ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD6, 0xFF) != i)) {
> +			mdelay(j+1);
> +
> +			if (!(ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD1, 0x20) &&
> +				ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDC, 0x01) &&
> +				ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDF, 0x01))) {
> +				ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE5, 0x00, 0x01);
> +				return false;
> +			}
> +
> +			j++;
> +			if (j > 200) {
> +				ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE5, 0x00, 0x01);
> +				return false;
> +			}
> +		}
> +
> +		*(ediddata) = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD8, 0xFF);
> +		*(ediddata + 1) = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD9, 0xFF);
> +		*(ediddata + 2) = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDA, 0xFF);
> +		*(ediddata + 3) = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDB,
> +0xFF);
> +
> +		if (i == 31) {
> +			*(ediddata + 3) = *(ediddata + 3) + *(ediddata + 2);
> +			*(ediddata + 2) = 0;
> +		}
> +
> +		ediddata += 4;
> +	}
> +
> +	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE5, 0x00, 0x01);
> +
> +#ifdef DPControlPower
> +	// Set back power off
> +	if (bDPState_Change)
> +		ast_dp_PowerOnOff(dev, 0);
> +#endif
> +
> +	return true;
> +}
> +
> +/*
> + * Launch Aspeed DP
> + */
> +bool ast_dp_launch(struct drm_device *dev, u8 bPower) {
> +	u32 i = 0, j = 0, WaitCount = 1;
> +	u8 bDPTX = 0;
> +	u8 bDPExecute = 1;
> +
> +	struct ast_private *ast = to_ast_private(dev);
> +	// S3 come back, need more time to wait BMC ready.
> +	if (bPower)
> +		WaitCount = 300;
> +
> +	// Fill
> +	ast->tx_chip_type = AST_TX_NONE;
> +
> +	// Wait total count by different condition.
> +	// This is a temp solution for DP check
> +	for (j = 0; j < WaitCount; j++) {
> +		bDPTX = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD1, 0x0E);
> +
> +		if (bDPTX)
> +			break;
> +
> +		msleep(100);
> +	}
> +
> +	// 0xE : ASTDP with DPMCU FW handling
> +	if (bDPTX == 0x0E) {
> +		// Wait one second then timeout.
> +		i = 0;
> +
> +		while (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD1, 0x20) != 0x20) {
> +			i++;
> +			// wait 100 ms
> +			msleep(100);
> +
> +			if (i >= 10) {
> +				// DP would not be ready.
> +				bDPExecute = 0;
> +				break;
> +			}
> +		};
> +
> +		if (bDPExecute)
> +			ast->tx_chip_type = AST_TX_ASTDP;
> +	}
> +
> +	return true;
> +}
> +
> +#ifdef DPControlPower
> +
> +void ast_dp_PowerOnOff(struct drm_device *dev, u8 Mode) {
> +	struct ast_private *ast = to_ast_private(dev);
> +	// Read and Turn off DP PHY sleep
> +	u8 bE3 = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE3, 0x0F);
> +
> +	// Turn on DP PHY sleep
> +	if (!Mode)
> +		bE3 |= 0x10;
> +
> +	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE3, 0x00, bE3); // DP
> +Power on/off
> +
> +	// Save ASTDP power state
> +	ast->ASTDP_State = bE3;
> +}
> +
> +#endif
> +
> +void ast_dp_SetOnOff(struct drm_device *dev, u8 Mode) {
> +	struct ast_private *ast = to_ast_private(dev);
> +
> +	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE3, 0x00, Mode); //
> +video on/off
> +
> +	// Save ASTDP power state
> +	ast->ASTDP_State = Mode;
> +
> +    // If DP plug in and link successful then check video on / off status
> +	if (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDC, 0x01) &&
> +		ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDF, 0x01)) {
> +		Mode <<= 4;
> +		while (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDF, 0x10) != Mode) {
> +			// wait 1 ms
> +			mdelay(1);
> +		}
> +	}
> +}
> +
> +void ast_dp_SetOutput(struct drm_crtc *crtc, struct ast_vbios_mode_info
> +*vbios_mode) {
> +	struct ast_private *ast = to_ast_private(crtc->dev);
> +
> +	u32 ulRefreshRateIndex;
> +	u8 ModeIdx;
> +
> +	ulRefreshRateIndex = vbios_mode->enh_table->refresh_rate_index - 1;
> +
> +	switch (crtc->mode.crtc_hdisplay) {
> +	case 320:
> +		ModeIdx = 0x11;
> +		break;
> +	case 400:
> +		ModeIdx = 0x12;
> +		break;
> +	case 512:
> +		ModeIdx = 0x13;
> +		break;
> +	case 640:
> +		ModeIdx = (0x00 + (u8) ulRefreshRateIndex);
> +		break;
> +	case 800:
> +		ModeIdx = (0x04 + (u8) ulRefreshRateIndex);
> +		break;
> +	case 1024:
> +		ModeIdx = (0x09 + (u8) ulRefreshRateIndex);
> +		break;
> +	case 1152:
> +		ModeIdx = 0x1F;
> +		break;
> +	case 1280:
> +		if (crtc->mode.crtc_vdisplay == 800)
> +			ModeIdx = (0x17 - (u8) ulRefreshRateIndex);	// For RB/Non-RB
> +		else		// 1024
> +			ModeIdx = (0x0D + (u8) ulRefreshRateIndex);
> +		break;
> +	case 1360:
> +	case 1366:
> +		ModeIdx = 0x1E;
> +		break;
> +	case 1440:
> +		ModeIdx = (0x19 - (u8) ulRefreshRateIndex);	// For RB/Non-RB
> +		break;
> +	case 1600:
> +		if (crtc->mode.crtc_vdisplay == 900)
> +			ModeIdx = (0x1D - (u8) ulRefreshRateIndex);	// For RB/Non-RB
> +		else		//1200
> +			ModeIdx = 0x10;
> +		break;
> +	case 1680:
> +		ModeIdx = (0x1B - (u8) ulRefreshRateIndex);	// For RB/Non-RB
> +		break;
> +	case 1920:
> +		if (crtc->mode.crtc_vdisplay == 1080)
> +			ModeIdx = 0x15;
> +		else		//1200
> +			ModeIdx = 0x14;
> +		break;
> +	default:
> +		return;
> +	}
> +
> +	/*
> +	 * CRE0[7:0]: MISC0 ((0x00: 18-bpp) or (0x20: 24-bpp)
> +	 * CRE1[7:0]: MISC1 (default: 0x00)
> +	 * CRE2[7:0]: video format index (0x00 ~ 0x20 or 0x40 ~ 0x50)
> +	 */
> +	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE0, 0x00, 0x20);
> +	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE1, 0x00, 0x00);
> +	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE2, 0x00, ModeIdx); }
> diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h index 2cfce7dc9..e56d5d57b 100644
> --- a/drivers/gpu/drm/ast/ast_drv.h
> +++ b/drivers/gpu/drm/ast/ast_drv.h
> @@ -71,6 +71,7 @@ enum ast_tx_chip {
>   	AST_TX_SIL164,
>   	AST_TX_ITE66121,
>   	AST_TX_DP501,
> +	AST_TX_ASTDP,
>   };
>   
>   #define AST_DRAM_512Mx16 0
> @@ -175,6 +176,9 @@ struct ast_private {
>   	u8 dp501_maxclk;
>   	u8 *dp501_fw_addr;
>   	const struct firmware *dp501_fw;	/* dp501 fw */
> +
> +    // ASTDP
> +	u8 ASTDP_State;
>   };
>   
>   static inline struct ast_private *to_ast_private(struct drm_device *dev) @@ -356,5 +360,14 @@ bool ast_backup_fw(struct drm_device *dev, u8 *addr, u32 size);  bool ast_dp501_read_edid(struct drm_device *dev, u8 *ediddata);
>   u8 ast_get_dp501_max_clk(struct drm_device *dev);  void ast_init_3rdtx(struct drm_device *dev);
> +/* aspeed DP */
> +#define DPControlPower
> +bool ast_dp_read_edid(struct drm_device *dev, u8 *ediddata); bool
> +ast_dp_launch(struct drm_device *dev, u8 bPower); #ifdef DPControlPower
> +void ast_dp_PowerOnOff(struct drm_device *dev, u8 Mode); #endif void
> +ast_dp_SetOnOff(struct drm_device *dev, u8 Mode); void
> +ast_dp_SetOutput(struct drm_crtc *crtc, struct ast_vbios_mode_info
> +*vbios_mode);
>   
>   #endif
> diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c index 79a361867..de5d69888 100644
> --- a/drivers/gpu/drm/ast/ast_main.c
> +++ b/drivers/gpu/drm/ast/ast_main.c
> @@ -212,7 +212,7 @@ static int ast_detect_chip(struct drm_device *dev, bool *need_post)
>   		}
>   		break;
>   	}
> -
> +	ast->support_wide_screen = true;
>   	/* Check 3rd Tx option (digital output afaik) */
>   	ast->tx_chip_type = AST_TX_NONE;
>   
> @@ -230,7 +230,7 @@ static int ast_detect_chip(struct drm_device *dev, bool *need_post)
>   			ast->tx_chip_type = AST_TX_SIL164;
>   	}
>   
> -	if ((ast->chip == AST2300) || (ast->chip == AST2400)) {
> +	if ((ast->chip == AST2300) || (ast->chip == AST2400) || (ast->chip ==
> +AST2500)) {
>   		/*
>   		 * On AST2300 and 2400, look the configuration set by the SoC in
>   		 * the SOC scratch register #1 bits 11:8 (interestingly marked @@ -254,7 +254,8 @@ static int ast_detect_chip(struct drm_device *dev, bool *need_post)
>   		case 0x0c:
>   			ast->tx_chip_type = AST_TX_DP501;
>   		}
> -	}
> +	} else if (ast->chip == AST2600)
> +		ast_dp_launch(&ast->base, 0);
>   
>   	/* Print stuff for diagnostic purposes */
>   	switch(ast->tx_chip_type) {
> diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index 6bfaefa01..d7347d510 100644
> --- a/drivers/gpu/drm/ast/ast_mode.c
> +++ b/drivers/gpu/drm/ast/ast_mode.c
> @@ -987,20 +987,44 @@ static int ast_cursor_plane_init(struct ast_private *ast)  static void ast_crtc_dpms(struct drm_crtc *crtc, int mode)  {
>   	struct ast_private *ast = to_ast_private(crtc->dev);
> +	u8 ch = 0x03;
>   
>   	/* TODO: Maybe control display signal generation with
>   	 *       Sync Enable (bit CR17.7).
>   	 */
>   	switch (mode) {
>   	case DRM_MODE_DPMS_ON:
> -	case DRM_MODE_DPMS_STANDBY:
> -	case DRM_MODE_DPMS_SUSPEND:
> +		ast_set_index_reg_mask(ast, AST_IO_SEQ_PORT,  0x01, 0xdf, 0);
> +		ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb6, 0xfc, 0);
>   		if (ast->tx_chip_type == AST_TX_DP501)
>   			ast_set_dp501_video_output(crtc->dev, 1);
> +
> +		if (ast->tx_chip_type == AST_TX_ASTDP) { #ifdef DPControlPower
> +			ast_dp_PowerOnOff(crtc->dev, 1);
> +#endif
> +			ast_wait_for_vretrace(ast);
> +			ast_dp_SetOnOff(crtc->dev, 1);
> +		}
> +
> +		ast_crtc_load_lut(ast, crtc);
>   		break;
> +	case DRM_MODE_DPMS_STANDBY:
> +	case DRM_MODE_DPMS_SUSPEND:
>   	case DRM_MODE_DPMS_OFF:
> +		ch = mode;
>   		if (ast->tx_chip_type == AST_TX_DP501)
>   			ast_set_dp501_video_output(crtc->dev, 0);
> +
> +		if (ast->tx_chip_type == AST_TX_ASTDP) {
> +			ast_dp_SetOnOff(crtc->dev, 0);
> +#ifdef DPControlPower
> +			ast_dp_PowerOnOff(crtc->dev, 0);
> +#endif
> +		}
> +
> +		ast_set_index_reg_mask(ast, AST_IO_SEQ_PORT,  0x01, 0xdf, 0x20);
> +		ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb6, 0xfc, ch);
>   		break;
>   	}
>   }
> @@ -1044,6 +1068,8 @@ ast_crtc_helper_atomic_flush(struct drm_crtc *crtc,
>   	struct ast_private *ast = to_ast_private(crtc->dev);
>   	struct ast_crtc_state *ast_crtc_state = to_ast_crtc_state(crtc_state);
>   	struct ast_crtc_state *old_ast_crtc_state = to_ast_crtc_state(old_crtc_state);
> +struct ast_vbios_mode_info *vbios_mode_info =
> +		&ast_crtc_state->vbios_mode_info;
>   
>   	/*
>   	 * The gamma LUT has to be reloaded after changing the primary @@ -1051,6 +1077,10 @@ ast_crtc_helper_atomic_flush(struct drm_crtc *crtc,
>   	 */
>   	if (old_ast_crtc_state->format != ast_crtc_state->format)
>   		ast_crtc_load_lut(ast, crtc);
> +
> +	//Set Aspeed Display-Port
> +	if (ast->tx_chip_type == AST_TX_ASTDP)
> +		ast_dp_SetOutput(crtc, vbios_mode_info);
>   }
>   
>   static void
> @@ -1225,7 +1255,16 @@ static int ast_get_modes(struct drm_connector *connector)
>   			ast->dp501_maxclk = ast_get_dp501_max_clk(connector->dev);
>   		else
>   			kfree(edid);
> +	} else if (ast->tx_chip_type == AST_TX_ASTDP) {
> +		edid = kmalloc(128, GFP_KERNEL);
> +		if (!edid)
> +			return -ENOMEM;
> +
> +		flags = ast_dp_read_edid(connector->dev, (u8 *)edid);
> +		if (!flags)
> +			kfree(edid);
>   	}
> +
>   	if (!flags)
>   		edid = drm_get_edid(connector, &ast_connector->i2c->adapter);
>   	if (edid) {
> @@ -1256,10 +1295,12 @@ static enum drm_mode_status ast_mode_valid(struct drm_connector *connector,
>   			return MODE_OK;
>   		if ((mode->hdisplay == 1600) && (mode->vdisplay == 900))
>   			return MODE_OK;
> +		if ((mode->hdisplay == 1152) && (mode->vdisplay == 864))
> +			return MODE_OK;
>   
>   		if ((ast->chip == AST2100) || (ast->chip == AST2200) ||
>   		    (ast->chip == AST2300) || (ast->chip == AST2400) ||
> -		    (ast->chip == AST2500)) {
> +		    (ast->chip == AST2500) || (ast->chip == AST2600)) {
>   			if ((mode->hdisplay == 1920) && (mode->vdisplay == 1080))
>   				return MODE_OK;
>   
> @@ -1400,7 +1441,8 @@ int ast_mode_config_init(struct ast_private *ast)
>   	    ast->chip == AST2200 ||
>   	    ast->chip == AST2300 ||
>   	    ast->chip == AST2400 ||
> -	    ast->chip == AST2500) {
> +	    ast->chip == AST2500 ||
> +	    ast->chip == AST2600) {
>   		dev->mode_config.max_width = 1920;
>   		dev->mode_config.max_height = 2048;
>   	} else {
> diff --git a/drivers/gpu/drm/ast/ast_post.c b/drivers/gpu/drm/ast/ast_post.c index b5d92f652..0aa9cf0fb 100644
> --- a/drivers/gpu/drm/ast/ast_post.c
> +++ b/drivers/gpu/drm/ast/ast_post.c
> @@ -379,7 +379,9 @@ void ast_post_gpu(struct drm_device *dev)
>   	ast_enable_mmio(dev);
>   	ast_set_def_ext_reg(dev);
>   
> -	if (ast->config_mode == ast_use_p2a) {
> +	if (ast->chip == AST2600) {
> +		ast_dp_launch(dev, 1);
> +	} else if (ast->config_mode == ast_use_p2a) {
>   		if (ast->chip == AST2500)
>   			ast_post_chip_2500(dev);
>   		else if (ast->chip == AST2300 || ast->chip == AST2400)
> --
> 2.27.0
>
kernel test robot Jan. 1, 2022, 7:51 p.m. UTC | #4
Hi KuoHsiang,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on drm/drm-next]
[also build test WARNING on tegra-drm/drm/tegra/for-next v5.16-rc7]
[cannot apply to drm-intel/for-linux-next drm-tip/drm-tip drm-exynos/exynos-drm-next airlied/drm-next next-20211224]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/KuoHsiang-Chou/drm-ast-Create-the-driver-for-ASPEED-proprietory-Display-Port/20211122-183830
base:   git://anongit.freedesktop.org/drm/drm drm-next
config: i386-randconfig-c021-20211123 (https://download.01.org/0day-ci/archive/20220102/202201020329.lEcno4eh-lkp@intel.com/config)
compiler: gcc-9 (Debian 9.3.0-22) 9.3.0

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>


cocci warnings: (new ones prefixed by >>)
>> drivers/gpu/drm/ast/ast_dp.c:166:3-4: Unneeded semicolon

Please review and possibly fold the followup patch.

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
diff mbox series

Patch

diff --git a/drivers/gpu/drm/ast/Makefile b/drivers/gpu/drm/ast/Makefile
index 438a2d05b..9bd0756e0 100644
--- a/drivers/gpu/drm/ast/Makefile
+++ b/drivers/gpu/drm/ast/Makefile
@@ -3,6 +3,6 @@ 
 # Makefile for the drm device driver.  This driver provides support for the
 # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
 
-ast-y := ast_drv.o ast_main.o ast_mm.o ast_mode.o ast_post.o ast_dp501.o
+ast-y := ast_drv.o ast_main.o ast_mm.o ast_mode.o ast_post.o ast_dp501.o ast_dp.o
 
 obj-$(CONFIG_DRM_AST) := ast.o
diff --git a/drivers/gpu/drm/ast/ast_dp.c b/drivers/gpu/drm/ast/ast_dp.c
new file mode 100644
index 000000000..537eaf4fa
--- /dev/null
+++ b/drivers/gpu/drm/ast/ast_dp.c
@@ -0,0 +1,286 @@ 
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ */
+/*
+ * Authors: KuoHsiang Chou <kuohsiang_chou@aspeedtech.com>
+ */
+
+#include <linux/firmware.h>
+#include <linux/delay.h>
+#include <drm/drm_print.h>
+#include "ast_drv.h"
+
+bool ast_dp_read_edid(struct drm_device *dev, u8 *ediddata)
+{
+	struct ast_private *ast = to_ast_private(dev);
+	u8 i = 0, j = 0;
+
+#ifdef DPControlPower
+	u8 bDPState_Change = false;
+
+	// Check DP power off or not.
+	if (ast->ASTDP_State & 0x10) {
+		// DP power on
+		ast_dp_PowerOnOff(dev, 1);
+		bDPState_Change = true;
+	}
+#endif
+
+	/*
+	 * CRD1[b5]: DP MCU FW is executing
+	 * CRDC[b0]: DP link success
+	 * CRDF[b0]: DP HPD
+	 * CRE5[b0]: Host reading EDID process is done
+	 */
+	if (!(ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD1, 0x20) &&
+		ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDC, 0x01) &&
+		ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDF, 0x01) &&
+		ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE5, 0x01))) {
+#ifdef DPControlPower
+		// Set back power off
+		if (bDPState_Change)
+			ast_dp_PowerOnOff(dev, 0);
+#endif
+		return false;
+	}
+
+	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE5, 0x00, 0x00);
+
+	for (i = 0; i < 32; i++) {
+		/*
+		 * CRE4[7:0]: Read-Pointer for EDID (Unit: 4bytes); valid range: 0~64
+		 */
+		ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE4, 0x00, (u8) i);
+		j = 0;
+
+		/*
+		 * CRD7[b0]: valid flag for EDID
+		 * CRD6[b0]: mirror read pointer for EDID
+		 */
+		while ((ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD7, 0x01) != 0x01) ||
+			(ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD6, 0xFF) != i)) {
+			mdelay(j+1);
+
+			if (!(ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD1, 0x20) &&
+				ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDC, 0x01) &&
+				ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDF, 0x01))) {
+				ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE5, 0x00, 0x01);
+				return false;
+			}
+
+			j++;
+			if (j > 200) {
+				ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE5, 0x00, 0x01);
+				return false;
+			}
+		}
+
+		*(ediddata) = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD8, 0xFF);
+		*(ediddata + 1) = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD9, 0xFF);
+		*(ediddata + 2) = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDA, 0xFF);
+		*(ediddata + 3) = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDB, 0xFF);
+
+		if (i == 31) {
+			*(ediddata + 3) = *(ediddata + 3) + *(ediddata + 2);
+			*(ediddata + 2) = 0;
+		}
+
+		ediddata += 4;
+	}
+
+	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE5, 0x00, 0x01);
+
+#ifdef DPControlPower
+	// Set back power off
+	if (bDPState_Change)
+		ast_dp_PowerOnOff(dev, 0);
+#endif
+
+	return true;
+}
+
+/*
+ * Launch Aspeed DP
+ */
+bool ast_dp_launch(struct drm_device *dev, u8 bPower)
+{
+	u32 i = 0, j = 0, WaitCount = 1;
+	u8 bDPTX = 0;
+	u8 bDPExecute = 1;
+
+	struct ast_private *ast = to_ast_private(dev);
+	// S3 come back, need more time to wait BMC ready.
+	if (bPower)
+		WaitCount = 300;
+
+	// Fill
+	ast->tx_chip_type = AST_TX_NONE;
+
+	// Wait total count by different condition.
+	// This is a temp solution for DP check
+	for (j = 0; j < WaitCount; j++) {
+		bDPTX = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD1, 0x0E);
+
+		if (bDPTX)
+			break;
+
+		msleep(100);
+	}
+
+	// 0xE : ASTDP with DPMCU FW handling
+	if (bDPTX == 0x0E) {
+		// Wait one second then timeout.
+		i = 0;
+
+		while (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD1, 0x20) != 0x20) {
+			i++;
+			// wait 100 ms
+			msleep(100);
+
+			if (i >= 10) {
+				// DP would not be ready.
+				bDPExecute = 0;
+				break;
+			}
+		};
+
+		if (bDPExecute)
+			ast->tx_chip_type = AST_TX_ASTDP;
+	}
+
+	return true;
+}
+
+#ifdef DPControlPower
+
+void ast_dp_PowerOnOff(struct drm_device *dev, u8 Mode)
+{
+	struct ast_private *ast = to_ast_private(dev);
+	// Read and Turn off DP PHY sleep
+	u8 bE3 = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE3, 0x0F);
+
+	// Turn on DP PHY sleep
+	if (!Mode)
+		bE3 |= 0x10;
+
+	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE3, 0x00, bE3); // DP Power on/off
+
+	// Save ASTDP power state
+	ast->ASTDP_State = bE3;
+}
+
+#endif
+
+void ast_dp_SetOnOff(struct drm_device *dev, u8 Mode)
+{
+	struct ast_private *ast = to_ast_private(dev);
+
+	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE3, 0x00, Mode); // video on/off
+
+	// Save ASTDP power state
+	ast->ASTDP_State = Mode;
+
+    // If DP plug in and link successful then check video on / off status
+	if (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDC, 0x01) &&
+		ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDF, 0x01)) {
+		Mode <<= 4;
+		while (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDF, 0x10) != Mode) {
+			// wait 1 ms
+			mdelay(1);
+		}
+	}
+}
+
+void ast_dp_SetOutput(struct drm_crtc *crtc, struct ast_vbios_mode_info *vbios_mode)
+{
+	struct ast_private *ast = to_ast_private(crtc->dev);
+
+	u32 ulRefreshRateIndex;
+	u8 ModeIdx;
+
+	ulRefreshRateIndex = vbios_mode->enh_table->refresh_rate_index - 1;
+
+	switch (crtc->mode.crtc_hdisplay) {
+	case 320:
+		ModeIdx = 0x11;
+		break;
+	case 400:
+		ModeIdx = 0x12;
+		break;
+	case 512:
+		ModeIdx = 0x13;
+		break;
+	case 640:
+		ModeIdx = (0x00 + (u8) ulRefreshRateIndex);
+		break;
+	case 800:
+		ModeIdx = (0x04 + (u8) ulRefreshRateIndex);
+		break;
+	case 1024:
+		ModeIdx = (0x09 + (u8) ulRefreshRateIndex);
+		break;
+	case 1152:
+		ModeIdx = 0x1F;
+		break;
+	case 1280:
+		if (crtc->mode.crtc_vdisplay == 800)
+			ModeIdx = (0x17 - (u8) ulRefreshRateIndex);	// For RB/Non-RB
+		else		// 1024
+			ModeIdx = (0x0D + (u8) ulRefreshRateIndex);
+		break;
+	case 1360:
+	case 1366:
+		ModeIdx = 0x1E;
+		break;
+	case 1440:
+		ModeIdx = (0x19 - (u8) ulRefreshRateIndex);	// For RB/Non-RB
+		break;
+	case 1600:
+		if (crtc->mode.crtc_vdisplay == 900)
+			ModeIdx = (0x1D - (u8) ulRefreshRateIndex);	// For RB/Non-RB
+		else		//1200
+			ModeIdx = 0x10;
+		break;
+	case 1680:
+		ModeIdx = (0x1B - (u8) ulRefreshRateIndex);	// For RB/Non-RB
+		break;
+	case 1920:
+		if (crtc->mode.crtc_vdisplay == 1080)
+			ModeIdx = 0x15;
+		else		//1200
+			ModeIdx = 0x14;
+		break;
+	default:
+		return;
+	}
+
+	/*
+	 * CRE0[7:0]: MISC0 ((0x00: 18-bpp) or (0x20: 24-bpp)
+	 * CRE1[7:0]: MISC1 (default: 0x00)
+	 * CRE2[7:0]: video format index (0x00 ~ 0x20 or 0x40 ~ 0x50)
+	 */
+	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE0, 0x00, 0x20);
+	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE1, 0x00, 0x00);
+	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE2, 0x00, ModeIdx);
+}
diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h
index 2cfce7dc9..e56d5d57b 100644
--- a/drivers/gpu/drm/ast/ast_drv.h
+++ b/drivers/gpu/drm/ast/ast_drv.h
@@ -71,6 +71,7 @@  enum ast_tx_chip {
 	AST_TX_SIL164,
 	AST_TX_ITE66121,
 	AST_TX_DP501,
+	AST_TX_ASTDP,
 };
 
 #define AST_DRAM_512Mx16 0
@@ -175,6 +176,9 @@  struct ast_private {
 	u8 dp501_maxclk;
 	u8 *dp501_fw_addr;
 	const struct firmware *dp501_fw;	/* dp501 fw */
+
+    // ASTDP
+	u8 ASTDP_State;
 };
 
 static inline struct ast_private *to_ast_private(struct drm_device *dev)
@@ -356,5 +360,14 @@  bool ast_backup_fw(struct drm_device *dev, u8 *addr, u32 size);
 bool ast_dp501_read_edid(struct drm_device *dev, u8 *ediddata);
 u8 ast_get_dp501_max_clk(struct drm_device *dev);
 void ast_init_3rdtx(struct drm_device *dev);
+/* aspeed DP */
+#define DPControlPower
+bool ast_dp_read_edid(struct drm_device *dev, u8 *ediddata);
+bool ast_dp_launch(struct drm_device *dev, u8 bPower);
+#ifdef DPControlPower
+void ast_dp_PowerOnOff(struct drm_device *dev, u8 Mode);
+#endif
+void ast_dp_SetOnOff(struct drm_device *dev, u8 Mode);
+void ast_dp_SetOutput(struct drm_crtc *crtc, struct ast_vbios_mode_info *vbios_mode);
 
 #endif
diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c
index 79a361867..de5d69888 100644
--- a/drivers/gpu/drm/ast/ast_main.c
+++ b/drivers/gpu/drm/ast/ast_main.c
@@ -212,7 +212,7 @@  static int ast_detect_chip(struct drm_device *dev, bool *need_post)
 		}
 		break;
 	}
-
+	ast->support_wide_screen = true;
 	/* Check 3rd Tx option (digital output afaik) */
 	ast->tx_chip_type = AST_TX_NONE;
 
@@ -230,7 +230,7 @@  static int ast_detect_chip(struct drm_device *dev, bool *need_post)
 			ast->tx_chip_type = AST_TX_SIL164;
 	}
 
-	if ((ast->chip == AST2300) || (ast->chip == AST2400)) {
+	if ((ast->chip == AST2300) || (ast->chip == AST2400) || (ast->chip == AST2500)) {
 		/*
 		 * On AST2300 and 2400, look the configuration set by the SoC in
 		 * the SOC scratch register #1 bits 11:8 (interestingly marked
@@ -254,7 +254,8 @@  static int ast_detect_chip(struct drm_device *dev, bool *need_post)
 		case 0x0c:
 			ast->tx_chip_type = AST_TX_DP501;
 		}
-	}
+	} else if (ast->chip == AST2600)
+		ast_dp_launch(&ast->base, 0);
 
 	/* Print stuff for diagnostic purposes */
 	switch(ast->tx_chip_type) {
diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c
index 6bfaefa01..d7347d510 100644
--- a/drivers/gpu/drm/ast/ast_mode.c
+++ b/drivers/gpu/drm/ast/ast_mode.c
@@ -987,20 +987,44 @@  static int ast_cursor_plane_init(struct ast_private *ast)
 static void ast_crtc_dpms(struct drm_crtc *crtc, int mode)
 {
 	struct ast_private *ast = to_ast_private(crtc->dev);
+	u8 ch = 0x03;
 
 	/* TODO: Maybe control display signal generation with
 	 *       Sync Enable (bit CR17.7).
 	 */
 	switch (mode) {
 	case DRM_MODE_DPMS_ON:
-	case DRM_MODE_DPMS_STANDBY:
-	case DRM_MODE_DPMS_SUSPEND:
+		ast_set_index_reg_mask(ast, AST_IO_SEQ_PORT,  0x01, 0xdf, 0);
+		ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb6, 0xfc, 0);
 		if (ast->tx_chip_type == AST_TX_DP501)
 			ast_set_dp501_video_output(crtc->dev, 1);
+
+		if (ast->tx_chip_type == AST_TX_ASTDP) {
+#ifdef DPControlPower
+			ast_dp_PowerOnOff(crtc->dev, 1);
+#endif
+			ast_wait_for_vretrace(ast);
+			ast_dp_SetOnOff(crtc->dev, 1);
+		}
+
+		ast_crtc_load_lut(ast, crtc);
 		break;
+	case DRM_MODE_DPMS_STANDBY:
+	case DRM_MODE_DPMS_SUSPEND:
 	case DRM_MODE_DPMS_OFF:
+		ch = mode;
 		if (ast->tx_chip_type == AST_TX_DP501)
 			ast_set_dp501_video_output(crtc->dev, 0);
+
+		if (ast->tx_chip_type == AST_TX_ASTDP) {
+			ast_dp_SetOnOff(crtc->dev, 0);
+#ifdef DPControlPower
+			ast_dp_PowerOnOff(crtc->dev, 0);
+#endif
+		}
+
+		ast_set_index_reg_mask(ast, AST_IO_SEQ_PORT,  0x01, 0xdf, 0x20);
+		ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb6, 0xfc, ch);
 		break;
 	}
 }
@@ -1044,6 +1068,8 @@  ast_crtc_helper_atomic_flush(struct drm_crtc *crtc,
 	struct ast_private *ast = to_ast_private(crtc->dev);
 	struct ast_crtc_state *ast_crtc_state = to_ast_crtc_state(crtc_state);
 	struct ast_crtc_state *old_ast_crtc_state = to_ast_crtc_state(old_crtc_state);
+struct ast_vbios_mode_info *vbios_mode_info =
+		&ast_crtc_state->vbios_mode_info;
 
 	/*
 	 * The gamma LUT has to be reloaded after changing the primary
@@ -1051,6 +1077,10 @@  ast_crtc_helper_atomic_flush(struct drm_crtc *crtc,
 	 */
 	if (old_ast_crtc_state->format != ast_crtc_state->format)
 		ast_crtc_load_lut(ast, crtc);
+
+	//Set Aspeed Display-Port
+	if (ast->tx_chip_type == AST_TX_ASTDP)
+		ast_dp_SetOutput(crtc, vbios_mode_info);
 }
 
 static void
@@ -1225,7 +1255,16 @@  static int ast_get_modes(struct drm_connector *connector)
 			ast->dp501_maxclk = ast_get_dp501_max_clk(connector->dev);
 		else
 			kfree(edid);
+	} else if (ast->tx_chip_type == AST_TX_ASTDP) {
+		edid = kmalloc(128, GFP_KERNEL);
+		if (!edid)
+			return -ENOMEM;
+
+		flags = ast_dp_read_edid(connector->dev, (u8 *)edid);
+		if (!flags)
+			kfree(edid);
 	}
+
 	if (!flags)
 		edid = drm_get_edid(connector, &ast_connector->i2c->adapter);
 	if (edid) {
@@ -1256,10 +1295,12 @@  static enum drm_mode_status ast_mode_valid(struct drm_connector *connector,
 			return MODE_OK;
 		if ((mode->hdisplay == 1600) && (mode->vdisplay == 900))
 			return MODE_OK;
+		if ((mode->hdisplay == 1152) && (mode->vdisplay == 864))
+			return MODE_OK;
 
 		if ((ast->chip == AST2100) || (ast->chip == AST2200) ||
 		    (ast->chip == AST2300) || (ast->chip == AST2400) ||
-		    (ast->chip == AST2500)) {
+		    (ast->chip == AST2500) || (ast->chip == AST2600)) {
 			if ((mode->hdisplay == 1920) && (mode->vdisplay == 1080))
 				return MODE_OK;
 
@@ -1400,7 +1441,8 @@  int ast_mode_config_init(struct ast_private *ast)
 	    ast->chip == AST2200 ||
 	    ast->chip == AST2300 ||
 	    ast->chip == AST2400 ||
-	    ast->chip == AST2500) {
+	    ast->chip == AST2500 ||
+	    ast->chip == AST2600) {
 		dev->mode_config.max_width = 1920;
 		dev->mode_config.max_height = 2048;
 	} else {
diff --git a/drivers/gpu/drm/ast/ast_post.c b/drivers/gpu/drm/ast/ast_post.c
index b5d92f652..0aa9cf0fb 100644
--- a/drivers/gpu/drm/ast/ast_post.c
+++ b/drivers/gpu/drm/ast/ast_post.c
@@ -379,7 +379,9 @@  void ast_post_gpu(struct drm_device *dev)
 	ast_enable_mmio(dev);
 	ast_set_def_ext_reg(dev);
 
-	if (ast->config_mode == ast_use_p2a) {
+	if (ast->chip == AST2600) {
+		ast_dp_launch(dev, 1);
+	} else if (ast->config_mode == ast_use_p2a) {
 		if (ast->chip == AST2500)
 			ast_post_chip_2500(dev);
 		else if (ast->chip == AST2300 || ast->chip == AST2400)