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