diff options
Diffstat (limited to 'drivers/gpu/drm/ast')
-rw-r--r-- | drivers/gpu/drm/ast/Makefile | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/ast/ast_dp.c | 406 | ||||
-rw-r--r-- | drivers/gpu/drm/ast/ast_dp501.c | 184 | ||||
-rw-r--r-- | drivers/gpu/drm/ast/ast_drv.h | 43 | ||||
-rw-r--r-- | drivers/gpu/drm/ast/ast_main.c | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/ast/ast_mode.c | 576 | ||||
-rw-r--r-- | drivers/gpu/drm/ast/ast_post.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/ast/ast_reg.h | 22 | ||||
-rw-r--r-- | drivers/gpu/drm/ast/ast_sil164.c | 127 | ||||
-rw-r--r-- | drivers/gpu/drm/ast/ast_vga.c | 127 |
10 files changed, 748 insertions, 749 deletions
diff --git a/drivers/gpu/drm/ast/Makefile b/drivers/gpu/drm/ast/Makefile index d794c076bc24..47da848fa3fc 100644 --- a/drivers/gpu/drm/ast/Makefile +++ b/drivers/gpu/drm/ast/Makefile @@ -11,6 +11,8 @@ ast-y := \ ast_main.o \ ast_mm.o \ ast_mode.o \ - ast_post.o + ast_post.o \ + ast_sil164.o \ + ast_vga.o obj-$(CONFIG_DRM_AST) := ast.o diff --git a/drivers/gpu/drm/ast/ast_dp.c b/drivers/gpu/drm/ast/ast_dp.c index e6c7f0d64e99..00b364f9a71e 100644 --- a/drivers/gpu/drm/ast/ast_dp.c +++ b/drivers/gpu/drm/ast/ast_dp.c @@ -4,87 +4,94 @@ #include <linux/firmware.h> #include <linux/delay.h> + +#include <drm/drm_atomic_state_helper.h> +#include <drm/drm_edid.h> +#include <drm/drm_modeset_helper_vtables.h> #include <drm/drm_print.h> +#include <drm/drm_probe_helper.h> + #include "ast_drv.h" -bool ast_astdp_is_connected(struct ast_device *ast) +static bool ast_astdp_is_connected(struct ast_device *ast) { - if (!ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xD1, ASTDP_MCU_FW_EXECUTING)) - return false; - if (!ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xDF, ASTDP_HPD)) - return false; - if (!ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xDC, ASTDP_LINK_SUCCESS)) + if (!ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xDF, AST_IO_VGACRDF_HPD)) return false; return true; } -int ast_astdp_read_edid(struct drm_device *dev, u8 *ediddata) +static int ast_astdp_read_edid_block(void *data, u8 *buf, unsigned int block, size_t len) { - struct ast_device *ast = to_ast_device(dev); - u8 i = 0, j = 0; + struct ast_device *ast = data; + size_t rdlen = round_up(len, 4); + int ret = 0; + unsigned int i; + + if (block > 0) + return -EIO; /* extension headers not supported */ /* - * CRD1[b5]: DP MCU FW is executing - * CRDC[b0]: DP link success - * CRDF[b0]: DP HPD - * CRE5[b0]: Host reading EDID process is done + * Protect access to I/O registers from concurrent modesetting + * by acquiring the I/O-register lock. */ - if (!(ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xD1, ASTDP_MCU_FW_EXECUTING) && - ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xDC, ASTDP_LINK_SUCCESS) && - ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xDF, ASTDP_HPD) && - ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xE5, - ASTDP_HOST_EDID_READ_DONE_MASK))) { - goto err_astdp_edid_not_ready; - } + mutex_lock(&ast->modeset_lock); + + /* Start reading EDID data */ + ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xe5, (u8)~AST_IO_VGACRE5_EDID_READ_DONE, 0x00); + + for (i = 0; i < rdlen; i += 4) { + unsigned int offset; + unsigned int j; + u8 ediddata[4]; + u8 vgacre4; - ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xE5, (u8) ~ASTDP_HOST_EDID_READ_DONE_MASK, - 0x00); + offset = (i + block * EDID_LENGTH) / 4; + if (offset >= 64) { + ret = -EIO; + goto out; + } + vgacre4 = offset; - 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_VGACRI, 0xE4, - ASTDP_AND_CLEAR_MASK, (u8)i); - j = 0; + ast_set_index_reg(ast, AST_IO_VGACRI, 0xe4, vgacre4); /* * CRD7[b0]: valid flag for EDID * CRD6[b0]: mirror read pointer for EDID */ - while ((ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xD7, - ASTDP_EDID_VALID_FLAG_MASK) != 0x01) || - (ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xD6, - ASTDP_EDID_READ_POINTER_MASK) != i)) { + for (j = 0; j < 200; ++j) { + u8 vgacrd7, vgacrd6; + /* * Delay are getting longer with each retry. - * 1. The Delays are often 2 loops when users request "Display Settings" + * + * 1. No delay on first try + * 2. 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. + * 3. 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_VGACRI, 0xD1, - ASTDP_MCU_FW_EXECUTING) && - ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xDC, - ASTDP_LINK_SUCCESS) && - ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xDF, ASTDP_HPD))) { - goto err_astdp_jump_out_loop_of_edid; + if (j) + mdelay(j + 1); + + /* Wait for EDID offset to show up in mirror register */ + vgacrd7 = ast_get_index_reg(ast, AST_IO_VGACRI, 0xd7); + if (vgacrd7 & AST_IO_VGACRD7_EDID_VALID_FLAG) { + vgacrd6 = ast_get_index_reg(ast, AST_IO_VGACRI, 0xd6); + if (vgacrd6 == offset) + break; } - - j++; - if (j > 200) - goto err_astdp_jump_out_loop_of_edid; + } + if (j == 200) { + ret = -EBUSY; + goto out; } - *(ediddata) = ast_get_index_reg_mask(ast, AST_IO_VGACRI, - 0xD8, ASTDP_EDID_READ_DATA_MASK); - *(ediddata + 1) = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xD9, - ASTDP_EDID_READ_DATA_MASK); - *(ediddata + 2) = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xDA, - ASTDP_EDID_READ_DATA_MASK); - *(ediddata + 3) = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xDB, - ASTDP_EDID_READ_DATA_MASK); + ediddata[0] = ast_get_index_reg(ast, AST_IO_VGACRI, 0xd8); + ediddata[1] = ast_get_index_reg(ast, AST_IO_VGACRI, 0xd9); + ediddata[2] = ast_get_index_reg(ast, AST_IO_VGACRI, 0xda); + ediddata[3] = ast_get_index_reg(ast, AST_IO_VGACRI, 0xdb); if (i == 31) { /* @@ -96,69 +103,53 @@ int ast_astdp_read_edid(struct drm_device *dev, u8 *ediddata) * The Bytes-126 indicates the Number of extensions to * follow. 0 represents noextensions. */ - *(ediddata + 3) = *(ediddata + 3) + *(ediddata + 2); - *(ediddata + 2) = 0; + ediddata[3] = ediddata[3] + ediddata[2]; + ediddata[2] = 0; } - ediddata += 4; + memcpy(buf, ediddata, min((len - i), 4)); + buf += 4; } - ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xE5, (u8) ~ASTDP_HOST_EDID_READ_DONE_MASK, - ASTDP_HOST_EDID_READ_DONE); +out: + /* Signal end of reading */ + ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xe5, (u8)~AST_IO_VGACRE5_EDID_READ_DONE, + AST_IO_VGACRE5_EDID_READ_DONE); - return 0; + mutex_unlock(&ast->modeset_lock); -err_astdp_jump_out_loop_of_edid: - ast_set_index_reg_mask(ast, AST_IO_VGACRI, 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_VGACRI, 0xD1, ASTDP_MCU_FW_EXECUTING))) - return (~0xD1 + 1); - if (!(ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xDC, ASTDP_LINK_SUCCESS))) - return (~0xDC + 1); - if (!(ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xDF, ASTDP_HPD))) - return (~0xDF + 1); - if (!(ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xE5, ASTDP_HOST_EDID_READ_DONE_MASK))) - return (~0xE5 + 1); - - return 0; + return ret; } /* * Launch Aspeed DP */ -void ast_dp_launch(struct drm_device *dev) +int ast_dp_launch(struct ast_device *ast) { - u32 i = 0; - u8 bDPExecute = 1; - struct ast_device *ast = to_ast_device(dev); + struct drm_device *dev = &ast->base; + unsigned int i = 10; - // Wait one second then timeout. - while (ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xD1, ASTDP_MCU_FW_EXECUTING) != - ASTDP_MCU_FW_EXECUTING) { - i++; - // wait 100 ms - msleep(100); + while (i) { + u8 vgacrd1 = ast_get_index_reg(ast, AST_IO_VGACRI, 0xd1); - if (i >= 10) { - // DP would not be ready. - bDPExecute = 0; + if (vgacrd1 & AST_IO_VGACRD1_MCU_FW_EXECUTING) break; - } + --i; + msleep(100); } - - if (!bDPExecute) + if (!i) { drm_err(dev, "Wait DPMCU executing timeout\n"); + return -ENODEV; + } - ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xE5, - (u8) ~ASTDP_HOST_EDID_READ_DONE_MASK, - ASTDP_HOST_EDID_READ_DONE); + ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xe5, + (u8) ~AST_IO_VGACRE5_EDID_READ_DONE, + AST_IO_VGACRE5_EDID_READ_DONE); + + return 0; } -bool ast_dp_power_is_on(struct ast_device *ast) +static bool ast_dp_power_is_on(struct ast_device *ast) { u8 vgacre3; @@ -167,7 +158,7 @@ bool ast_dp_power_is_on(struct ast_device *ast) return !(vgacre3 & AST_DP_PHY_SLEEP); } -void ast_dp_power_on_off(struct drm_device *dev, bool on) +static 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 @@ -179,11 +170,29 @@ void ast_dp_power_on_off(struct drm_device *dev, bool on) // DP Power on/off ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xE3, (u8) ~AST_DP_PHY_SLEEP, bE3); + + msleep(50); } +static void ast_dp_link_training(struct ast_device *ast) +{ + struct drm_device *dev = &ast->base; + int i; + + for (i = 0; i < 10; i++) { + u8 vgacrdc; + + if (i) + msleep(100); + vgacrdc = ast_get_index_reg(ast, AST_IO_VGACRI, 0xdc); + if (vgacrdc & AST_IO_VGACRDC_LINK_SUCCESS) + return; + } + drm_err(dev, "Link training failed\n"); +} -void ast_dp_set_on_off(struct drm_device *dev, bool on) +static 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; @@ -192,21 +201,17 @@ void ast_dp_set_on_off(struct drm_device *dev, bool on) // Video On/Off ast_set_index_reg_mask(ast, AST_IO_VGACRI, 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_VGACRI, 0xDC, ASTDP_LINK_SUCCESS) && - ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xDF, ASTDP_HPD)) { - video_on_off <<= 4; - while (ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xDF, + video_on_off <<= 4; + while (ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xDF, ASTDP_MIRROR_VIDEO_ENABLE) != video_on_off) { - // wait 1 ms - mdelay(1); - if (++i > 200) - break; - } + // 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) +static 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); @@ -279,3 +284,188 @@ void ast_dp_set_mode(struct drm_crtc *crtc, struct ast_vbios_mode_info *vbios_mo ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xE1, ASTDP_AND_CLEAR_MASK, ASTDP_MISC1); ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xE2, ASTDP_AND_CLEAR_MASK, ModeIdx); } + +static void ast_wait_for_vretrace(struct ast_device *ast) +{ + unsigned long timeout = jiffies + HZ; + u8 vgair1; + + do { + vgair1 = ast_io_read8(ast, AST_IO_VGAIR1_R); + } while (!(vgair1 & AST_IO_VGAIR1_VREFRESH) && time_before(jiffies, timeout)); +} + +/* + * Encoder + */ + +static const struct drm_encoder_funcs ast_astdp_encoder_funcs = { + .destroy = drm_encoder_cleanup, +}; + +static void ast_astdp_encoder_helper_atomic_mode_set(struct drm_encoder *encoder, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + struct drm_crtc *crtc = crtc_state->crtc; + struct ast_crtc_state *ast_crtc_state = to_ast_crtc_state(crtc_state); + struct ast_vbios_mode_info *vbios_mode_info = &ast_crtc_state->vbios_mode_info; + + ast_dp_set_mode(crtc, vbios_mode_info); +} + +static void ast_astdp_encoder_helper_atomic_enable(struct drm_encoder *encoder, + struct drm_atomic_state *state) +{ + struct drm_device *dev = encoder->dev; + struct ast_device *ast = to_ast_device(dev); + struct ast_connector *ast_connector = &ast->output.astdp.connector; + + if (ast_connector->physical_status == connector_status_connected) { + ast_dp_power_on_off(dev, AST_DP_POWER_ON); + ast_dp_link_training(ast); + + ast_wait_for_vretrace(ast); + ast_dp_set_on_off(dev, 1); + } +} + +static void ast_astdp_encoder_helper_atomic_disable(struct drm_encoder *encoder, + struct drm_atomic_state *state) +{ + struct drm_device *dev = encoder->dev; + + ast_dp_set_on_off(dev, 0); + ast_dp_power_on_off(dev, AST_DP_POWER_OFF); +} + +static const struct drm_encoder_helper_funcs ast_astdp_encoder_helper_funcs = { + .atomic_mode_set = ast_astdp_encoder_helper_atomic_mode_set, + .atomic_enable = ast_astdp_encoder_helper_atomic_enable, + .atomic_disable = ast_astdp_encoder_helper_atomic_disable, +}; + +/* + * Connector + */ + +static int ast_astdp_connector_helper_get_modes(struct drm_connector *connector) +{ + struct ast_connector *ast_connector = to_ast_connector(connector); + int count; + + if (ast_connector->physical_status == connector_status_connected) { + struct ast_device *ast = to_ast_device(connector->dev); + const struct drm_edid *drm_edid; + + drm_edid = drm_edid_read_custom(connector, ast_astdp_read_edid_block, ast); + drm_edid_connector_update(connector, drm_edid); + count = drm_edid_connector_add_modes(connector); + drm_edid_free(drm_edid); + } else { + drm_edid_connector_update(connector, NULL); + + /* + * There's no EDID data without a connected monitor. Set BMC- + * compatible modes in this case. The XGA default resolution + * should work well for all BMCs. + */ + count = drm_add_modes_noedid(connector, 4096, 4096); + if (count) + drm_set_preferred_mode(connector, 1024, 768); + } + + return count; +} + +static int ast_astdp_connector_helper_detect_ctx(struct drm_connector *connector, + struct drm_modeset_acquire_ctx *ctx, + bool force) +{ + struct ast_connector *ast_connector = to_ast_connector(connector); + struct drm_device *dev = connector->dev; + struct ast_device *ast = to_ast_device(connector->dev); + enum drm_connector_status status = connector_status_disconnected; + bool power_is_on; + + mutex_lock(&ast->modeset_lock); + + power_is_on = ast_dp_power_is_on(ast); + if (!power_is_on) + ast_dp_power_on_off(dev, true); + + if (ast_astdp_is_connected(ast)) + status = connector_status_connected; + + if (!power_is_on && status == connector_status_disconnected) + ast_dp_power_on_off(dev, false); + + mutex_unlock(&ast->modeset_lock); + + if (status != ast_connector->physical_status) + ++connector->epoch_counter; + ast_connector->physical_status = status; + + return connector_status_connected; +} + +static const struct drm_connector_helper_funcs ast_astdp_connector_helper_funcs = { + .get_modes = ast_astdp_connector_helper_get_modes, + .detect_ctx = ast_astdp_connector_helper_detect_ctx, +}; + +static const struct drm_connector_funcs ast_astdp_connector_funcs = { + .reset = drm_atomic_helper_connector_reset, + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = drm_connector_cleanup, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, +}; + +static int ast_astdp_connector_init(struct drm_device *dev, struct drm_connector *connector) +{ + int ret; + + ret = drm_connector_init(dev, connector, &ast_astdp_connector_funcs, + DRM_MODE_CONNECTOR_DisplayPort); + if (ret) + return ret; + + drm_connector_helper_add(connector, &ast_astdp_connector_helper_funcs); + + connector->interlace_allowed = 0; + connector->doublescan_allowed = 0; + + connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; + + return 0; +} + +int ast_astdp_output_init(struct ast_device *ast) +{ + struct drm_device *dev = &ast->base; + struct drm_crtc *crtc = &ast->crtc; + struct drm_encoder *encoder = &ast->output.astdp.encoder; + struct ast_connector *ast_connector = &ast->output.astdp.connector; + struct drm_connector *connector = &ast_connector->base; + int ret; + + ret = drm_encoder_init(dev, encoder, &ast_astdp_encoder_funcs, + DRM_MODE_ENCODER_TMDS, NULL); + if (ret) + return ret; + drm_encoder_helper_add(encoder, &ast_astdp_encoder_helper_funcs); + + encoder->possible_crtcs = drm_crtc_mask(crtc); + + ret = ast_astdp_connector_init(dev, connector); + if (ret) + return ret; + ast_connector->physical_status = connector->status; + + ret = drm_connector_attach_encoder(connector, encoder); + if (ret) + return ret; + + return 0; +} diff --git a/drivers/gpu/drm/ast/ast_dp501.c b/drivers/gpu/drm/ast/ast_dp501.c index 9a4c3a0963f9..e4c636f45082 100644 --- a/drivers/gpu/drm/ast/ast_dp501.c +++ b/drivers/gpu/drm/ast/ast_dp501.c @@ -4,6 +4,11 @@ #include <linux/firmware.h> #include <linux/module.h> +#include <drm/drm_atomic_state_helper.h> +#include <drm/drm_edid.h> +#include <drm/drm_modeset_helper_vtables.h> +#include <drm/drm_probe_helper.h> + #include "ast_drv.h" MODULE_FIRMWARE("ast_dp501_fw.bin"); @@ -170,7 +175,7 @@ static void clear_cmd(struct ast_device *ast) } #endif -void ast_set_dp501_video_output(struct drm_device *dev, u8 mode) +static void ast_set_dp501_video_output(struct drm_device *dev, u8 mode) { ast_write_cmd(dev, 0x40); ast_write_data(dev, mode); @@ -272,7 +277,7 @@ static bool ast_launch_m68k(struct drm_device *dev) return true; } -bool ast_dp501_is_connected(struct ast_device *ast) +static bool ast_dp501_is_connected(struct ast_device *ast) { u32 boot_address, offset, data; @@ -313,32 +318,30 @@ bool ast_dp501_is_connected(struct ast_device *ast) return true; } -bool ast_dp501_read_edid(struct drm_device *dev, u8 *ediddata) +static int ast_dp512_read_edid_block(void *data, u8 *buf, unsigned int block, size_t len) { - struct ast_device *ast = to_ast_device(dev); - u32 i, boot_address, offset, data; - u32 *pEDIDidx; + struct ast_device *ast = data; + size_t rdlen = round_up(len, 4); + u32 i, boot_address, offset, ediddata; - if (!ast_dp501_is_connected(ast)) - return false; + if (block > (512 / EDID_LENGTH)) + return -EIO; + + offset = AST_DP501_EDID_DATA + block * EDID_LENGTH; if (ast->config_mode == ast_use_p2a) { boot_address = get_fw_base(ast); - /* Read EDID */ - offset = AST_DP501_EDID_DATA; - for (i = 0; i < 128; i += 4) { - data = ast_mindwm(ast, boot_address + offset + i); - pEDIDidx = (u32 *)(ediddata + i); - *pEDIDidx = data; + for (i = 0; i < rdlen; i += 4) { + ediddata = ast_mindwm(ast, boot_address + offset + i); + memcpy(buf, &ediddata, min((len - i), 4)); + buf += 4; } } else { - /* Read EDID */ - offset = AST_DP501_EDID_DATA; - for (i = 0; i < 128; i += 4) { - data = readl(ast->dp501_fw_buf + offset + i); - pEDIDidx = (u32 *)(ediddata + i); - *pEDIDidx = data; + for (i = 0; i < rdlen; i += 4) { + ediddata = readl(ast->dp501_fw_buf + offset + i); + memcpy(buf, &ediddata, min((len - i), 4)); + buf += 4; } } @@ -470,3 +473,144 @@ void ast_init_3rdtx(struct drm_device *dev) } } } + +/* + * Encoder + */ + +static const struct drm_encoder_funcs ast_dp501_encoder_funcs = { + .destroy = drm_encoder_cleanup, +}; + +static void ast_dp501_encoder_helper_atomic_enable(struct drm_encoder *encoder, + struct drm_atomic_state *state) +{ + struct drm_device *dev = encoder->dev; + + ast_set_dp501_video_output(dev, 1); +} + +static void ast_dp501_encoder_helper_atomic_disable(struct drm_encoder *encoder, + struct drm_atomic_state *state) +{ + struct drm_device *dev = encoder->dev; + + ast_set_dp501_video_output(dev, 0); +} + +static const struct drm_encoder_helper_funcs ast_dp501_encoder_helper_funcs = { + .atomic_enable = ast_dp501_encoder_helper_atomic_enable, + .atomic_disable = ast_dp501_encoder_helper_atomic_disable, +}; + +/* + * Connector + */ + +static int ast_dp501_connector_helper_get_modes(struct drm_connector *connector) +{ + struct ast_connector *ast_connector = to_ast_connector(connector); + int count; + + if (ast_connector->physical_status == connector_status_connected) { + struct ast_device *ast = to_ast_device(connector->dev); + const struct drm_edid *drm_edid; + + drm_edid = drm_edid_read_custom(connector, ast_dp512_read_edid_block, ast); + drm_edid_connector_update(connector, drm_edid); + count = drm_edid_connector_add_modes(connector); + drm_edid_free(drm_edid); + } else { + drm_edid_connector_update(connector, NULL); + + /* + * There's no EDID data without a connected monitor. Set BMC- + * compatible modes in this case. The XGA default resolution + * should work well for all BMCs. + */ + count = drm_add_modes_noedid(connector, 4096, 4096); + if (count) + drm_set_preferred_mode(connector, 1024, 768); + } + + return count; +} + +static int ast_dp501_connector_helper_detect_ctx(struct drm_connector *connector, + struct drm_modeset_acquire_ctx *ctx, + bool force) +{ + struct ast_connector *ast_connector = to_ast_connector(connector); + struct ast_device *ast = to_ast_device(connector->dev); + enum drm_connector_status status = connector_status_disconnected; + + if (ast_dp501_is_connected(ast)) + status = connector_status_connected; + + if (status != ast_connector->physical_status) + ++connector->epoch_counter; + ast_connector->physical_status = status; + + return connector_status_connected; +} + +static const struct drm_connector_helper_funcs ast_dp501_connector_helper_funcs = { + .get_modes = ast_dp501_connector_helper_get_modes, + .detect_ctx = ast_dp501_connector_helper_detect_ctx, +}; + +static const struct drm_connector_funcs ast_dp501_connector_funcs = { + .reset = drm_atomic_helper_connector_reset, + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = drm_connector_cleanup, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, +}; + +static int ast_dp501_connector_init(struct drm_device *dev, struct drm_connector *connector) +{ + int ret; + + ret = drm_connector_init(dev, connector, &ast_dp501_connector_funcs, + DRM_MODE_CONNECTOR_DisplayPort); + if (ret) + return ret; + + drm_connector_helper_add(connector, &ast_dp501_connector_helper_funcs); + + connector->interlace_allowed = 0; + connector->doublescan_allowed = 0; + + connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; + + return 0; +} + +int ast_dp501_output_init(struct ast_device *ast) +{ + struct drm_device *dev = &ast->base; + struct drm_crtc *crtc = &ast->crtc; + struct drm_encoder *encoder = &ast->output.dp501.encoder; + struct ast_connector *ast_connector = &ast->output.dp501.connector; + struct drm_connector *connector = &ast_connector->base; + int ret; + + ret = drm_encoder_init(dev, encoder, &ast_dp501_encoder_funcs, + DRM_MODE_ENCODER_TMDS, NULL); + if (ret) + return ret; + drm_encoder_helper_add(encoder, &ast_dp501_encoder_helper_funcs); + + encoder->possible_crtcs = drm_crtc_mask(crtc); + + ret = ast_dp501_connector_init(dev, connector); + if (ret) + return ret; + ast_connector->physical_status = connector->status; + + ret = drm_connector_attach_encoder(connector, encoder); + if (ret) + return ret; + + return 0; +} diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h index 47bab5596c16..91fe07cf7b07 100644 --- a/drivers/gpu/drm/ast/ast_drv.h +++ b/drivers/gpu/drm/ast/ast_drv.h @@ -147,18 +147,19 @@ static inline struct ast_plane *to_ast_plane(struct drm_plane *plane) } /* - * BMC + * Connector */ -struct ast_bmc_connector { +struct ast_connector { struct drm_connector base; - struct drm_connector *physical_connector; + + enum drm_connector_status physical_status; }; -static inline struct ast_bmc_connector * -to_ast_bmc_connector(struct drm_connector *connector) +static inline struct ast_connector * +to_ast_connector(struct drm_connector *connector) { - return container_of(connector, struct ast_bmc_connector, base); + return container_of(connector, struct ast_connector, base); } /* @@ -192,24 +193,20 @@ struct ast_device { struct { struct { struct drm_encoder encoder; - struct drm_connector connector; + struct ast_connector connector; } vga; struct { struct drm_encoder encoder; - struct drm_connector connector; + struct ast_connector connector; } sil164; struct { struct drm_encoder encoder; - struct drm_connector connector; + struct ast_connector connector; } dp501; struct { struct drm_encoder encoder; - struct drm_connector connector; + struct ast_connector connector; } astdp; - struct { - struct drm_encoder encoder; - struct ast_bmc_connector bmc_connector; - } bmc; } output; bool support_wide_screen; @@ -460,21 +457,17 @@ void ast_post_gpu(struct drm_device *dev); u32 ast_mindwm(struct ast_device *ast, u32 r); void ast_moutdwm(struct ast_device *ast, u32 r, u32 v); void ast_patch_ahb_2500(void __iomem *regs); + +int ast_vga_output_init(struct ast_device *ast); +int ast_sil164_output_init(struct ast_device *ast); + /* ast dp501 */ -void ast_set_dp501_video_output(struct drm_device *dev, u8 mode); bool ast_backup_fw(struct drm_device *dev, u8 *addr, u32 size); -bool ast_dp501_is_connected(struct ast_device *ast); -bool ast_dp501_read_edid(struct drm_device *dev, u8 *ediddata); -u8 ast_get_dp501_max_clk(struct drm_device *dev); void ast_init_3rdtx(struct drm_device *dev); +int ast_dp501_output_init(struct ast_device *ast); /* aspeed DP */ -bool ast_astdp_is_connected(struct ast_device *ast); -int ast_astdp_read_edid(struct drm_device *dev, u8 *ediddata); -void ast_dp_launch(struct drm_device *dev); -bool ast_dp_power_is_on(struct ast_device *ast); -void ast_dp_power_on_off(struct drm_device *dev, bool no); -void ast_dp_set_on_off(struct drm_device *dev, bool no); -void ast_dp_set_mode(struct drm_crtc *crtc, struct ast_vbios_mode_info *vbios_mode); +int ast_dp_launch(struct ast_device *ast); +int ast_astdp_output_init(struct ast_device *ast); #endif diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c index 0637abb70361..d836f2a4f9f3 100644 --- a/drivers/gpu/drm/ast/ast_main.c +++ b/drivers/gpu/drm/ast/ast_main.c @@ -115,8 +115,10 @@ static void ast_detect_tx_chip(struct ast_device *ast, bool need_post) } else if (IS_AST_GEN7(ast)) { if (ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xD1, TX_TYPE_MASK) == ASTDP_DPMCU_TX) { - ast->tx_chip_types = AST_TX_ASTDP_BIT; - ast_dp_launch(&ast->base); + int ret = ast_dp_launch(ast); + + if (!ret) + ast->tx_chip_types = AST_TX_ASTDP_BIT; } } diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index 049ee1477c33..ed496fb32bf3 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -34,10 +34,8 @@ #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> -#include <drm/drm_atomic_state_helper.h> #include <drm/drm_crtc.h> #include <drm/drm_damage_helper.h> -#include <drm/drm_edid.h> #include <drm/drm_format_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_gem_atomic_helper.h> @@ -47,7 +45,6 @@ #include <drm/drm_panic.h> #include <drm/drm_probe_helper.h> -#include "ast_ddc.h" #include "ast_drv.h" #include "ast_tables.h" @@ -1311,571 +1308,6 @@ static int ast_crtc_init(struct drm_device *dev) } /* - * VGA Encoder - */ - -static const struct drm_encoder_funcs ast_vga_encoder_funcs = { - .destroy = drm_encoder_cleanup, -}; - -/* - * VGA Connector - */ - -static const struct drm_connector_helper_funcs ast_vga_connector_helper_funcs = { - .get_modes = drm_connector_helper_get_modes, - .detect_ctx = drm_connector_helper_detect_from_ddc, -}; - -static const struct drm_connector_funcs ast_vga_connector_funcs = { - .reset = drm_atomic_helper_connector_reset, - .fill_modes = drm_helper_probe_single_connector_modes, - .destroy = drm_connector_cleanup, - .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, -}; - -static int ast_vga_connector_init(struct drm_device *dev, struct drm_connector *connector) -{ - struct ast_device *ast = to_ast_device(dev); - struct i2c_adapter *ddc; - int ret; - - ddc = ast_ddc_create(ast); - if (IS_ERR(ddc)) { - ret = PTR_ERR(ddc); - drm_err(dev, "failed to add DDC bus for connector; ret=%d\n", ret); - return ret; - } - - ret = drm_connector_init_with_ddc(dev, connector, &ast_vga_connector_funcs, - DRM_MODE_CONNECTOR_VGA, ddc); - if (ret) - return ret; - - drm_connector_helper_add(connector, &ast_vga_connector_helper_funcs); - - connector->interlace_allowed = 0; - connector->doublescan_allowed = 0; - - connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; - - return 0; -} - -static int ast_vga_output_init(struct ast_device *ast) -{ - struct drm_device *dev = &ast->base; - struct drm_crtc *crtc = &ast->crtc; - struct drm_encoder *encoder = &ast->output.vga.encoder; - struct drm_connector *connector = &ast->output.vga.connector; - int ret; - - ret = drm_encoder_init(dev, encoder, &ast_vga_encoder_funcs, - DRM_MODE_ENCODER_DAC, NULL); - if (ret) - return ret; - encoder->possible_crtcs = drm_crtc_mask(crtc); - - ret = ast_vga_connector_init(dev, connector); - if (ret) - return ret; - - ret = drm_connector_attach_encoder(connector, encoder); - if (ret) - return ret; - - return 0; -} - -/* - * SIL164 Encoder - */ - -static const struct drm_encoder_funcs ast_sil164_encoder_funcs = { - .destroy = drm_encoder_cleanup, -}; - -/* - * SIL164 Connector - */ - -static const struct drm_connector_helper_funcs ast_sil164_connector_helper_funcs = { - .get_modes = drm_connector_helper_get_modes, - .detect_ctx = drm_connector_helper_detect_from_ddc, -}; - -static const struct drm_connector_funcs ast_sil164_connector_funcs = { - .reset = drm_atomic_helper_connector_reset, - .fill_modes = drm_helper_probe_single_connector_modes, - .destroy = drm_connector_cleanup, - .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, -}; - -static int ast_sil164_connector_init(struct drm_device *dev, struct drm_connector *connector) -{ - struct ast_device *ast = to_ast_device(dev); - struct i2c_adapter *ddc; - int ret; - - ddc = ast_ddc_create(ast); - if (IS_ERR(ddc)) { - ret = PTR_ERR(ddc); - drm_err(dev, "failed to add DDC bus for connector; ret=%d\n", ret); - return ret; - } - - ret = drm_connector_init_with_ddc(dev, connector, &ast_sil164_connector_funcs, - DRM_MODE_CONNECTOR_DVII, ddc); - if (ret) - return ret; - - drm_connector_helper_add(connector, &ast_sil164_connector_helper_funcs); - - connector->interlace_allowed = 0; - connector->doublescan_allowed = 0; - - connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; - - return 0; -} - -static int ast_sil164_output_init(struct ast_device *ast) -{ - struct drm_device *dev = &ast->base; - struct drm_crtc *crtc = &ast->crtc; - struct drm_encoder *encoder = &ast->output.sil164.encoder; - struct drm_connector *connector = &ast->output.sil164.connector; - int ret; - - ret = drm_encoder_init(dev, encoder, &ast_sil164_encoder_funcs, - DRM_MODE_ENCODER_TMDS, NULL); - if (ret) - return ret; - encoder->possible_crtcs = drm_crtc_mask(crtc); - - ret = ast_sil164_connector_init(dev, connector); - if (ret) - return ret; - - ret = drm_connector_attach_encoder(connector, encoder); - if (ret) - return ret; - - return 0; -} - -/* - * DP501 Encoder - */ - -static const struct drm_encoder_funcs ast_dp501_encoder_funcs = { - .destroy = drm_encoder_cleanup, -}; - -static void ast_dp501_encoder_helper_atomic_enable(struct drm_encoder *encoder, - struct drm_atomic_state *state) -{ - struct drm_device *dev = encoder->dev; - - ast_set_dp501_video_output(dev, 1); -} - -static void ast_dp501_encoder_helper_atomic_disable(struct drm_encoder *encoder, - struct drm_atomic_state *state) -{ - struct drm_device *dev = encoder->dev; - - ast_set_dp501_video_output(dev, 0); -} - -static const struct drm_encoder_helper_funcs ast_dp501_encoder_helper_funcs = { - .atomic_enable = ast_dp501_encoder_helper_atomic_enable, - .atomic_disable = ast_dp501_encoder_helper_atomic_disable, -}; - -/* - * DP501 Connector - */ - -static int ast_dp501_connector_helper_get_modes(struct drm_connector *connector) -{ - void *edid; - bool succ; - int count; - - edid = kmalloc(EDID_LENGTH, GFP_KERNEL); - if (!edid) - goto err_drm_connector_update_edid_property; - - succ = ast_dp501_read_edid(connector->dev, edid); - if (!succ) - goto err_kfree; - - drm_connector_update_edid_property(connector, edid); - count = drm_add_edid_modes(connector, edid); - kfree(edid); - - return count; - -err_kfree: - kfree(edid); -err_drm_connector_update_edid_property: - drm_connector_update_edid_property(connector, NULL); - return 0; -} - -static int ast_dp501_connector_helper_detect_ctx(struct drm_connector *connector, - struct drm_modeset_acquire_ctx *ctx, - bool force) -{ - struct ast_device *ast = to_ast_device(connector->dev); - - if (ast_dp501_is_connected(ast)) - return connector_status_connected; - return connector_status_disconnected; -} - -static const struct drm_connector_helper_funcs ast_dp501_connector_helper_funcs = { - .get_modes = ast_dp501_connector_helper_get_modes, - .detect_ctx = ast_dp501_connector_helper_detect_ctx, -}; - -static const struct drm_connector_funcs ast_dp501_connector_funcs = { - .reset = drm_atomic_helper_connector_reset, - .fill_modes = drm_helper_probe_single_connector_modes, - .destroy = drm_connector_cleanup, - .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, -}; - -static int ast_dp501_connector_init(struct drm_device *dev, struct drm_connector *connector) -{ - int ret; - - ret = drm_connector_init(dev, connector, &ast_dp501_connector_funcs, - DRM_MODE_CONNECTOR_DisplayPort); - if (ret) - return ret; - - drm_connector_helper_add(connector, &ast_dp501_connector_helper_funcs); - - connector->interlace_allowed = 0; - connector->doublescan_allowed = 0; - - connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; - - return 0; -} - -static int ast_dp501_output_init(struct ast_device *ast) -{ - struct drm_device *dev = &ast->base; - struct drm_crtc *crtc = &ast->crtc; - struct drm_encoder *encoder = &ast->output.dp501.encoder; - struct drm_connector *connector = &ast->output.dp501.connector; - int ret; - - ret = drm_encoder_init(dev, encoder, &ast_dp501_encoder_funcs, - DRM_MODE_ENCODER_TMDS, NULL); - if (ret) - return ret; - drm_encoder_helper_add(encoder, &ast_dp501_encoder_helper_funcs); - - encoder->possible_crtcs = drm_crtc_mask(crtc); - - ret = ast_dp501_connector_init(dev, connector); - if (ret) - return ret; - - ret = drm_connector_attach_encoder(connector, encoder); - if (ret) - return ret; - - return 0; -} - -/* - * ASPEED Display-Port Encoder - */ - -static const struct drm_encoder_funcs ast_astdp_encoder_funcs = { - .destroy = drm_encoder_cleanup, -}; - -static void ast_astdp_encoder_helper_atomic_mode_set(struct drm_encoder *encoder, - struct drm_crtc_state *crtc_state, - struct drm_connector_state *conn_state) -{ - struct drm_crtc *crtc = crtc_state->crtc; - struct ast_crtc_state *ast_crtc_state = to_ast_crtc_state(crtc_state); - struct ast_vbios_mode_info *vbios_mode_info = &ast_crtc_state->vbios_mode_info; - - ast_dp_set_mode(crtc, vbios_mode_info); -} - -static void ast_astdp_encoder_helper_atomic_enable(struct drm_encoder *encoder, - struct drm_atomic_state *state) -{ - struct drm_device *dev = encoder->dev; - struct ast_device *ast = to_ast_device(dev); - - ast_dp_power_on_off(dev, AST_DP_POWER_ON); - ast_wait_for_vretrace(ast); - ast_dp_set_on_off(dev, 1); -} - -static void ast_astdp_encoder_helper_atomic_disable(struct drm_encoder *encoder, - struct drm_atomic_state *state) -{ - struct drm_device *dev = encoder->dev; - - ast_dp_set_on_off(dev, 0); - ast_dp_power_on_off(dev, AST_DP_POWER_OFF); -} - -static const struct drm_encoder_helper_funcs ast_astdp_encoder_helper_funcs = { - .atomic_mode_set = ast_astdp_encoder_helper_atomic_mode_set, - .atomic_enable = ast_astdp_encoder_helper_atomic_enable, - .atomic_disable = ast_astdp_encoder_helper_atomic_disable, -}; - -/* - * ASPEED Display-Port Connector - */ - -static int ast_astdp_connector_helper_get_modes(struct drm_connector *connector) -{ - void *edid; - struct drm_device *dev = connector->dev; - struct ast_device *ast = to_ast_device(dev); - - int succ; - int count; - - edid = kmalloc(EDID_LENGTH, GFP_KERNEL); - if (!edid) - goto err_drm_connector_update_edid_property; - - /* - * Protect access to I/O registers from concurrent modesetting - * by acquiring the I/O-register lock. - */ - mutex_lock(&ast->modeset_lock); - - succ = ast_astdp_read_edid(connector->dev, edid); - if (succ < 0) - goto err_mutex_unlock; - - mutex_unlock(&ast->modeset_lock); - - drm_connector_update_edid_property(connector, edid); - count = drm_add_edid_modes(connector, edid); - kfree(edid); - - return count; - -err_mutex_unlock: - mutex_unlock(&ast->modeset_lock); - kfree(edid); -err_drm_connector_update_edid_property: - drm_connector_update_edid_property(connector, NULL); - return 0; -} - -static int ast_astdp_connector_helper_detect_ctx(struct drm_connector *connector, - struct drm_modeset_acquire_ctx *ctx, - bool force) -{ - struct drm_device *dev = connector->dev; - struct ast_device *ast = to_ast_device(connector->dev); - enum drm_connector_status status = connector_status_disconnected; - struct drm_connector_state *connector_state = connector->state; - bool is_active = false; - - mutex_lock(&ast->modeset_lock); - - if (connector_state && connector_state->crtc) { - struct drm_crtc_state *crtc_state = connector_state->crtc->state; - - if (crtc_state && crtc_state->active) - is_active = true; - } - - if (!is_active && !ast_dp_power_is_on(ast)) { - ast_dp_power_on_off(dev, true); - msleep(50); - } - - if (ast_astdp_is_connected(ast)) - status = connector_status_connected; - - if (!is_active && status == connector_status_disconnected) - ast_dp_power_on_off(dev, false); - - mutex_unlock(&ast->modeset_lock); - - return status; -} - -static const struct drm_connector_helper_funcs ast_astdp_connector_helper_funcs = { - .get_modes = ast_astdp_connector_helper_get_modes, - .detect_ctx = ast_astdp_connector_helper_detect_ctx, -}; - -static const struct drm_connector_funcs ast_astdp_connector_funcs = { - .reset = drm_atomic_helper_connector_reset, - .fill_modes = drm_helper_probe_single_connector_modes, - .destroy = drm_connector_cleanup, - .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, -}; - -static int ast_astdp_connector_init(struct drm_device *dev, struct drm_connector *connector) -{ - int ret; - - ret = drm_connector_init(dev, connector, &ast_astdp_connector_funcs, - DRM_MODE_CONNECTOR_DisplayPort); - if (ret) - return ret; - - drm_connector_helper_add(connector, &ast_astdp_connector_helper_funcs); - - connector->interlace_allowed = 0; - connector->doublescan_allowed = 0; - - connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; - - return 0; -} - -static int ast_astdp_output_init(struct ast_device *ast) -{ - struct drm_device *dev = &ast->base; - struct drm_crtc *crtc = &ast->crtc; - struct drm_encoder *encoder = &ast->output.astdp.encoder; - struct drm_connector *connector = &ast->output.astdp.connector; - int ret; - - ret = drm_encoder_init(dev, encoder, &ast_astdp_encoder_funcs, - DRM_MODE_ENCODER_TMDS, NULL); - if (ret) - return ret; - drm_encoder_helper_add(encoder, &ast_astdp_encoder_helper_funcs); - - encoder->possible_crtcs = drm_crtc_mask(crtc); - - ret = ast_astdp_connector_init(dev, connector); - if (ret) - return ret; - - ret = drm_connector_attach_encoder(connector, encoder); - if (ret) - return ret; - - return 0; -} - -/* - * BMC virtual Connector - */ - -static const struct drm_encoder_funcs ast_bmc_encoder_funcs = { - .destroy = drm_encoder_cleanup, -}; - -static int ast_bmc_connector_helper_detect_ctx(struct drm_connector *connector, - struct drm_modeset_acquire_ctx *ctx, - bool force) -{ - struct ast_bmc_connector *bmc_connector = to_ast_bmc_connector(connector); - struct drm_connector *physical_connector = bmc_connector->physical_connector; - - /* - * Most user-space compositors cannot handle more than one connected - * connector per CRTC. Hence, we only mark the BMC as connected if the - * physical connector is disconnected. If the physical connector's status - * is connected or unknown, the BMC remains disconnected. This has no - * effect on the output of the BMC. - * - * FIXME: Remove this logic once user-space compositors can handle more - * than one connector per CRTC. The BMC should always be connected. - */ - - if (physical_connector && physical_connector->status == connector_status_disconnected) - return connector_status_connected; - - return connector_status_disconnected; -} - -static int ast_bmc_connector_helper_get_modes(struct drm_connector *connector) -{ - return drm_add_modes_noedid(connector, 4096, 4096); -} - -static const struct drm_connector_helper_funcs ast_bmc_connector_helper_funcs = { - .get_modes = ast_bmc_connector_helper_get_modes, - .detect_ctx = ast_bmc_connector_helper_detect_ctx, -}; - -static const struct drm_connector_funcs ast_bmc_connector_funcs = { - .reset = drm_atomic_helper_connector_reset, - .fill_modes = drm_helper_probe_single_connector_modes, - .destroy = drm_connector_cleanup, - .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, -}; - -static int ast_bmc_connector_init(struct drm_device *dev, - struct ast_bmc_connector *bmc_connector, - struct drm_connector *physical_connector) -{ - struct drm_connector *connector = &bmc_connector->base; - int ret; - - ret = drm_connector_init(dev, connector, &ast_bmc_connector_funcs, - DRM_MODE_CONNECTOR_VIRTUAL); - if (ret) - return ret; - - drm_connector_helper_add(connector, &ast_bmc_connector_helper_funcs); - - bmc_connector->physical_connector = physical_connector; - - return 0; -} - -static int ast_bmc_output_init(struct ast_device *ast, - struct drm_connector *physical_connector) -{ - struct drm_device *dev = &ast->base; - struct drm_crtc *crtc = &ast->crtc; - struct drm_encoder *encoder = &ast->output.bmc.encoder; - struct ast_bmc_connector *bmc_connector = &ast->output.bmc.bmc_connector; - struct drm_connector *connector = &bmc_connector->base; - int ret; - - ret = drm_encoder_init(dev, encoder, - &ast_bmc_encoder_funcs, - DRM_MODE_ENCODER_VIRTUAL, "ast_bmc"); - if (ret) - return ret; - encoder->possible_crtcs = drm_crtc_mask(crtc); - - ret = ast_bmc_connector_init(dev, bmc_connector, physical_connector); - if (ret) - return ret; - - ret = drm_connector_attach_encoder(connector, encoder); - if (ret) - return ret; - - return 0; -} - -/* * Mode config */ @@ -1926,7 +1358,6 @@ static const struct drm_mode_config_funcs ast_mode_config_funcs = { int ast_mode_config_init(struct ast_device *ast) { struct drm_device *dev = &ast->base; - struct drm_connector *physical_connector = NULL; int ret; ret = drmm_mutex_init(dev, &ast->modeset_lock); @@ -1971,29 +1402,22 @@ int ast_mode_config_init(struct ast_device *ast) ret = ast_vga_output_init(ast); if (ret) return ret; - physical_connector = &ast->output.vga.connector; } if (ast->tx_chip_types & AST_TX_SIL164_BIT) { ret = ast_sil164_output_init(ast); if (ret) return ret; - physical_connector = &ast->output.sil164.connector; } if (ast->tx_chip_types & AST_TX_DP501_BIT) { ret = ast_dp501_output_init(ast); if (ret) return ret; - physical_connector = &ast->output.dp501.connector; } if (ast->tx_chip_types & AST_TX_ASTDP_BIT) { ret = ast_astdp_output_init(ast); if (ret) return ret; - physical_connector = &ast->output.astdp.connector; } - ret = ast_bmc_output_init(ast, physical_connector); - if (ret) - return ret; drm_mode_config_reset(dev); diff --git a/drivers/gpu/drm/ast/ast_post.c b/drivers/gpu/drm/ast/ast_post.c index 22f548805dfb..65755798ab94 100644 --- a/drivers/gpu/drm/ast/ast_post.c +++ b/drivers/gpu/drm/ast/ast_post.c @@ -351,7 +351,7 @@ void ast_post_gpu(struct drm_device *dev) if (IS_AST_GEN7(ast)) { if (ast->tx_chip_types & AST_TX_ASTDP_BIT) - ast_dp_launch(dev); + ast_dp_launch(ast); } else if (ast->config_mode == ast_use_p2a) { if (IS_AST_GEN6(ast)) ast_post_chip_2500(dev); diff --git a/drivers/gpu/drm/ast/ast_reg.h b/drivers/gpu/drm/ast/ast_reg.h index 75671d345057..040961cc1a19 100644 --- a/drivers/gpu/drm/ast/ast_reg.h +++ b/drivers/gpu/drm/ast/ast_reg.h @@ -37,6 +37,12 @@ #define AST_IO_VGACRCB_HWC_16BPP BIT(0) /* set: ARGB4444, cleared: 2bpp palette */ #define AST_IO_VGACRCB_HWC_ENABLED BIT(1) +#define AST_IO_VGACRD1_MCU_FW_EXECUTING BIT(5) +#define AST_IO_VGACRD7_EDID_VALID_FLAG BIT(0) +#define AST_IO_VGACRDC_LINK_SUCCESS BIT(0) +#define AST_IO_VGACRDF_HPD BIT(0) +#define AST_IO_VGACRE5_EDID_READ_DONE BIT(0) + #define AST_IO_VGAIR1_R (0x5A) #define AST_IO_VGAIR1_VREFRESH BIT(3) @@ -67,18 +73,6 @@ #define AST_DP_VIDEO_ENABLE BIT(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 - */ -#define ASTDP_MCU_FW_EXECUTING BIT(5) -#define ASTDP_LINK_SUCCESS BIT(0) -#define ASTDP_HPD BIT(0) -#define ASTDP_HOST_EDID_READ_DONE BIT(0) -#define ASTDP_HOST_EDID_READ_DONE_MASK GENMASK(0, 0) - -/* * CRDF[b4]: Mirror of AST_DP_VIDEO_ENABLE * Precondition: A. ~AST_DP_PHY_SLEEP && * B. DP_HPD && @@ -86,10 +80,6 @@ */ #define ASTDP_MIRROR_VIDEO_ENABLE BIT(4) -#define ASTDP_EDID_READ_POINTER_MASK GENMASK(7, 0) -#define ASTDP_EDID_VALID_FLAG_MASK GENMASK(0, 0) -#define ASTDP_EDID_READ_DATA_MASK GENMASK(7, 0) - /* * ASTDP setmode registers: * CRE0[7:0]: MISC0 ((0x00: 18-bpp) or (0x20: 24-bpp) diff --git a/drivers/gpu/drm/ast/ast_sil164.c b/drivers/gpu/drm/ast/ast_sil164.c new file mode 100644 index 000000000000..496c7120e515 --- /dev/null +++ b/drivers/gpu/drm/ast/ast_sil164.c @@ -0,0 +1,127 @@ +// SPDX-License-Identifier: MIT + +#include <drm/drm_atomic_state_helper.h> +#include <drm/drm_edid.h> +#include <drm/drm_modeset_helper_vtables.h> +#include <drm/drm_print.h> +#include <drm/drm_probe_helper.h> + +#include "ast_ddc.h" +#include "ast_drv.h" + +/* + * Encoder + */ + +static const struct drm_encoder_funcs ast_sil164_encoder_funcs = { + .destroy = drm_encoder_cleanup, +}; + +/* + * Connector + */ + +static int ast_sil164_connector_helper_get_modes(struct drm_connector *connector) +{ + struct ast_connector *ast_connector = to_ast_connector(connector); + int count; + + if (ast_connector->physical_status == connector_status_connected) { + count = drm_connector_helper_get_modes(connector); + } else { + /* + * There's no EDID data without a connected monitor. Set BMC- + * compatible modes in this case. The XGA default resolution + * should work well for all BMCs. + */ + count = drm_add_modes_noedid(connector, 4096, 4096); + if (count) + drm_set_preferred_mode(connector, 1024, 768); + } + + return count; +} + +static int ast_sil164_connector_helper_detect_ctx(struct drm_connector *connector, + struct drm_modeset_acquire_ctx *ctx, + bool force) +{ + struct ast_connector *ast_connector = to_ast_connector(connector); + enum drm_connector_status status; + + status = drm_connector_helper_detect_from_ddc(connector, ctx, force); + + if (status != ast_connector->physical_status) + ++connector->epoch_counter; + ast_connector->physical_status = status; + + return connector_status_connected; +} + +static const struct drm_connector_helper_funcs ast_sil164_connector_helper_funcs = { + .get_modes = ast_sil164_connector_helper_get_modes, + .detect_ctx = ast_sil164_connector_helper_detect_ctx, +}; + +static const struct drm_connector_funcs ast_sil164_connector_funcs = { + .reset = drm_atomic_helper_connector_reset, + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = drm_connector_cleanup, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, +}; + +static int ast_sil164_connector_init(struct drm_device *dev, struct drm_connector *connector) +{ + struct ast_device *ast = to_ast_device(dev); + struct i2c_adapter *ddc; + int ret; + + ddc = ast_ddc_create(ast); + if (IS_ERR(ddc)) { + ret = PTR_ERR(ddc); + drm_err(dev, "failed to add DDC bus for connector; ret=%d\n", ret); + return ret; + } + + ret = drm_connector_init_with_ddc(dev, connector, &ast_sil164_connector_funcs, + DRM_MODE_CONNECTOR_DVII, ddc); + if (ret) + return ret; + + drm_connector_helper_add(connector, &ast_sil164_connector_helper_funcs); + + connector->interlace_allowed = 0; + connector->doublescan_allowed = 0; + + connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; + + return 0; +} + +int ast_sil164_output_init(struct ast_device *ast) +{ + struct drm_device *dev = &ast->base; + struct drm_crtc *crtc = &ast->crtc; + struct drm_encoder *encoder = &ast->output.sil164.encoder; + struct ast_connector *ast_connector = &ast->output.sil164.connector; + struct drm_connector *connector = &ast_connector->base; + int ret; + + ret = drm_encoder_init(dev, encoder, &ast_sil164_encoder_funcs, + DRM_MODE_ENCODER_TMDS, NULL); + if (ret) + return ret; + encoder->possible_crtcs = drm_crtc_mask(crtc); + + ret = ast_sil164_connector_init(dev, connector); + if (ret) + return ret; + ast_connector->physical_status = connector->status; + + ret = drm_connector_attach_encoder(connector, encoder); + if (ret) + return ret; + + return 0; +} diff --git a/drivers/gpu/drm/ast/ast_vga.c b/drivers/gpu/drm/ast/ast_vga.c new file mode 100644 index 000000000000..3e815da43fbd --- /dev/null +++ b/drivers/gpu/drm/ast/ast_vga.c @@ -0,0 +1,127 @@ +// SPDX-License-Identifier: MIT + +#include <drm/drm_atomic_state_helper.h> +#include <drm/drm_edid.h> +#include <drm/drm_modeset_helper_vtables.h> +#include <drm/drm_print.h> +#include <drm/drm_probe_helper.h> + +#include "ast_ddc.h" +#include "ast_drv.h" + +/* + * Encoder + */ + +static const struct drm_encoder_funcs ast_vga_encoder_funcs = { + .destroy = drm_encoder_cleanup, +}; + +/* + * Connector + */ + +static int ast_vga_connector_helper_get_modes(struct drm_connector *connector) +{ + struct ast_connector *ast_connector = to_ast_connector(connector); + int count; + + if (ast_connector->physical_status == connector_status_connected) { + count = drm_connector_helper_get_modes(connector); + } else { + /* + * There's no EDID data without a connected monitor. Set BMC- + * compatible modes in this case. The XGA default resolution + * should work well for all BMCs. + */ + count = drm_add_modes_noedid(connector, 4096, 4096); + if (count) + drm_set_preferred_mode(connector, 1024, 768); + } + + return count; +} + +static int ast_vga_connector_helper_detect_ctx(struct drm_connector *connector, + struct drm_modeset_acquire_ctx *ctx, + bool force) +{ + struct ast_connector *ast_connector = to_ast_connector(connector); + enum drm_connector_status status; + + status = drm_connector_helper_detect_from_ddc(connector, ctx, force); + + if (status != ast_connector->physical_status) + ++connector->epoch_counter; + ast_connector->physical_status = status; + + return connector_status_connected; +} + +static const struct drm_connector_helper_funcs ast_vga_connector_helper_funcs = { + .get_modes = ast_vga_connector_helper_get_modes, + .detect_ctx = ast_vga_connector_helper_detect_ctx, +}; + +static const struct drm_connector_funcs ast_vga_connector_funcs = { + .reset = drm_atomic_helper_connector_reset, + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = drm_connector_cleanup, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, +}; + +static int ast_vga_connector_init(struct drm_device *dev, struct drm_connector *connector) +{ + struct ast_device *ast = to_ast_device(dev); + struct i2c_adapter *ddc; + int ret; + + ddc = ast_ddc_create(ast); + if (IS_ERR(ddc)) { + ret = PTR_ERR(ddc); + drm_err(dev, "failed to add DDC bus for connector; ret=%d\n", ret); + return ret; + } + + ret = drm_connector_init_with_ddc(dev, connector, &ast_vga_connector_funcs, + DRM_MODE_CONNECTOR_VGA, ddc); + if (ret) + return ret; + + drm_connector_helper_add(connector, &ast_vga_connector_helper_funcs); + + connector->interlace_allowed = 0; + connector->doublescan_allowed = 0; + + connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; + + return 0; +} + +int ast_vga_output_init(struct ast_device *ast) +{ + struct drm_device *dev = &ast->base; + struct drm_crtc *crtc = &ast->crtc; + struct drm_encoder *encoder = &ast->output.vga.encoder; + struct ast_connector *ast_connector = &ast->output.vga.connector; + struct drm_connector *connector = &ast_connector->base; + int ret; + + ret = drm_encoder_init(dev, encoder, &ast_vga_encoder_funcs, + DRM_MODE_ENCODER_DAC, NULL); + if (ret) + return ret; + encoder->possible_crtcs = drm_crtc_mask(crtc); + + ret = ast_vga_connector_init(dev, connector); + if (ret) + return ret; + ast_connector->physical_status = connector->status; + + ret = drm_connector_attach_encoder(connector, encoder); + if (ret) + return ret; + + return 0; +} |