|
| 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