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
10bool ast_astdp_is_connected(struct ast_device *ast)
11{
12	if (!ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xD1, ASTDP_MCU_FW_EXECUTING))
13		return false;
14	if (!ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xDF, ASTDP_HPD))
15		return false;
16	if (!ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xDC, ASTDP_LINK_SUCCESS))
17		return false;
18	return true;
19}
20
21int 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_VGACRI, 0xD1, ASTDP_MCU_FW_EXECUTING) &&
33		ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xDC, ASTDP_LINK_SUCCESS) &&
34		ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xDF, ASTDP_HPD) &&
35		ast_get_index_reg_mask(ast, AST_IO_VGACRI, 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_VGACRI, 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_VGACRI, 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_VGACRI, 0xD7,
56				ASTDP_EDID_VALID_FLAG_MASK) != 0x01) ||
57			(ast_get_index_reg_mask(ast, AST_IO_VGACRI, 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_VGACRI, 0xD1,
68							ASTDP_MCU_FW_EXECUTING) &&
69				ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xDC,
70							ASTDP_LINK_SUCCESS) &&
71				ast_get_index_reg_mask(ast, AST_IO_VGACRI, 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_VGACRI,
81							0xD8, ASTDP_EDID_READ_DATA_MASK);
82		*(ediddata + 1) = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xD9,
83								ASTDP_EDID_READ_DATA_MASK);
84		*(ediddata + 2) = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xDA,
85								ASTDP_EDID_READ_DATA_MASK);
86		*(ediddata + 3) = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 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_VGACRI, 0xE5, (u8) ~ASTDP_HOST_EDID_READ_DONE_MASK,
107							ASTDP_HOST_EDID_READ_DONE);
108
109	return 0;
110
111err_astdp_jump_out_loop_of_edid:
112	ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xE5,
113							(u8) ~ASTDP_HOST_EDID_READ_DONE_MASK,
114							ASTDP_HOST_EDID_READ_DONE);
115	return (~(j+256) + 1);
116
117err_astdp_edid_not_ready:
118	if (!(ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xD1, ASTDP_MCU_FW_EXECUTING)))
119		return (~0xD1 + 1);
120	if (!(ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xDC, ASTDP_LINK_SUCCESS)))
121		return (~0xDC + 1);
122	if (!(ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xDF, ASTDP_HPD)))
123		return (~0xDF + 1);
124	if (!(ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xE5, ASTDP_HOST_EDID_READ_DONE_MASK)))
125		return (~0xE5 + 1);
126
127	return	0;
128}
129
130/*
131 * Launch Aspeed DP
132 */
133void 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_VGACRI, 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_VGACRI, 0xE5,
157			       (u8) ~ASTDP_HOST_EDID_READ_DONE_MASK,
158			       ASTDP_HOST_EDID_READ_DONE);
159}
160
161
162
163void 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_VGACRI, 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_VGACRI, 0xE3, (u8) ~AST_DP_PHY_SLEEP, bE3);
175}
176
177
178
179void 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_VGACRI, 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_VGACRI, 0xDC, ASTDP_LINK_SUCCESS) &&
190		ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xDF, ASTDP_HPD)) {
191		video_on_off <<= 4;
192		while (ast_get_index_reg_mask(ast, AST_IO_VGACRI, 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
202void 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_VGACRI, 0xE0, ASTDP_AND_CLEAR_MASK,
271			       ASTDP_MISC0_24bpp);
272	ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xE1, ASTDP_AND_CLEAR_MASK, ASTDP_MISC1);
273	ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xE2, ASTDP_AND_CLEAR_MASK, ModeIdx);
274}
275