Skip to content

Commit 594e9c0

Browse files
Kuo-Hsiang-Choutdz
authored andcommitted
drm/ast: Create the driver for ASPEED proprietory Display-Port
V1: 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. V2: Modules description: 1. ASTDP (ASPEED DisplayPort) is controlled by dedicated AST-MCU (ASPEED propriatary MCU). 2. MCU is looping in charged of HPD, Read EDID, Link Training with DP sink. 3. ASTDP and AST-MUC reside in BMC (Baseboard Management controller) addressing-space. 4. ASPEED DRM driver requests MCU to get HPD and EDID by CR-scratched register. Booting sequence: 1. Check if TX is ASTDP // ast_dp_launch() 2. Check if DP-MCU FW has loaded // ast_dp_launch() 3. Read EDID // ast_dp_read_edid() 4. Resolution switch // ast_dp_SetOutput() V3: 1. Remove unneeded semicolon. 2. Apply to git://anongit.freedesktop.org/drm/drm, instead of git://anongit.freedesktop.org/drm/drm-misc 3. Resolve auto build test WARNINGs on V1 patch. V4: 1. Sync code-base with kernel 5.17_rc6 2. Remove the define of DPControlPower, because DP chips need to be powered on to be used. 3. Remove the switches of PHY and Display from EDID procedure. 4. Revise increaing delay to fixed delay, because this version kernel doesn't detect minitor consistenntly. 5. Create clean-up code used for reset of power state on errors with -EIO manner. 6. Revise the DP detection by TX type and its DP-FW status during booting and resume. 7. Correct the CamelCase Style. 8. Use register reading while needing, and remove to hold full register. 9. Instead of 'u8', revise to 'bool' on swwitch of PHY and video. 10.Correct typo 11.Remove the duplicated copy of TX definition. 12.Use EDID_LENGTH as the constant of 128. Signed-off-by: KuoHsiang Chou <[email protected]> Reviewed-by: Thomas Zimmermann <[email protected]> Signed-off-by: Thomas Zimmermann <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
1 parent 6e944f5 commit 594e9c0

File tree

6 files changed

+524
-8
lines changed

6 files changed

+524
-8
lines changed

drivers/gpu/drm/ast/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@
33
# Makefile for the drm device driver. This driver provides support for the
44
# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
55

6-
ast-y := ast_drv.o ast_i2c.o ast_main.o ast_mm.o ast_mode.o ast_post.o ast_dp501.o
6+
ast-y := ast_drv.o ast_i2c.o ast_main.o ast_mm.o ast_mode.o ast_post.o ast_dp501.o ast_dp.o
77

88
obj-$(CONFIG_DRM_AST) := ast.o

drivers/gpu/drm/ast/ast_dp.c

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

0 commit comments

Comments
 (0)