diff options
Diffstat (limited to 'drivers/gpu/drm/ast/ast_mode.c')
| -rw-r--r-- | drivers/gpu/drm/ast/ast_mode.c | 499 | 
1 files changed, 265 insertions, 234 deletions
| diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index 1bc0220e6783..c7443317c747 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -36,11 +36,13 @@  #include <drm/drm_atomic_state_helper.h>  #include <drm/drm_crtc.h>  #include <drm/drm_crtc_helper.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>  #include <drm/drm_gem_framebuffer_helper.h> -#include <drm/drm_gem_vram_helper.h> +#include <drm/drm_gem_shmem_helper.h>  #include <drm/drm_managed.h>  #include <drm/drm_probe_helper.h>  #include <drm/drm_simple_kms_helper.h> @@ -48,6 +50,8 @@  #include "ast_drv.h"  #include "ast_tables.h" +#define AST_LUT_SIZE 256 +  static inline void ast_load_palette_index(struct ast_private *ast,  				     u8 index, u8 red, u8 green,  				     u8 blue) @@ -62,20 +66,46 @@ static inline void ast_load_palette_index(struct ast_private *ast,  	ast_io_read8(ast, AST_IO_SEQ_PORT);  } -static void ast_crtc_load_lut(struct ast_private *ast, struct drm_crtc *crtc) +static void ast_crtc_set_gamma_linear(struct ast_private *ast, +				      const struct drm_format_info *format)  { -	u16 *r, *g, *b;  	int i; -	if (!crtc->enabled) -		return; +	switch (format->format) { +	case DRM_FORMAT_C8: /* In this case, gamma table is used as color palette */ +	case DRM_FORMAT_RGB565: +	case DRM_FORMAT_XRGB8888: +		for (i = 0; i < AST_LUT_SIZE; i++) +			ast_load_palette_index(ast, i, i, i, i); +		break; +	default: +		drm_warn_once(&ast->base, "Unsupported format %p4cc for gamma correction\n", +			      &format->format); +		break; +	} +} -	r = crtc->gamma_store; -	g = r + crtc->gamma_size; -	b = g + crtc->gamma_size; +static void ast_crtc_set_gamma(struct ast_private *ast, +			       const struct drm_format_info *format, +			       struct drm_color_lut *lut) +{ +	int i; -	for (i = 0; i < 256; i++) -		ast_load_palette_index(ast, i, *r++ >> 8, *g++ >> 8, *b++ >> 8); +	switch (format->format) { +	case DRM_FORMAT_C8: /* In this case, gamma table is used as color palette */ +	case DRM_FORMAT_RGB565: +	case DRM_FORMAT_XRGB8888: +		for (i = 0; i < AST_LUT_SIZE; i++) +			ast_load_palette_index(ast, i, +					       lut[i].red >> 8, +					       lut[i].green >> 8, +					       lut[i].blue >> 8); +		break; +	default: +		drm_warn_once(&ast->base, "Unsupported format %p4cc for gamma correction\n", +			      &format->format); +		break; +	}  }  static bool ast_get_vbios_mode_info(const struct drm_format_info *format, @@ -538,6 +568,29 @@ static void ast_wait_for_vretrace(struct ast_private *ast)  }  /* + * Planes + */ + +static int ast_plane_init(struct drm_device *dev, struct ast_plane *ast_plane, +			  void __iomem *vaddr, u64 offset, unsigned long size, +			  uint32_t possible_crtcs, +			  const struct drm_plane_funcs *funcs, +			  const uint32_t *formats, unsigned int format_count, +			  const uint64_t *format_modifiers, +			  enum drm_plane_type type) +{ +	struct drm_plane *plane = &ast_plane->base; + +	ast_plane->vaddr = vaddr; +	ast_plane->offset = offset; +	ast_plane->size = size; + +	return drm_universal_plane_init(dev, plane, possible_crtcs, funcs, +					formats, format_count, format_modifiers, +					type, NULL); +} + +/*   * Primary plane   */ @@ -550,52 +603,62 @@ static const uint32_t ast_primary_plane_formats[] = {  static int ast_primary_plane_helper_atomic_check(struct drm_plane *plane,  						 struct drm_atomic_state *state)  { -	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, -										 plane); -	struct drm_crtc_state *crtc_state; -	struct ast_crtc_state *ast_crtc_state; +	struct drm_device *dev = plane->dev; +	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane); +	struct drm_crtc_state *new_crtc_state = NULL; +	struct ast_crtc_state *new_ast_crtc_state;  	int ret; -	if (!new_plane_state->crtc) -		return 0; - -	crtc_state = drm_atomic_get_new_crtc_state(state, -						   new_plane_state->crtc); +	if (new_plane_state->crtc) +		new_crtc_state = drm_atomic_get_new_crtc_state(state, new_plane_state->crtc); -	ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state, +	ret = drm_atomic_helper_check_plane_state(new_plane_state, new_crtc_state,  						  DRM_PLANE_NO_SCALING,  						  DRM_PLANE_NO_SCALING,  						  false, true); -	if (ret) +	if (ret) {  		return ret; +	} else if (!new_plane_state->visible) { +		if (drm_WARN_ON(dev, new_plane_state->crtc)) /* cannot legally happen */ +			return -EINVAL; +		else +			return 0; +	} -	if (!new_plane_state->visible) -		return 0; - -	ast_crtc_state = to_ast_crtc_state(crtc_state); +	new_ast_crtc_state = to_ast_crtc_state(new_crtc_state); -	ast_crtc_state->format = new_plane_state->fb->format; +	new_ast_crtc_state->format = new_plane_state->fb->format;  	return 0;  } -static void -ast_primary_plane_helper_atomic_update(struct drm_plane *plane, -				       struct drm_atomic_state *state) +static void ast_handle_damage(struct ast_plane *ast_plane, struct iosys_map *src, +			      struct drm_framebuffer *fb, +			      const struct drm_rect *clip) +{ +	struct iosys_map dst = IOSYS_MAP_INIT_VADDR(ast_plane->vaddr); + +	iosys_map_incr(&dst, drm_fb_clip_offset(fb->pitches[0], fb->format, clip)); +	drm_fb_memcpy(&dst, fb->pitches, src, fb, clip); +} + +static void ast_primary_plane_helper_atomic_update(struct drm_plane *plane, +						   struct drm_atomic_state *state)  { -	struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, -									   plane);  	struct drm_device *dev = plane->dev;  	struct ast_private *ast = to_ast_private(dev); -	struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, -									   plane); -	struct drm_gem_vram_object *gbo; -	s64 gpu_addr; -	struct drm_framebuffer *fb = new_state->fb; -	struct drm_framebuffer *old_fb = old_state->fb; +	struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane); +	struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); +	struct drm_framebuffer *fb = plane_state->fb; +	struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane); +	struct drm_framebuffer *old_fb = old_plane_state->fb; +	struct ast_plane *ast_plane = to_ast_plane(plane); +	struct drm_rect damage; +	struct drm_atomic_helper_damage_iter iter;  	if (!old_fb || (fb->format != old_fb->format)) { -		struct drm_crtc_state *crtc_state = new_state->crtc->state; +		struct drm_crtc *crtc = plane_state->crtc; +		struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(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; @@ -603,20 +666,28 @@ ast_primary_plane_helper_atomic_update(struct drm_plane *plane,  		ast_set_vbios_color_reg(ast, fb->format, vbios_mode_info);  	} -	gbo = drm_gem_vram_of_gem(fb->obj[0]); -	gpu_addr = drm_gem_vram_offset(gbo); -	if (drm_WARN_ON_ONCE(dev, gpu_addr < 0)) -		return; /* Bug: we didn't pin the BO to VRAM in prepare_fb. */ - -	ast_set_offset_reg(ast, fb); -	ast_set_start_address_crt1(ast, (u32)gpu_addr); +	drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state); +	drm_atomic_for_each_plane_damage(&iter, &damage) { +		ast_handle_damage(ast_plane, shadow_plane_state->data, fb, &damage); +	} -	ast_set_index_reg_mask(ast, AST_IO_SEQ_PORT, 0x1, 0xdf, 0x00); +	/* +	 * Some BMCs stop scanning out the video signal after the driver +	 * reprogrammed the offset or scanout address. This stalls display +	 * output for several seconds and makes the display unusable. +	 * Therefore only update the offset if it changes and reprogram the +	 * address after enabling the plane. +	 */ +	if (!old_fb || old_fb->pitches[0] != fb->pitches[0]) +		ast_set_offset_reg(ast, fb); +	if (!old_fb) { +		ast_set_start_address_crt1(ast, (u32)ast_plane->offset); +		ast_set_index_reg_mask(ast, AST_IO_SEQ_PORT, 0x1, 0xdf, 0x00); +	}  } -static void -ast_primary_plane_helper_atomic_disable(struct drm_plane *plane, -					struct drm_atomic_state *state) +static void ast_primary_plane_helper_atomic_disable(struct drm_plane *plane, +						    struct drm_atomic_state *state)  {  	struct ast_private *ast = to_ast_private(plane->dev); @@ -624,7 +695,7 @@ ast_primary_plane_helper_atomic_disable(struct drm_plane *plane,  }  static const struct drm_plane_helper_funcs ast_primary_plane_helper_funcs = { -	DRM_GEM_VRAM_PLANE_HELPER_FUNCS, +	DRM_GEM_SHADOW_PLANE_HELPER_FUNCS,  	.atomic_check = ast_primary_plane_helper_atomic_check,  	.atomic_update = ast_primary_plane_helper_atomic_update,  	.atomic_disable = ast_primary_plane_helper_atomic_disable, @@ -634,27 +705,30 @@ static const struct drm_plane_funcs ast_primary_plane_funcs = {  	.update_plane = drm_atomic_helper_update_plane,  	.disable_plane = drm_atomic_helper_disable_plane,  	.destroy = drm_plane_cleanup, -	.reset = drm_atomic_helper_plane_reset, -	.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, -	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state, +	DRM_GEM_SHADOW_PLANE_FUNCS,  };  static int ast_primary_plane_init(struct ast_private *ast)  {  	struct drm_device *dev = &ast->base; -	struct drm_plane *primary_plane = &ast->primary_plane; +	struct ast_plane *ast_primary_plane = &ast->primary_plane; +	struct drm_plane *primary_plane = &ast_primary_plane->base; +	void __iomem *vaddr = ast->vram; +	u64 offset = ast->vram_base; +	unsigned long cursor_size = roundup(AST_HWC_SIZE + AST_HWC_SIGNATURE_SIZE, PAGE_SIZE); +	unsigned long size = ast->vram_fb_available - cursor_size;  	int ret; -	ret = drm_universal_plane_init(dev, primary_plane, 0x01, -				       &ast_primary_plane_funcs, -				       ast_primary_plane_formats, -				       ARRAY_SIZE(ast_primary_plane_formats), -				       NULL, DRM_PLANE_TYPE_PRIMARY, NULL); +	ret = ast_plane_init(dev, ast_primary_plane, vaddr, offset, size, +			     0x01, &ast_primary_plane_funcs, +			     ast_primary_plane_formats, ARRAY_SIZE(ast_primary_plane_formats), +			     NULL, DRM_PLANE_TYPE_PRIMARY);  	if (ret) { -		drm_err(dev, "drm_universal_plane_init() failed: %d\n", ret); +		drm_err(dev, "ast_plane_init() failed: %d\n", ret);  		return ret;  	}  	drm_plane_helper_add(primary_plane, &ast_primary_plane_helper_funcs); +	drm_plane_enable_fb_damage_clips(primary_plane);  	return 0;  } @@ -774,99 +848,79 @@ static const uint32_t ast_cursor_plane_formats[] = {  static int ast_cursor_plane_helper_atomic_check(struct drm_plane *plane,  						struct drm_atomic_state *state)  { -	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, -										 plane); -	struct drm_framebuffer *fb = new_plane_state->fb; -	struct drm_crtc_state *crtc_state; +	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane); +	struct drm_framebuffer *new_fb = new_plane_state->fb; +	struct drm_crtc_state *new_crtc_state = NULL;  	int ret; -	if (!new_plane_state->crtc) -		return 0; - -	crtc_state = drm_atomic_get_new_crtc_state(state, -						   new_plane_state->crtc); +	if (new_plane_state->crtc) +		new_crtc_state = drm_atomic_get_new_crtc_state(state, new_plane_state->crtc); -	ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state, +	ret = drm_atomic_helper_check_plane_state(new_plane_state, new_crtc_state,  						  DRM_PLANE_NO_SCALING,  						  DRM_PLANE_NO_SCALING,  						  true, true); -	if (ret) +	if (ret || !new_plane_state->visible)  		return ret; -	if (!new_plane_state->visible) -		return 0; - -	if (fb->width > AST_MAX_HWC_WIDTH || fb->height > AST_MAX_HWC_HEIGHT) +	if (new_fb->width > AST_MAX_HWC_WIDTH || new_fb->height > AST_MAX_HWC_HEIGHT)  		return -EINVAL;  	return 0;  } -static void -ast_cursor_plane_helper_atomic_update(struct drm_plane *plane, -				      struct drm_atomic_state *state) +static void ast_cursor_plane_helper_atomic_update(struct drm_plane *plane, +						  struct drm_atomic_state *state)  { -	struct ast_cursor_plane *ast_cursor_plane = to_ast_cursor_plane(plane); -	struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, -									   plane); -	struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, -									   plane); -	struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(new_state); -	struct drm_framebuffer *fb = new_state->fb; +	struct ast_plane *ast_plane = to_ast_plane(plane); +	struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane); +	struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); +	struct drm_framebuffer *fb = plane_state->fb; +	struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);  	struct ast_private *ast = to_ast_private(plane->dev); -	struct iosys_map dst_map = -		ast_cursor_plane->hwc[ast_cursor_plane->next_hwc_index].map; -	u64 dst_off = -		ast_cursor_plane->hwc[ast_cursor_plane->next_hwc_index].off;  	struct iosys_map src_map = shadow_plane_state->data[0]; +	struct drm_rect damage; +	const u8 *src = src_map.vaddr; /* TODO: Use mapping abstraction properly */ +	u64 dst_off = ast_plane->offset; +	u8 __iomem *dst = ast_plane->vaddr; /* TODO: Use mapping abstraction properly */ +	u8 __iomem *sig = dst + AST_HWC_SIZE; /* TODO: Use mapping abstraction properly */  	unsigned int offset_x, offset_y;  	u16 x, y;  	u8 x_offset, y_offset; -	u8 __iomem *dst; -	u8 __iomem *sig; -	const u8 *src; - -	src = src_map.vaddr; /* TODO: Use mapping abstraction properly */ -	dst = dst_map.vaddr_iomem; /* TODO: Use mapping abstraction properly */ -	sig = dst + AST_HWC_SIZE; /* TODO: Use mapping abstraction properly */  	/* -	 * Do data transfer to HW cursor BO. If a new cursor image was installed, -	 * point the scanout engine to dst_gbo's offset and page-flip the HWC buffers. +	 * Do data transfer to hardware buffer and point the scanout +	 * engine to the offset.  	 */ -	ast_update_cursor_image(dst, src, fb->width, fb->height); - -	if (new_state->fb != old_state->fb) { +	if (drm_atomic_helper_damage_merged(old_plane_state, plane_state, &damage)) { +		ast_update_cursor_image(dst, src, fb->width, fb->height);  		ast_set_cursor_base(ast, dst_off); - -		++ast_cursor_plane->next_hwc_index; -		ast_cursor_plane->next_hwc_index %= ARRAY_SIZE(ast_cursor_plane->hwc);  	}  	/*  	 * Update location in HWC signature and registers.  	 */ -	writel(new_state->crtc_x, sig + AST_HWC_SIGNATURE_X); -	writel(new_state->crtc_y, sig + AST_HWC_SIGNATURE_Y); +	writel(plane_state->crtc_x, sig + AST_HWC_SIGNATURE_X); +	writel(plane_state->crtc_y, sig + AST_HWC_SIGNATURE_Y);  	offset_x = AST_MAX_HWC_WIDTH - fb->width;  	offset_y = AST_MAX_HWC_HEIGHT - fb->height; -	if (new_state->crtc_x < 0) { -		x_offset = (-new_state->crtc_x) + offset_x; +	if (plane_state->crtc_x < 0) { +		x_offset = (-plane_state->crtc_x) + offset_x;  		x = 0;  	} else {  		x_offset = offset_x; -		x = new_state->crtc_x; +		x = plane_state->crtc_x;  	} -	if (new_state->crtc_y < 0) { -		y_offset = (-new_state->crtc_y) + offset_y; +	if (plane_state->crtc_y < 0) { +		y_offset = (-plane_state->crtc_y) + offset_y;  		y = 0;  	} else {  		y_offset = offset_y; -		y = new_state->crtc_y; +		y = plane_state->crtc_y;  	}  	ast_set_cursor_location(ast, x, y, x_offset, y_offset); @@ -875,9 +929,8 @@ ast_cursor_plane_helper_atomic_update(struct drm_plane *plane,  	ast_set_cursor_enabled(ast, true);  } -static void -ast_cursor_plane_helper_atomic_disable(struct drm_plane *plane, -				       struct drm_atomic_state *state) +static void ast_cursor_plane_helper_atomic_disable(struct drm_plane *plane, +						   struct drm_atomic_state *state)  {  	struct ast_private *ast = to_ast_private(plane->dev); @@ -891,41 +944,22 @@ static const struct drm_plane_helper_funcs ast_cursor_plane_helper_funcs = {  	.atomic_disable = ast_cursor_plane_helper_atomic_disable,  }; -static void ast_cursor_plane_destroy(struct drm_plane *plane) -{ -	struct ast_cursor_plane *ast_cursor_plane = to_ast_cursor_plane(plane); -	size_t i; -	struct drm_gem_vram_object *gbo; -	struct iosys_map map; - -	for (i = 0; i < ARRAY_SIZE(ast_cursor_plane->hwc); ++i) { -		gbo = ast_cursor_plane->hwc[i].gbo; -		map = ast_cursor_plane->hwc[i].map; -		drm_gem_vram_vunmap(gbo, &map); -		drm_gem_vram_unpin(gbo); -		drm_gem_vram_put(gbo); -	} - -	drm_plane_cleanup(plane); -} -  static const struct drm_plane_funcs ast_cursor_plane_funcs = {  	.update_plane = drm_atomic_helper_update_plane,  	.disable_plane = drm_atomic_helper_disable_plane, -	.destroy = ast_cursor_plane_destroy, +	.destroy = drm_plane_cleanup,  	DRM_GEM_SHADOW_PLANE_FUNCS,  };  static int ast_cursor_plane_init(struct ast_private *ast)  {  	struct drm_device *dev = &ast->base; -	struct ast_cursor_plane *ast_cursor_plane = &ast->cursor_plane; +	struct ast_plane *ast_cursor_plane = &ast->cursor_plane;  	struct drm_plane *cursor_plane = &ast_cursor_plane->base; -	size_t size, i; -	struct drm_gem_vram_object *gbo; -	struct iosys_map map; +	size_t size; +	void __iomem *vaddr; +	u64 offset;  	int ret; -	s64 off;  	/*  	 * Allocate backing storage for cursors. The BOs are permanently @@ -934,60 +968,26 @@ static int ast_cursor_plane_init(struct ast_private *ast)  	size = roundup(AST_HWC_SIZE + AST_HWC_SIGNATURE_SIZE, PAGE_SIZE); -	for (i = 0; i < ARRAY_SIZE(ast_cursor_plane->hwc); ++i) { -		gbo = drm_gem_vram_create(dev, size, 0); -		if (IS_ERR(gbo)) { -			ret = PTR_ERR(gbo); -			goto err_hwc; -		} -		ret = drm_gem_vram_pin(gbo, DRM_GEM_VRAM_PL_FLAG_VRAM | -					    DRM_GEM_VRAM_PL_FLAG_TOPDOWN); -		if (ret) -			goto err_drm_gem_vram_put; -		ret = drm_gem_vram_vmap(gbo, &map); -		if (ret) -			goto err_drm_gem_vram_unpin; -		off = drm_gem_vram_offset(gbo); -		if (off < 0) { -			ret = off; -			goto err_drm_gem_vram_vunmap; -		} -		ast_cursor_plane->hwc[i].gbo = gbo; -		ast_cursor_plane->hwc[i].map = map; -		ast_cursor_plane->hwc[i].off = off; -	} +	if (ast->vram_fb_available < size) +		return -ENOMEM; -	/* -	 * Create the cursor plane. The plane's destroy callback will release -	 * the backing storages' BO memory. -	 */ +	vaddr = ast->vram + ast->vram_fb_available - size; +	offset = ast->vram_base + ast->vram_fb_available - size; -	ret = drm_universal_plane_init(dev, cursor_plane, 0x01, -				       &ast_cursor_plane_funcs, -				       ast_cursor_plane_formats, -				       ARRAY_SIZE(ast_cursor_plane_formats), -				       NULL, DRM_PLANE_TYPE_CURSOR, NULL); +	ret = ast_plane_init(dev, ast_cursor_plane, vaddr, offset, size, +			     0x01, &ast_cursor_plane_funcs, +			     ast_cursor_plane_formats, ARRAY_SIZE(ast_cursor_plane_formats), +			     NULL, DRM_PLANE_TYPE_CURSOR);  	if (ret) { -		drm_err(dev, "drm_universal_plane failed(): %d\n", ret); -		goto err_hwc; +		drm_err(dev, "ast_plane_init() failed: %d\n", ret); +		return ret;  	}  	drm_plane_helper_add(cursor_plane, &ast_cursor_plane_helper_funcs); +	drm_plane_enable_fb_damage_clips(cursor_plane); -	return 0; +	ast->vram_fb_available -= size; -err_hwc: -	while (i) { -		--i; -		gbo = ast_cursor_plane->hwc[i].gbo; -		map = ast_cursor_plane->hwc[i].map; -err_drm_gem_vram_vunmap: -		drm_gem_vram_vunmap(gbo, &map); -err_drm_gem_vram_unpin: -		drm_gem_vram_unpin(gbo); -err_drm_gem_vram_put: -		drm_gem_vram_put(gbo); -	} -	return ret; +	return 0;  }  /* @@ -1026,9 +1026,11 @@ static void ast_crtc_dpms(struct drm_crtc *crtc, int mode)  			ast_set_color_reg(ast, format);  			ast_set_vbios_color_reg(ast, format, vbios_mode_info); +			if (crtc->state->gamma_lut) +				ast_crtc_set_gamma(ast, format, crtc->state->gamma_lut->data); +			else +				ast_crtc_set_gamma_linear(ast, format);  		} - -		ast_crtc_load_lut(ast, crtc);  		break;  	case DRM_MODE_DPMS_STANDBY:  	case DRM_MODE_DPMS_SUSPEND: @@ -1123,47 +1125,50 @@ static int ast_crtc_helper_atomic_check(struct drm_crtc *crtc,  					struct drm_atomic_state *state)  {  	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); +	struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc); +	struct ast_crtc_state *old_ast_crtc_state = to_ast_crtc_state(old_crtc_state);  	struct drm_device *dev = crtc->dev;  	struct ast_crtc_state *ast_state;  	const struct drm_format_info *format;  	bool succ;  	int ret; -	ret = drm_atomic_helper_check_crtc_state(crtc_state, false); +	if (!crtc_state->enable) +		return 0; + +	ret = drm_atomic_helper_check_crtc_primary_plane(crtc_state);  	if (ret)  		return ret; -	if (!crtc_state->enable) -		goto out; -  	ast_state = to_ast_crtc_state(crtc_state);  	format = ast_state->format;  	if (drm_WARN_ON_ONCE(dev, !format))  		return -EINVAL; /* BUG: We didn't set format in primary check(). */ +	/* +	 * The gamma LUT has to be reloaded after changing the primary +	 * plane's color format. +	 */ +	if (old_ast_crtc_state->format != format) +		crtc_state->color_mgmt_changed = true; + +	if (crtc_state->color_mgmt_changed && crtc_state->gamma_lut) { +		if (crtc_state->gamma_lut->length != +		    AST_LUT_SIZE * sizeof(struct drm_color_lut)) { +			drm_err(dev, "Wrong size for gamma_lut %zu\n", +				crtc_state->gamma_lut->length); +			return -EINVAL; +		} +	} +  	succ = ast_get_vbios_mode_info(format, &crtc_state->mode,  				       &crtc_state->adjusted_mode,  				       &ast_state->vbios_mode_info);  	if (!succ)  		return -EINVAL; -out: -	return drm_atomic_add_affected_planes(state, crtc); -} - -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); +	return 0;  }  static void @@ -1172,35 +1177,34 @@ ast_crtc_helper_atomic_flush(struct drm_crtc *crtc,  {  	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,  									  crtc); -	struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state, -									      crtc);  	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  	 * plane's color format.  	 */ -	if (old_ast_crtc_state->format != ast_crtc_state->format) -		ast_crtc_load_lut(ast, crtc); +	if (crtc_state->enable && crtc_state->color_mgmt_changed) { +		if (crtc_state->gamma_lut) +			ast_crtc_set_gamma(ast, +					   ast_crtc_state->format, +					   crtc_state->gamma_lut->data); +		else +			ast_crtc_set_gamma_linear(ast, ast_crtc_state->format); +	}  	//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 -ast_crtc_helper_atomic_enable(struct drm_crtc *crtc, -			      struct drm_atomic_state *state) +static void ast_crtc_helper_atomic_enable(struct drm_crtc *crtc, struct drm_atomic_state *state)  {  	struct drm_device *dev = crtc->dev;  	struct ast_private *ast = to_ast_private(dev); -	struct drm_crtc_state *crtc_state = crtc->state; +	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(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; @@ -1217,12 +1221,9 @@ ast_crtc_helper_atomic_enable(struct drm_crtc *crtc,  	ast_crtc_dpms(crtc, DRM_MODE_DPMS_ON);  } -static void -ast_crtc_helper_atomic_disable(struct drm_crtc *crtc, -			       struct drm_atomic_state *state) +static void ast_crtc_helper_atomic_disable(struct drm_crtc *crtc, struct drm_atomic_state *state)  { -	struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state, -									      crtc); +	struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc);  	struct drm_device *dev = crtc->dev;  	struct ast_private *ast = to_ast_private(dev); @@ -1250,7 +1251,6 @@ 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, @@ -1317,13 +1317,15 @@ static int ast_crtc_init(struct drm_device *dev)  	struct drm_crtc *crtc = &ast->crtc;  	int ret; -	ret = drm_crtc_init_with_planes(dev, crtc, &ast->primary_plane, +	ret = drm_crtc_init_with_planes(dev, crtc, &ast->primary_plane.base,  					&ast->cursor_plane.base, &ast_crtc_funcs,  					NULL);  	if (ret)  		return ret; -	drm_mode_crtc_set_gamma_size(crtc, 256); +	drm_mode_crtc_set_gamma_size(crtc, AST_LUT_SIZE); +	drm_crtc_enable_color_mgmt(crtc, 0, false, AST_LUT_SIZE); +  	drm_crtc_helper_add(crtc, &ast_crtc_helper_funcs);  	return 0; @@ -1718,13 +1720,46 @@ static int ast_astdp_output_init(struct ast_private *ast)   * Mode config   */ +static void ast_mode_config_helper_atomic_commit_tail(struct drm_atomic_state *state) +{ +	struct ast_private *ast = to_ast_private(state->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); +	drm_atomic_helper_commit_tail_rpm(state); +	mutex_unlock(&ast->ioregs_lock); +} +  static const struct drm_mode_config_helper_funcs ast_mode_config_helper_funcs = { -	.atomic_commit_tail = drm_atomic_helper_commit_tail_rpm, +	.atomic_commit_tail = ast_mode_config_helper_atomic_commit_tail,  }; +static enum drm_mode_status ast_mode_config_mode_valid(struct drm_device *dev, +						       const struct drm_display_mode *mode) +{ +	static const unsigned long max_bpp = 4; /* DRM_FORMAT_XRGB8888 */ +	struct ast_private *ast = to_ast_private(dev); +	unsigned long fbsize, fbpages, max_fbpages; + +	max_fbpages = (ast->vram_fb_available) >> PAGE_SHIFT; + +	fbsize = mode->hdisplay * mode->vdisplay * max_bpp; +	fbpages = DIV_ROUND_UP(fbsize, PAGE_SIZE); + +	if (fbpages > max_fbpages) +		return MODE_MEM; + +	return MODE_OK; +} +  static const struct drm_mode_config_funcs ast_mode_config_funcs = { -	.fb_create = drm_gem_fb_create, -	.mode_valid = drm_vram_helper_mode_valid, +	.fb_create = drm_gem_fb_create_with_dirty, +	.mode_valid = ast_mode_config_mode_valid,  	.atomic_check = drm_atomic_helper_check,  	.atomic_commit = drm_atomic_helper_commit,  }; @@ -1732,7 +1767,6 @@ static const struct drm_mode_config_funcs ast_mode_config_funcs = {  int ast_mode_config_init(struct ast_private *ast)  {  	struct drm_device *dev = &ast->base; -	struct pci_dev *pdev = to_pci_dev(dev->dev);  	int ret;  	ret = drmm_mode_config_init(dev); @@ -1743,8 +1777,6 @@ int ast_mode_config_init(struct ast_private *ast)  	dev->mode_config.min_width = 0;  	dev->mode_config.min_height = 0;  	dev->mode_config.preferred_depth = 24; -	dev->mode_config.prefer_shadow = 1; -	dev->mode_config.fb_base = pci_resource_start(pdev, 0);  	if (ast->chip == AST2100 ||  	    ast->chip == AST2200 || @@ -1761,7 +1793,6 @@ int ast_mode_config_init(struct ast_private *ast)  	dev->mode_config.helper_private = &ast_mode_config_helper_funcs; -  	ret = ast_primary_plane_init(ast);  	if (ret)  		return ret; |