diff options
Diffstat (limited to 'drivers/gpu/drm/ast/ast_mode.c')
-rw-r--r-- | drivers/gpu/drm/ast/ast_mode.c | 172 |
1 files changed, 165 insertions, 7 deletions
diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index 45b56b39ad47..323af2746aa9 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -988,21 +988,41 @@ err_drm_gem_vram_put: static void ast_crtc_dpms(struct drm_crtc *crtc, int mode) { struct ast_private *ast = to_ast_private(crtc->dev); + u8 ch = AST_DPMS_VSYNC_OFF | AST_DPMS_HSYNC_OFF; /* TODO: Maybe control display signal generation with * Sync Enable (bit CR17.7). */ switch (mode) { case DRM_MODE_DPMS_ON: - case DRM_MODE_DPMS_STANDBY: - case DRM_MODE_DPMS_SUSPEND: + ast_set_index_reg_mask(ast, AST_IO_SEQ_PORT, 0x01, 0xdf, 0); + ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb6, 0xfc, 0); if (ast->tx_chip_type == AST_TX_DP501) ast_set_dp501_video_output(crtc->dev, 1); + + if (ast->tx_chip_type == AST_TX_ASTDP) { + ast_dp_power_on_off(crtc->dev, AST_DP_POWER_ON); + ast_wait_for_vretrace(ast); + ast_dp_set_on_off(crtc->dev, 1); + } + + ast_crtc_load_lut(ast, crtc); break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_OFF: + ch = mode; if (ast->tx_chip_type == AST_TX_DP501) ast_set_dp501_video_output(crtc->dev, 0); break; + + if (ast->tx_chip_type == AST_TX_ASTDP) { + ast_dp_set_on_off(crtc->dev, 0); + ast_dp_power_on_off(crtc->dev, AST_DP_POWER_OFF); + } + + ast_set_index_reg_mask(ast, AST_IO_SEQ_PORT, 0x01, 0xdf, 0x20); + ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb6, 0xfc, ch); } } @@ -1027,7 +1047,7 @@ ast_crtc_helper_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode if ((ast->chip == AST2100) || (ast->chip == AST2200) || (ast->chip == AST2300) || (ast->chip == AST2400) || - (ast->chip == AST2500)) { + (ast->chip == AST2500) || (ast->chip == AST2600)) { if ((mode->hdisplay == 1920) && (mode->vdisplay == 1080)) return MODE_OK; @@ -1099,6 +1119,20 @@ static int ast_crtc_helper_atomic_check(struct drm_crtc *crtc, return 0; } +static void ast_crtc_helper_atomic_begin(struct drm_crtc *crtc, struct drm_atomic_state *state) +{ + struct drm_device *dev = crtc->dev; + struct ast_private *ast = to_ast_private(dev); + + /* + * Concurrent operations could possibly trigger a call to + * drm_connector_helper_funcs.get_modes by trying to read the + * display modes. Protect access to I/O registers by acquiring + * the I/O-register lock. Released in atomic_flush(). + */ + mutex_lock(&ast->ioregs_lock); +} + static void ast_crtc_helper_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_state *state) @@ -1107,9 +1141,11 @@ ast_crtc_helper_atomic_flush(struct drm_crtc *crtc, crtc); struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc); - struct ast_private *ast = to_ast_private(crtc->dev); + struct drm_device *dev = crtc->dev; + struct ast_private *ast = to_ast_private(dev); struct ast_crtc_state *ast_crtc_state = to_ast_crtc_state(crtc_state); struct ast_crtc_state *old_ast_crtc_state = to_ast_crtc_state(old_crtc_state); + struct ast_vbios_mode_info *vbios_mode_info = &ast_crtc_state->vbios_mode_info; /* * The gamma LUT has to be reloaded after changing the primary @@ -1117,6 +1153,12 @@ ast_crtc_helper_atomic_flush(struct drm_crtc *crtc, */ if (old_ast_crtc_state->format != ast_crtc_state->format) ast_crtc_load_lut(ast, crtc); + + //Set Aspeed Display-Port + if (ast->tx_chip_type == AST_TX_ASTDP) + ast_dp_set_mode(crtc, vbios_mode_info); + + mutex_unlock(&ast->ioregs_lock); } static void @@ -1175,6 +1217,7 @@ ast_crtc_helper_atomic_disable(struct drm_crtc *crtc, static const struct drm_crtc_helper_funcs ast_crtc_helper_funcs = { .mode_valid = ast_crtc_helper_mode_valid, .atomic_check = ast_crtc_helper_atomic_check, + .atomic_begin = ast_crtc_helper_atomic_begin, .atomic_flush = ast_crtc_helper_atomic_flush, .atomic_enable = ast_crtc_helper_atomic_enable, .atomic_disable = ast_crtc_helper_atomic_disable, @@ -1260,21 +1303,33 @@ static int ast_crtc_init(struct drm_device *dev) static int ast_vga_connector_helper_get_modes(struct drm_connector *connector) { struct ast_vga_connector *ast_vga_connector = to_ast_vga_connector(connector); + struct drm_device *dev = connector->dev; + struct ast_private *ast = to_ast_private(dev); struct edid *edid; int count; if (!ast_vga_connector->i2c) 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->ioregs_lock); + edid = drm_get_edid(connector, &ast_vga_connector->i2c->adapter); if (!edid) - goto err_drm_connector_update_edid_property; + goto err_mutex_unlock; + + mutex_unlock(&ast->ioregs_lock); count = drm_add_edid_modes(connector, edid); kfree(edid); return count; +err_mutex_unlock: + mutex_unlock(&ast->ioregs_lock); err_drm_connector_update_edid_property: drm_connector_update_edid_property(connector, NULL); return 0; @@ -1354,21 +1409,33 @@ static int ast_vga_output_init(struct ast_private *ast) static int ast_sil164_connector_helper_get_modes(struct drm_connector *connector) { struct ast_sil164_connector *ast_sil164_connector = to_ast_sil164_connector(connector); + struct drm_device *dev = connector->dev; + struct ast_private *ast = to_ast_private(dev); struct edid *edid; int count; if (!ast_sil164_connector->i2c) 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->ioregs_lock); + edid = drm_get_edid(connector, &ast_sil164_connector->i2c->adapter); if (!edid) - goto err_drm_connector_update_edid_property; + goto err_mutex_unlock; + + mutex_unlock(&ast->ioregs_lock); count = drm_add_edid_modes(connector, edid); kfree(edid); return count; +err_mutex_unlock: + mutex_unlock(&ast->ioregs_lock); err_drm_connector_update_edid_property: drm_connector_update_edid_property(connector, NULL); return 0; @@ -1528,6 +1595,93 @@ static int ast_dp501_output_init(struct ast_private *ast) } /* + * ASPEED Display-Port Connector + */ + +static int ast_astdp_connector_helper_get_modes(struct drm_connector *connector) +{ + void *edid; + + int succ; + int count; + + edid = kmalloc(EDID_LENGTH, GFP_KERNEL); + if (!edid) + goto err_drm_connector_update_edid_property; + + succ = ast_astdp_read_edid(connector->dev, edid); + if (succ < 0) + 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 const struct drm_connector_helper_funcs ast_astdp_connector_helper_funcs = { + .get_modes = ast_astdp_connector_helper_get_modes, +}; + +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; + + return 0; +} + +static int ast_astdp_output_init(struct ast_private *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_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_TMDS); + if (ret) + return ret; + 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; +} + +/* * Mode config */ @@ -1563,7 +1717,8 @@ int ast_mode_config_init(struct ast_private *ast) ast->chip == AST2200 || ast->chip == AST2300 || ast->chip == AST2400 || - ast->chip == AST2500) { + ast->chip == AST2500 || + ast->chip == AST2600) { dev->mode_config.max_width = 1920; dev->mode_config.max_height = 2048; } else { @@ -1594,6 +1749,9 @@ int ast_mode_config_init(struct ast_private *ast) case AST_TX_DP501: ret = ast_dp501_output_init(ast); break; + case AST_TX_ASTDP: + ret = ast_astdp_output_init(ast); + break; } if (ret) return ret; |