// SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2021, ASPEED Technology Inc. // Authors: KuoHsiang Chou #include #include #include #include "ast_drv.h" bool ast_astdp_is_connected(struct ast_device *ast) { if (!ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD1, ASTDP_MCU_FW_EXECUTING)) return false; if (!ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDF, ASTDP_HPD)) return false; if (!ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDC, ASTDP_LINK_SUCCESS)) return false; return true; } int ast_astdp_read_edid(struct drm_device *dev, u8 *ediddata) { struct ast_device *ast = to_ast_device(dev); u8 i = 0, j = 0; /* * CRD1[b5]: DP MCU FW is executing * CRDC[b0]: DP link success * CRDF[b0]: DP HPD * CRE5[b0]: Host reading EDID process is done */ if (!(ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD1, ASTDP_MCU_FW_EXECUTING) && ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDC, ASTDP_LINK_SUCCESS) && ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDF, ASTDP_HPD) && ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE5, ASTDP_HOST_EDID_READ_DONE_MASK))) { goto err_astdp_edid_not_ready; } ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE5, (u8) ~ASTDP_HOST_EDID_READ_DONE_MASK, 0x00); for (i = 0; i < 32; i++) { /* * CRE4[7:0]: Read-Pointer for EDID (Unit: 4bytes); valid range: 0~64 */ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE4, ASTDP_AND_CLEAR_MASK, (u8)i); j = 0; /* * CRD7[b0]: valid flag for EDID * CRD6[b0]: mirror read pointer for EDID */ while ((ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD7, ASTDP_EDID_VALID_FLAG_MASK) != 0x01) || (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD6, ASTDP_EDID_READ_POINTER_MASK) != i)) { /* * Delay are getting longer with each retry. * 1. The Delays are often 2 loops when users request "Display Settings" * of right-click of mouse. * 2. The Delays are often longer a lot when system resume from S3/S4. */ mdelay(j+1); if (!(ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD1, ASTDP_MCU_FW_EXECUTING) && ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDC, ASTDP_LINK_SUCCESS) && ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDF, ASTDP_HPD))) { goto err_astdp_jump_out_loop_of_edid; } j++; if (j > 200) goto err_astdp_jump_out_loop_of_edid; } *(ediddata) = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD8, ASTDP_EDID_READ_DATA_MASK); *(ediddata + 1) = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD9, ASTDP_EDID_READ_DATA_MASK); *(ediddata + 2) = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDA, ASTDP_EDID_READ_DATA_MASK); *(ediddata + 3) = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDB, ASTDP_EDID_READ_DATA_MASK); if (i == 31) { /* * For 128-bytes EDID_1.3, * 1. Add the value of Bytes-126 to Bytes-127. * The Bytes-127 is Checksum. Sum of all 128bytes should * equal 0 (mod 256). * 2. Modify Bytes-126 to be 0. * The Bytes-126 indicates the Number of extensions to * follow. 0 represents noextensions. */ *(ediddata + 3) = *(ediddata + 3) + *(ediddata + 2); *(ediddata + 2) = 0; } ediddata += 4; } ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE5, (u8) ~ASTDP_HOST_EDID_READ_DONE_MASK, ASTDP_HOST_EDID_READ_DONE); return 0; err_astdp_jump_out_loop_of_edid: ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE5, (u8) ~ASTDP_HOST_EDID_READ_DONE_MASK, ASTDP_HOST_EDID_READ_DONE); return (~(j+256) + 1); err_astdp_edid_not_ready: if (!(ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD1, ASTDP_MCU_FW_EXECUTING))) return (~0xD1 + 1); if (!(ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDC, ASTDP_LINK_SUCCESS))) return (~0xDC + 1); if (!(ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDF, ASTDP_HPD))) return (~0xDF + 1); if (!(ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE5, ASTDP_HOST_EDID_READ_DONE_MASK))) return (~0xE5 + 1); return 0; } /* * Launch Aspeed DP */ void ast_dp_launch(struct drm_device *dev) { u32 i = 0; u8 bDPExecute = 1; struct ast_device *ast = to_ast_device(dev); // Wait one second then timeout. while (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD1, ASTDP_MCU_FW_EXECUTING) != ASTDP_MCU_FW_EXECUTING) { i++; // wait 100 ms msleep(100); if (i >= 10) { // DP would not be ready. bDPExecute = 0; break; } } if (!bDPExecute) drm_err(dev, "Wait DPMCU executing timeout\n"); ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE5, (u8) ~ASTDP_HOST_EDID_READ_DONE_MASK, ASTDP_HOST_EDID_READ_DONE); } void ast_dp_power_on_off(struct drm_device *dev, bool on) { struct ast_device *ast = to_ast_device(dev); // Read and Turn off DP PHY sleep u8 bE3 = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE3, AST_DP_VIDEO_ENABLE); // Turn on DP PHY sleep if (!on) bE3 |= AST_DP_PHY_SLEEP; // DP Power on/off ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE3, (u8) ~AST_DP_PHY_SLEEP, bE3); } void ast_dp_set_on_off(struct drm_device *dev, bool on) { struct ast_device *ast = to_ast_device(dev); u8 video_on_off = on; u32 i = 0; // Video On/Off ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE3, (u8) ~AST_DP_VIDEO_ENABLE, on); // If DP plug in and link successful then check video on / off status if (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDC, ASTDP_LINK_SUCCESS) && ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDF, ASTDP_HPD)) { video_on_off <<= 4; while (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDF, ASTDP_MIRROR_VIDEO_ENABLE) != video_on_off) { // wait 1 ms mdelay(1); if (++i > 200) break; } } } void ast_dp_set_mode(struct drm_crtc *crtc, struct ast_vbios_mode_info *vbios_mode) { struct ast_device *ast = to_ast_device(crtc->dev); u32 ulRefreshRateIndex; u8 ModeIdx; ulRefreshRateIndex = vbios_mode->enh_table->refresh_rate_index - 1; switch (crtc->mode.crtc_hdisplay) { case 320: ModeIdx = ASTDP_320x240_60; break; case 400: ModeIdx = ASTDP_400x300_60; break; case 512: ModeIdx = ASTDP_512x384_60; break; case 640: ModeIdx = (ASTDP_640x480_60 + (u8) ulRefreshRateIndex); break; case 800: ModeIdx = (ASTDP_800x600_56 + (u8) ulRefreshRateIndex); break; case 1024: ModeIdx = (ASTDP_1024x768_60 + (u8) ulRefreshRateIndex); break; case 1152: ModeIdx = ASTDP_1152x864_75; break; case 1280: if (crtc->mode.crtc_vdisplay == 800) ModeIdx = (ASTDP_1280x800_60_RB - (u8) ulRefreshRateIndex); else // 1024 ModeIdx = (ASTDP_1280x1024_60 + (u8) ulRefreshRateIndex); break; case 1360: case 1366: ModeIdx = ASTDP_1366x768_60; break; case 1440: ModeIdx = (ASTDP_1440x900_60_RB - (u8) ulRefreshRateIndex); break; case 1600: if (crtc->mode.crtc_vdisplay == 900) ModeIdx = (ASTDP_1600x900_60_RB - (u8) ulRefreshRateIndex); else //1200 ModeIdx = ASTDP_1600x1200_60; break; case 1680: ModeIdx = (ASTDP_1680x1050_60_RB - (u8) ulRefreshRateIndex); break; case 1920: if (crtc->mode.crtc_vdisplay == 1080) ModeIdx = ASTDP_1920x1080_60; else //1200 ModeIdx = ASTDP_1920x1200_60; break; default: return; } /* * CRE0[7:0]: MISC0 ((0x00: 18-bpp) or (0x20: 24-bpp) * CRE1[7:0]: MISC1 (default: 0x00) * CRE2[7:0]: video format index (0x00 ~ 0x20 or 0x40 ~ 0x50) */ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE0, ASTDP_AND_CLEAR_MASK, ASTDP_MISC0_24bpp); ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE1, ASTDP_AND_CLEAR_MASK, ASTDP_MISC1); ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE2, ASTDP_AND_CLEAR_MASK, ModeIdx); }