diff options
Diffstat (limited to 'drivers/gpu/drm/ast/ast_mode.c')
| -rw-r--r-- | drivers/gpu/drm/ast/ast_mode.c | 198 | 
1 files changed, 180 insertions, 18 deletions
diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index 45b56b39ad47..db2010a55674 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -988,20 +988,40 @@ 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: -		if (ast->tx_chip_type == AST_TX_DP501) +		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_types & AST_TX_DP501_BIT)  			ast_set_dp501_video_output(crtc->dev, 1); + +		if (ast->tx_chip_types & AST_TX_ASTDP_BIT) { +			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: -		if (ast->tx_chip_type == AST_TX_DP501) +		ch = mode; +		if (ast->tx_chip_types & AST_TX_DP501_BIT)  			ast_set_dp501_video_output(crtc->dev, 0); + +		if (ast->tx_chip_types & AST_TX_ASTDP_BIT) { +			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);  		break;  	}  } @@ -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_types & AST_TX_ASTDP_BIT) +		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 { @@ -1584,19 +1739,26 @@ int ast_mode_config_init(struct ast_private *ast)  	ast_crtc_init(dev); -	switch (ast->tx_chip_type) { -	case AST_TX_NONE: +	if (ast->tx_chip_types & AST_TX_NONE_BIT) {  		ret = ast_vga_output_init(ast); -		break; -	case AST_TX_SIL164: +		if (ret) +			return ret; +	} +	if (ast->tx_chip_types & AST_TX_SIL164_BIT) {  		ret = ast_sil164_output_init(ast); -		break; -	case AST_TX_DP501: +		if (ret) +			return ret; +	} +	if (ast->tx_chip_types & AST_TX_DP501_BIT) {  		ret = ast_dp501_output_init(ast); -		break; +		if (ret) +			return ret; +	} +	if (ast->tx_chip_types & AST_TX_ASTDP_BIT) { +		ret = ast_astdp_output_init(ast); +		if (ret) +			return ret;  	} -	if (ret) -		return ret;  	drm_mode_config_reset(dev);  |