xref: /openbmc/linux/drivers/gpu/drm/ast/ast_dp.c (revision f0931824)
1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2021, ASPEED Technology Inc.
3 // Authors: KuoHsiang Chou <kuohsiang_chou@aspeedtech.com>
4 
5 #include <linux/firmware.h>
6 #include <linux/delay.h>
7 #include <drm/drm_print.h>
8 #include "ast_drv.h"
9 
10 bool ast_astdp_is_connected(struct ast_device *ast)
11 {
12 	if (!ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD1, ASTDP_MCU_FW_EXECUTING))
13 		return false;
14 	if (!ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDF, ASTDP_HPD))
15 		return false;
16 	if (!ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDC, ASTDP_LINK_SUCCESS))
17 		return false;
18 	return true;
19 }
20 
21 int ast_astdp_read_edid(struct drm_device *dev, u8 *ediddata)
22 {
23 	struct ast_device *ast = to_ast_device(dev);
24 	u8 i = 0, j = 0;
25 
26 	/*
27 	 * CRD1[b5]: DP MCU FW is executing
28 	 * CRDC[b0]: DP link success
29 	 * CRDF[b0]: DP HPD
30 	 * CRE5[b0]: Host reading EDID process is done
31 	 */
32 	if (!(ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD1, ASTDP_MCU_FW_EXECUTING) &&
33 		ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDC, ASTDP_LINK_SUCCESS) &&
34 		ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDF, ASTDP_HPD) &&
35 		ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE5,
36 								ASTDP_HOST_EDID_READ_DONE_MASK))) {
37 		goto err_astdp_edid_not_ready;
38 	}
39 
40 	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE5, (u8) ~ASTDP_HOST_EDID_READ_DONE_MASK,
41 							0x00);
42 
43 	for (i = 0; i < 32; i++) {
44 		/*
45 		 * CRE4[7:0]: Read-Pointer for EDID (Unit: 4bytes); valid range: 0~64
46 		 */
47 		ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE4,
48 				       ASTDP_AND_CLEAR_MASK, (u8)i);
49 		j = 0;
50 
51 		/*
52 		 * CRD7[b0]: valid flag for EDID
53 		 * CRD6[b0]: mirror read pointer for EDID
54 		 */
55 		while ((ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD7,
56 				ASTDP_EDID_VALID_FLAG_MASK) != 0x01) ||
57 			(ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD6,
58 						ASTDP_EDID_READ_POINTER_MASK) != i)) {
59 			/*
60 			 * Delay are getting longer with each retry.
61 			 * 1. The Delays are often 2 loops when users request "Display Settings"
62 			 *	  of right-click of mouse.
63 			 * 2. The Delays are often longer a lot when system resume from S3/S4.
64 			 */
65 			mdelay(j+1);
66 
67 			if (!(ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD1,
68 							ASTDP_MCU_FW_EXECUTING) &&
69 				ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDC,
70 							ASTDP_LINK_SUCCESS) &&
71 				ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDF, ASTDP_HPD))) {
72 				goto err_astdp_jump_out_loop_of_edid;
73 			}
74 
75 			j++;
76 			if (j > 200)
77 				goto err_astdp_jump_out_loop_of_edid;
78 		}
79 
80 		*(ediddata) = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT,
81 							0xD8, ASTDP_EDID_READ_DATA_MASK);
82 		*(ediddata + 1) = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD9,
83 								ASTDP_EDID_READ_DATA_MASK);
84 		*(ediddata + 2) = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDA,
85 								ASTDP_EDID_READ_DATA_MASK);
86 		*(ediddata + 3) = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDB,
87 								ASTDP_EDID_READ_DATA_MASK);
88 
89 		if (i == 31) {
90 			/*
91 			 * For 128-bytes EDID_1.3,
92 			 * 1. Add the value of Bytes-126 to Bytes-127.
93 			 *		The Bytes-127 is Checksum. Sum of all 128bytes should
94 			 *		equal 0	(mod 256).
95 			 * 2. Modify Bytes-126 to be 0.
96 			 *		The Bytes-126 indicates the Number of extensions to
97 			 *		follow. 0 represents noextensions.
98 			 */
99 			*(ediddata + 3) = *(ediddata + 3) + *(ediddata + 2);
100 			*(ediddata + 2) = 0;
101 		}
102 
103 		ediddata += 4;
104 	}
105 
106 	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE5, (u8) ~ASTDP_HOST_EDID_READ_DONE_MASK,
107 							ASTDP_HOST_EDID_READ_DONE);
108 
109 	return 0;
110 
111 err_astdp_jump_out_loop_of_edid:
112 	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE5,
113 							(u8) ~ASTDP_HOST_EDID_READ_DONE_MASK,
114 							ASTDP_HOST_EDID_READ_DONE);
115 	return (~(j+256) + 1);
116 
117 err_astdp_edid_not_ready:
118 	if (!(ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD1, ASTDP_MCU_FW_EXECUTING)))
119 		return (~0xD1 + 1);
120 	if (!(ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDC, ASTDP_LINK_SUCCESS)))
121 		return (~0xDC + 1);
122 	if (!(ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDF, ASTDP_HPD)))
123 		return (~0xDF + 1);
124 	if (!(ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE5, ASTDP_HOST_EDID_READ_DONE_MASK)))
125 		return (~0xE5 + 1);
126 
127 	return	0;
128 }
129 
130 /*
131  * Launch Aspeed DP
132  */
133 void ast_dp_launch(struct drm_device *dev)
134 {
135 	u32 i = 0;
136 	u8 bDPExecute = 1;
137 	struct ast_device *ast = to_ast_device(dev);
138 
139 	// Wait one second then timeout.
140 	while (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD1, ASTDP_MCU_FW_EXECUTING) !=
141 		ASTDP_MCU_FW_EXECUTING) {
142 		i++;
143 		// wait 100 ms
144 		msleep(100);
145 
146 		if (i >= 10) {
147 			// DP would not be ready.
148 			bDPExecute = 0;
149 			break;
150 		}
151 	}
152 
153 	if (!bDPExecute)
154 		drm_err(dev, "Wait DPMCU executing timeout\n");
155 
156 	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE5,
157 			       (u8) ~ASTDP_HOST_EDID_READ_DONE_MASK,
158 			       ASTDP_HOST_EDID_READ_DONE);
159 }
160 
161 
162 
163 void ast_dp_power_on_off(struct drm_device *dev, bool on)
164 {
165 	struct ast_device *ast = to_ast_device(dev);
166 	// Read and Turn off DP PHY sleep
167 	u8 bE3 = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE3, AST_DP_VIDEO_ENABLE);
168 
169 	// Turn on DP PHY sleep
170 	if (!on)
171 		bE3 |= AST_DP_PHY_SLEEP;
172 
173 	// DP Power on/off
174 	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE3, (u8) ~AST_DP_PHY_SLEEP, bE3);
175 }
176 
177 
178 
179 void ast_dp_set_on_off(struct drm_device *dev, bool on)
180 {
181 	struct ast_device *ast = to_ast_device(dev);
182 	u8 video_on_off = on;
183 	u32 i = 0;
184 
185 	// Video On/Off
186 	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE3, (u8) ~AST_DP_VIDEO_ENABLE, on);
187 
188 	// If DP plug in and link successful then check video on / off status
189 	if (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDC, ASTDP_LINK_SUCCESS) &&
190 		ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDF, ASTDP_HPD)) {
191 		video_on_off <<= 4;
192 		while (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDF,
193 						ASTDP_MIRROR_VIDEO_ENABLE) != video_on_off) {
194 			// wait 1 ms
195 			mdelay(1);
196 			if (++i > 200)
197 				break;
198 		}
199 	}
200 }
201 
202 void ast_dp_set_mode(struct drm_crtc *crtc, struct ast_vbios_mode_info *vbios_mode)
203 {
204 	struct ast_device *ast = to_ast_device(crtc->dev);
205 
206 	u32 ulRefreshRateIndex;
207 	u8 ModeIdx;
208 
209 	ulRefreshRateIndex = vbios_mode->enh_table->refresh_rate_index - 1;
210 
211 	switch (crtc->mode.crtc_hdisplay) {
212 	case 320:
213 		ModeIdx = ASTDP_320x240_60;
214 		break;
215 	case 400:
216 		ModeIdx = ASTDP_400x300_60;
217 		break;
218 	case 512:
219 		ModeIdx = ASTDP_512x384_60;
220 		break;
221 	case 640:
222 		ModeIdx = (ASTDP_640x480_60 + (u8) ulRefreshRateIndex);
223 		break;
224 	case 800:
225 		ModeIdx = (ASTDP_800x600_56 + (u8) ulRefreshRateIndex);
226 		break;
227 	case 1024:
228 		ModeIdx = (ASTDP_1024x768_60 + (u8) ulRefreshRateIndex);
229 		break;
230 	case 1152:
231 		ModeIdx = ASTDP_1152x864_75;
232 		break;
233 	case 1280:
234 		if (crtc->mode.crtc_vdisplay == 800)
235 			ModeIdx = (ASTDP_1280x800_60_RB - (u8) ulRefreshRateIndex);
236 		else		// 1024
237 			ModeIdx = (ASTDP_1280x1024_60 + (u8) ulRefreshRateIndex);
238 		break;
239 	case 1360:
240 	case 1366:
241 		ModeIdx = ASTDP_1366x768_60;
242 		break;
243 	case 1440:
244 		ModeIdx = (ASTDP_1440x900_60_RB - (u8) ulRefreshRateIndex);
245 		break;
246 	case 1600:
247 		if (crtc->mode.crtc_vdisplay == 900)
248 			ModeIdx = (ASTDP_1600x900_60_RB - (u8) ulRefreshRateIndex);
249 		else		//1200
250 			ModeIdx = ASTDP_1600x1200_60;
251 		break;
252 	case 1680:
253 		ModeIdx = (ASTDP_1680x1050_60_RB - (u8) ulRefreshRateIndex);
254 		break;
255 	case 1920:
256 		if (crtc->mode.crtc_vdisplay == 1080)
257 			ModeIdx = ASTDP_1920x1080_60;
258 		else		//1200
259 			ModeIdx = ASTDP_1920x1200_60;
260 		break;
261 	default:
262 		return;
263 	}
264 
265 	/*
266 	 * CRE0[7:0]: MISC0 ((0x00: 18-bpp) or (0x20: 24-bpp)
267 	 * CRE1[7:0]: MISC1 (default: 0x00)
268 	 * CRE2[7:0]: video format index (0x00 ~ 0x20 or 0x40 ~ 0x50)
269 	 */
270 	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE0, ASTDP_AND_CLEAR_MASK,
271 			       ASTDP_MISC0_24bpp);
272 	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE1, ASTDP_AND_CLEAR_MASK, ASTDP_MISC1);
273 	ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE2, ASTDP_AND_CLEAR_MASK, ModeIdx);
274 }
275