]> Git Repo - linux.git/blob - drivers/gpu/drm/ast/ast_dp.c
Merge tag 'apparmor-pr-2024-07-25' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux.git] / drivers / gpu / drm / ast / ast_dp.c
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 bool 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
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_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
111 err_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
117 err_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  */
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_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
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_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
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_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
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_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 }
This page took 0.047353 seconds and 4 git commands to generate.