diff options
Diffstat (limited to 'drivers/gpu/drm/tiny/cirrus.c')
| -rw-r--r-- | drivers/gpu/drm/tiny/cirrus.c | 499 | 
1 files changed, 305 insertions, 194 deletions
diff --git a/drivers/gpu/drm/tiny/cirrus.c b/drivers/gpu/drm/tiny/cirrus.c index accfa52e78c5..594bc472862f 100644 --- a/drivers/gpu/drm/tiny/cirrus.c +++ b/drivers/gpu/drm/tiny/cirrus.c @@ -24,6 +24,7 @@  #include <video/vga.h>  #include <drm/drm_aperture.h> +#include <drm/drm_atomic.h>  #include <drm/drm_atomic_helper.h>  #include <drm/drm_atomic_state_helper.h>  #include <drm/drm_connector.h> @@ -43,7 +44,6 @@  #include <drm/drm_modeset_helper_vtables.h>  #include <drm/drm_module.h>  #include <drm/drm_probe_helper.h> -#include <drm/drm_simple_kms_helper.h>  #define DRIVER_NAME "cirrus"  #define DRIVER_DESC "qemu cirrus vga" @@ -56,16 +56,34 @@  struct cirrus_device {  	struct drm_device	       dev; -	struct drm_simple_display_pipe pipe; -	struct drm_connector	       conn; -	unsigned int		       cpp; -	unsigned int		       pitch; + +	/* modesetting pipeline */ +	struct drm_plane	       primary_plane; +	struct drm_crtc		       crtc; +	struct drm_encoder	       encoder; +	struct drm_connector	       connector; + +	/* HW resources */  	void __iomem		       *vram;  	void __iomem		       *mmio;  };  #define to_cirrus(_dev) container_of(_dev, struct cirrus_device, dev) +struct cirrus_primary_plane_state { +	struct drm_shadow_plane_state base; + +	/* HW scanout buffer */ +	const struct drm_format_info   *format; +	unsigned int		       pitch; +}; + +static inline struct cirrus_primary_plane_state * +to_cirrus_primary_plane_state(struct drm_plane_state *plane_state) +{ +	return container_of(plane_state, struct cirrus_primary_plane_state, base.base); +}; +  /* ------------------------------------------------------------------ */  /*   * The meat of this driver. The core passes us a mode and we have to program @@ -126,46 +144,42 @@ static void wreg_hdr(struct cirrus_device *cirrus, u8 val)  	iowrite8(val, cirrus->mmio + VGA_DAC_MASK);  } -static int cirrus_convert_to(struct drm_framebuffer *fb) +static const struct drm_format_info *cirrus_convert_to(struct drm_framebuffer *fb)  { -	if (fb->format->cpp[0] == 4 && fb->pitches[0] > CIRRUS_MAX_PITCH) { +	if (fb->format->format == DRM_FORMAT_XRGB8888 && fb->pitches[0] > CIRRUS_MAX_PITCH) {  		if (fb->width * 3 <= CIRRUS_MAX_PITCH)  			/* convert from XR24 to RG24 */ -			return 3; +			return drm_format_info(DRM_FORMAT_RGB888);  		else  			/* convert from XR24 to RG16 */ -			return 2; +			return drm_format_info(DRM_FORMAT_RGB565);  	} -	return 0; +	return NULL;  } -static int cirrus_cpp(struct drm_framebuffer *fb) +static const struct drm_format_info *cirrus_format(struct drm_framebuffer *fb)  { -	int convert_cpp = cirrus_convert_to(fb); +	const struct drm_format_info *format = cirrus_convert_to(fb); -	if (convert_cpp) -		return convert_cpp; -	return fb->format->cpp[0]; +	if (format) +		return format; +	return fb->format;  }  static int cirrus_pitch(struct drm_framebuffer *fb)  { -	int convert_cpp = cirrus_convert_to(fb); +	const struct drm_format_info *format = cirrus_convert_to(fb); -	if (convert_cpp) -		return convert_cpp * fb->width; +	if (format) +		return drm_format_info_min_pitch(format, 0, fb->width);  	return fb->pitches[0];  }  static void cirrus_set_start_address(struct cirrus_device *cirrus, u32 offset)  { -	int idx;  	u32 addr;  	u8 tmp; -	if (!drm_dev_enter(&cirrus->dev, &idx)) -		return; -  	addr = offset >> 2;  	wreg_crt(cirrus, 0x0c, (u8)((addr >> 8) & 0xff));  	wreg_crt(cirrus, 0x0d, (u8)(addr & 0xff)); @@ -180,21 +194,14 @@ static void cirrus_set_start_address(struct cirrus_device *cirrus, u32 offset)  	tmp &= 0x7f;  	tmp |= (addr >> 12) & 0x80;  	wreg_crt(cirrus, 0x1d, tmp); - -	drm_dev_exit(idx);  } -static int cirrus_mode_set(struct cirrus_device *cirrus, -			   struct drm_display_mode *mode, -			   struct drm_framebuffer *fb) +static void cirrus_mode_set(struct cirrus_device *cirrus, +			    struct drm_display_mode *mode)  {  	int hsyncstart, hsyncend, htotal, hdispend;  	int vtotal, vdispend; -	int tmp, idx; -	int sr07 = 0, hdr = 0; - -	if (!drm_dev_enter(&cirrus->dev, &idx)) -		return -1; +	int tmp;  	htotal = mode->htotal / 8;  	hsyncend = mode->hsync_end / 8; @@ -258,46 +265,39 @@ static int cirrus_mode_set(struct cirrus_device *cirrus,  	/* Disable Hercules/CGA compatibility */  	wreg_crt(cirrus, VGA_CRTC_MODE, 0x03); +} + +static void cirrus_format_set(struct cirrus_device *cirrus, +			      const struct drm_format_info *format) +{ +	u8 sr07, hdr;  	sr07 = rreg_seq(cirrus, 0x07);  	sr07 &= 0xe0; -	hdr = 0; -	cirrus->cpp = cirrus_cpp(fb); -	switch (cirrus->cpp * 8) { -	case 8: +	switch (format->format) { +	case DRM_FORMAT_C8:  		sr07 |= 0x11; +		hdr = 0x00;  		break; -	case 16: +	case DRM_FORMAT_RGB565:  		sr07 |= 0x17;  		hdr = 0xc1;  		break; -	case 24: +	case DRM_FORMAT_RGB888:  		sr07 |= 0x15;  		hdr = 0xc5;  		break; -	case 32: +	case DRM_FORMAT_XRGB8888:  		sr07 |= 0x19;  		hdr = 0xc5;  		break;  	default: -		drm_dev_exit(idx); -		return -1; +		return;  	}  	wreg_seq(cirrus, 0x7, sr07); -	/* Program the pitch */ -	cirrus->pitch = cirrus_pitch(fb); -	tmp = cirrus->pitch / 8; -	wreg_crt(cirrus, VGA_CRTC_OFFSET, tmp); - -	/* Enable extended blanking and pitch bits, and enable full memory */ -	tmp = 0x22; -	tmp |= (cirrus->pitch >> 7) & 0x10; -	tmp |= (cirrus->pitch >> 6) & 0x40; -	wreg_crt(cirrus, 0x1b, tmp); -  	/* Enable high-colour modes */  	wreg_gfx(cirrus, VGA_GFX_MODE, 0x40); @@ -305,208 +305,323 @@ static int cirrus_mode_set(struct cirrus_device *cirrus,  	wreg_gfx(cirrus, VGA_GFX_MISC, 0x01);  	wreg_hdr(cirrus, hdr); +} -	cirrus_set_start_address(cirrus, 0); +static void cirrus_pitch_set(struct cirrus_device *cirrus, unsigned int pitch) +{ +	u8 cr13, cr1b; -	/* Unblank (needed on S3 resume, vgabios doesn't do it then) */ -	outb(0x20, 0x3c0); +	/* Program the pitch */ +	cr13 = pitch / 8; +	wreg_crt(cirrus, VGA_CRTC_OFFSET, cr13); -	drm_dev_exit(idx); -	return 0; +	/* Enable extended blanking and pitch bits, and enable full memory */ +	cr1b = 0x22; +	cr1b |= (pitch >> 7) & 0x10; +	cr1b |= (pitch >> 6) & 0x40; +	wreg_crt(cirrus, 0x1b, cr1b); + +	cirrus_set_start_address(cirrus, 0);  } -static int cirrus_fb_blit_rect(struct drm_framebuffer *fb, -			       const struct iosys_map *vmap, -			       struct drm_rect *rect) -{ -	struct cirrus_device *cirrus = to_cirrus(fb->dev); -	struct iosys_map dst; -	int idx; +/* ------------------------------------------------------------------ */ +/* cirrus display pipe						      */ -	if (!drm_dev_enter(&cirrus->dev, &idx)) -		return -ENODEV; +static const uint32_t cirrus_primary_plane_formats[] = { +	DRM_FORMAT_RGB565, +	DRM_FORMAT_RGB888, +	DRM_FORMAT_XRGB8888, +}; -	iosys_map_set_vaddr_iomem(&dst, cirrus->vram); +static const uint64_t cirrus_primary_plane_format_modifiers[] = { +	DRM_FORMAT_MOD_LINEAR, +	DRM_FORMAT_MOD_INVALID +}; + +static int cirrus_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 cirrus_primary_plane_state *new_primary_plane_state = +		to_cirrus_primary_plane_state(new_plane_state); +	struct drm_framebuffer *fb = new_plane_state->fb; +	struct drm_crtc *new_crtc = new_plane_state->crtc; +	struct drm_crtc_state *new_crtc_state = NULL; +	int ret; +	unsigned int pitch; -	if (cirrus->cpp == fb->format->cpp[0]) { -		iosys_map_incr(&dst, drm_fb_clip_offset(fb->pitches[0], fb->format, rect)); -		drm_fb_memcpy(&dst, fb->pitches, vmap, fb, rect); +	if (new_crtc) +		new_crtc_state = drm_atomic_get_new_crtc_state(state, new_crtc); -	} else if (fb->format->cpp[0] == 4 && cirrus->cpp == 2) { -		iosys_map_incr(&dst, drm_fb_clip_offset(cirrus->pitch, fb->format, rect)); -		drm_fb_xrgb8888_to_rgb565(&dst, &cirrus->pitch, vmap, fb, rect, false); +	ret = drm_atomic_helper_check_plane_state(new_plane_state, new_crtc_state, +						  DRM_PLANE_NO_SCALING, +						  DRM_PLANE_NO_SCALING, +						  false, false); +	if (ret) +		return ret; +	else if (!new_plane_state->visible) +		return 0; -	} else if (fb->format->cpp[0] == 4 && cirrus->cpp == 3) { -		iosys_map_incr(&dst, drm_fb_clip_offset(cirrus->pitch, fb->format, rect)); -		drm_fb_xrgb8888_to_rgb888(&dst, &cirrus->pitch, vmap, fb, rect); +	pitch = cirrus_pitch(fb); -	} else { -		WARN_ON_ONCE("cpp mismatch"); -	} +	/* validate size constraints */ +	if (pitch > CIRRUS_MAX_PITCH) +		return -EINVAL; +	else if (pitch * fb->height > CIRRUS_VRAM_SIZE) +		return -EINVAL; -	drm_dev_exit(idx); +	new_primary_plane_state->format = cirrus_format(fb); +	new_primary_plane_state->pitch = pitch;  	return 0;  } -static int cirrus_fb_blit_fullscreen(struct drm_framebuffer *fb, -				     const struct iosys_map *map) +static void cirrus_primary_plane_helper_atomic_update(struct drm_plane *plane, +						      struct drm_atomic_state *state)  { -	struct drm_rect fullscreen = { -		.x1 = 0, -		.x2 = fb->width, -		.y1 = 0, -		.y2 = fb->height, -	}; -	return cirrus_fb_blit_rect(fb, map, &fullscreen); -} +	struct cirrus_device *cirrus = to_cirrus(plane->dev); +	struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane); +	struct cirrus_primary_plane_state *primary_plane_state = +		to_cirrus_primary_plane_state(plane_state); +	struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); +	struct drm_framebuffer *fb = plane_state->fb; +	const struct drm_format_info *format = primary_plane_state->format; +	unsigned int pitch = primary_plane_state->pitch; +	struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane); +	struct cirrus_primary_plane_state *old_primary_plane_state = +		to_cirrus_primary_plane_state(old_plane_state); +	struct iosys_map vaddr = IOSYS_MAP_INIT_VADDR_IOMEM(cirrus->vram); +	struct drm_atomic_helper_damage_iter iter; +	struct drm_rect damage; +	int idx; -static int cirrus_check_size(int width, int height, -			     struct drm_framebuffer *fb) -{ -	int pitch = width * 2; +	if (!fb) +		return; -	if (fb) -		pitch = cirrus_pitch(fb); +	if (!drm_dev_enter(&cirrus->dev, &idx)) +		return; -	if (pitch > CIRRUS_MAX_PITCH) -		return -EINVAL; -	if (pitch * height > CIRRUS_VRAM_SIZE) -		return -EINVAL; -	return 0; -} +	if (old_primary_plane_state->format != format) +		cirrus_format_set(cirrus, format); +	if (old_primary_plane_state->pitch != pitch) +		cirrus_pitch_set(cirrus, pitch); -/* ------------------------------------------------------------------ */ -/* cirrus connector						      */ +	drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state); +	drm_atomic_for_each_plane_damage(&iter, &damage) { +		unsigned int offset = drm_fb_clip_offset(pitch, format, &damage); +		struct iosys_map dst = IOSYS_MAP_INIT_OFFSET(&vaddr, offset); -static int cirrus_conn_get_modes(struct drm_connector *conn) -{ -	int count; +		drm_fb_blit(&dst, &pitch, format->format, shadow_plane_state->data, fb, &damage); +	} -	count = drm_add_modes_noedid(conn, -				     conn->dev->mode_config.max_width, -				     conn->dev->mode_config.max_height); -	drm_set_preferred_mode(conn, 1024, 768); -	return count; +	drm_dev_exit(idx);  } -static const struct drm_connector_helper_funcs cirrus_conn_helper_funcs = { -	.get_modes = cirrus_conn_get_modes, -}; - -static const struct drm_connector_funcs cirrus_conn_funcs = { -	.fill_modes = drm_helper_probe_single_connector_modes, -	.destroy = drm_connector_cleanup, -	.reset = drm_atomic_helper_connector_reset, -	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, -	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state, +static const struct drm_plane_helper_funcs cirrus_primary_plane_helper_funcs = { +	DRM_GEM_SHADOW_PLANE_HELPER_FUNCS, +	.atomic_check = cirrus_primary_plane_helper_atomic_check, +	.atomic_update = cirrus_primary_plane_helper_atomic_update,  }; -static int cirrus_conn_init(struct cirrus_device *cirrus) +static struct drm_plane_state * +cirrus_primary_plane_atomic_duplicate_state(struct drm_plane *plane)  { -	drm_connector_helper_add(&cirrus->conn, &cirrus_conn_helper_funcs); -	return drm_connector_init(&cirrus->dev, &cirrus->conn, -				  &cirrus_conn_funcs, DRM_MODE_CONNECTOR_VGA); +	struct drm_plane_state *plane_state = plane->state; +	struct cirrus_primary_plane_state *primary_plane_state = +		to_cirrus_primary_plane_state(plane_state); +	struct cirrus_primary_plane_state *new_primary_plane_state; +	struct drm_shadow_plane_state *new_shadow_plane_state; -} +	if (!plane_state) +		return NULL; -/* ------------------------------------------------------------------ */ -/* cirrus (simple) display pipe					      */ +	new_primary_plane_state = kzalloc(sizeof(*new_primary_plane_state), GFP_KERNEL); +	if (!new_primary_plane_state) +		return NULL; +	new_shadow_plane_state = &new_primary_plane_state->base; + +	__drm_gem_duplicate_shadow_plane_state(plane, new_shadow_plane_state); +	new_primary_plane_state->format = primary_plane_state->format; +	new_primary_plane_state->pitch = primary_plane_state->pitch; + +	return &new_shadow_plane_state->base; +} -static enum drm_mode_status cirrus_pipe_mode_valid(struct drm_simple_display_pipe *pipe, -						   const struct drm_display_mode *mode) +static void cirrus_primary_plane_atomic_destroy_state(struct drm_plane *plane, +						      struct drm_plane_state *plane_state)  { -	if (cirrus_check_size(mode->hdisplay, mode->vdisplay, NULL) < 0) -		return MODE_BAD; -	return MODE_OK; +	struct cirrus_primary_plane_state *primary_plane_state = +		to_cirrus_primary_plane_state(plane_state); + +	__drm_gem_destroy_shadow_plane_state(&primary_plane_state->base); +	kfree(primary_plane_state);  } -static int cirrus_pipe_check(struct drm_simple_display_pipe *pipe, -			     struct drm_plane_state *plane_state, -			     struct drm_crtc_state *crtc_state) +static void cirrus_reset_primary_plane(struct drm_plane *plane)  { -	struct drm_framebuffer *fb = plane_state->fb; +	struct cirrus_primary_plane_state *primary_plane_state; -	if (!fb) -		return 0; -	return cirrus_check_size(fb->width, fb->height, fb); +	if (plane->state) { +		cirrus_primary_plane_atomic_destroy_state(plane, plane->state); +		plane->state = NULL; /* must be set to NULL here */ +	} + +	primary_plane_state = kzalloc(sizeof(*primary_plane_state), GFP_KERNEL); +	if (!primary_plane_state) +		return; +	__drm_gem_reset_shadow_plane(plane, &primary_plane_state->base);  } -static void cirrus_pipe_enable(struct drm_simple_display_pipe *pipe, -			       struct drm_crtc_state *crtc_state, -			       struct drm_plane_state *plane_state) +static const struct drm_plane_funcs cirrus_primary_plane_funcs = { +	.update_plane = drm_atomic_helper_update_plane, +	.disable_plane = drm_atomic_helper_disable_plane, +	.destroy = drm_plane_cleanup, +	.reset = cirrus_reset_primary_plane, +	.atomic_duplicate_state = cirrus_primary_plane_atomic_duplicate_state, +	.atomic_destroy_state = cirrus_primary_plane_atomic_destroy_state, +}; + +static int cirrus_crtc_helper_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state)  { -	struct cirrus_device *cirrus = to_cirrus(pipe->crtc.dev); -	struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); +	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); +	int ret; + +	if (!crtc_state->enable) +		return 0; + +	ret = drm_atomic_helper_check_crtc_primary_plane(crtc_state); +	if (ret) +		return ret; -	cirrus_mode_set(cirrus, &crtc_state->mode, plane_state->fb); -	cirrus_fb_blit_fullscreen(plane_state->fb, &shadow_plane_state->data[0]); +	return 0;  } -static void cirrus_pipe_update(struct drm_simple_display_pipe *pipe, -			       struct drm_plane_state *old_state) +static void cirrus_crtc_helper_atomic_enable(struct drm_crtc *crtc, +					     struct drm_atomic_state *state)  { -	struct cirrus_device *cirrus = to_cirrus(pipe->crtc.dev); -	struct drm_plane_state *state = pipe->plane.state; -	struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(state); -	struct drm_crtc *crtc = &pipe->crtc; -	struct drm_rect rect; +	struct cirrus_device *cirrus = to_cirrus(crtc->dev); +	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); +	int idx; + +	if (!drm_dev_enter(&cirrus->dev, &idx)) +		return; -	if (state->fb && cirrus->cpp != cirrus_cpp(state->fb)) -		cirrus_mode_set(cirrus, &crtc->mode, state->fb); +	cirrus_mode_set(cirrus, &crtc_state->mode); -	if (state->fb && drm_atomic_helper_damage_merged(old_state, state, &rect)) -		cirrus_fb_blit_rect(state->fb, &shadow_plane_state->data[0], &rect); +	/* Unblank (needed on S3 resume, vgabios doesn't do it then) */ +	outb(VGA_AR_ENABLE_DISPLAY, VGA_ATT_W); + +	drm_dev_exit(idx);  } -static const struct drm_simple_display_pipe_funcs cirrus_pipe_funcs = { -	.mode_valid = cirrus_pipe_mode_valid, -	.check	    = cirrus_pipe_check, -	.enable	    = cirrus_pipe_enable, -	.update	    = cirrus_pipe_update, -	DRM_GEM_SIMPLE_DISPLAY_PIPE_SHADOW_PLANE_FUNCS, +static const struct drm_crtc_helper_funcs cirrus_crtc_helper_funcs = { +	.atomic_check = cirrus_crtc_helper_atomic_check, +	.atomic_enable = cirrus_crtc_helper_atomic_enable,  }; -static const uint32_t cirrus_formats[] = { -	DRM_FORMAT_RGB565, -	DRM_FORMAT_RGB888, -	DRM_FORMAT_XRGB8888, +static const struct drm_crtc_funcs cirrus_crtc_funcs = { +	.reset = drm_atomic_helper_crtc_reset, +	.destroy = drm_crtc_cleanup, +	.set_config = drm_atomic_helper_set_config, +	.page_flip = drm_atomic_helper_page_flip, +	.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, +	.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,  }; -static const uint64_t cirrus_modifiers[] = { -	DRM_FORMAT_MOD_LINEAR, -	DRM_FORMAT_MOD_INVALID +static const struct drm_encoder_funcs cirrus_encoder_funcs = { +	.destroy = drm_encoder_cleanup, +}; + +static int cirrus_connector_helper_get_modes(struct drm_connector *connector) +{ +	int count; + +	count = drm_add_modes_noedid(connector, +				     connector->dev->mode_config.max_width, +				     connector->dev->mode_config.max_height); +	drm_set_preferred_mode(connector, 1024, 768); +	return count; +} + +static const struct drm_connector_helper_funcs cirrus_connector_helper_funcs = { +	.get_modes = cirrus_connector_helper_get_modes, +}; + +static const struct drm_connector_funcs cirrus_connector_funcs = { +	.fill_modes = drm_helper_probe_single_connector_modes, +	.destroy = drm_connector_cleanup, +	.reset = drm_atomic_helper_connector_reset, +	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, +	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,  };  static int cirrus_pipe_init(struct cirrus_device *cirrus)  { -	return drm_simple_display_pipe_init(&cirrus->dev, -					    &cirrus->pipe, -					    &cirrus_pipe_funcs, -					    cirrus_formats, -					    ARRAY_SIZE(cirrus_formats), -					    cirrus_modifiers, -					    &cirrus->conn); +	struct drm_device *dev = &cirrus->dev; +	struct drm_plane *primary_plane; +	struct drm_crtc *crtc; +	struct drm_encoder *encoder; +	struct drm_connector *connector; +	int ret; + +	primary_plane = &cirrus->primary_plane; +	ret = drm_universal_plane_init(dev, primary_plane, 0, +				       &cirrus_primary_plane_funcs, +				       cirrus_primary_plane_formats, +				       ARRAY_SIZE(cirrus_primary_plane_formats), +				       cirrus_primary_plane_format_modifiers, +				       DRM_PLANE_TYPE_PRIMARY, NULL); +	if (ret) +		return ret; +	drm_plane_helper_add(primary_plane, &cirrus_primary_plane_helper_funcs); +	drm_plane_enable_fb_damage_clips(primary_plane); + +	crtc = &cirrus->crtc; +	ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL, +					&cirrus_crtc_funcs, NULL); +	if (ret) +		return ret; +	drm_crtc_helper_add(crtc, &cirrus_crtc_helper_funcs); + +	encoder = &cirrus->encoder; +	ret = drm_encoder_init(dev, encoder, &cirrus_encoder_funcs, +			       DRM_MODE_ENCODER_DAC, NULL); +	if (ret) +		return ret; +	encoder->possible_crtcs = drm_crtc_mask(crtc); + +	connector = &cirrus->connector; +	ret = drm_connector_init(dev, connector, &cirrus_connector_funcs, +				 DRM_MODE_CONNECTOR_VGA); +	if (ret) +		return ret; +	drm_connector_helper_add(connector, &cirrus_connector_helper_funcs); + +	ret = drm_connector_attach_encoder(connector, encoder); +	if (ret) +		return ret; + +	return 0;  }  /* ------------------------------------------------------------------ */  /* cirrus framebuffers & mode config				      */ -static struct drm_framebuffer* -cirrus_fb_create(struct drm_device *dev, struct drm_file *file_priv, -		 const struct drm_mode_fb_cmd2 *mode_cmd) +static enum drm_mode_status cirrus_mode_config_mode_valid(struct drm_device *dev, +							  const struct drm_display_mode *mode)  { -	if (mode_cmd->pixel_format != DRM_FORMAT_RGB565 && -	    mode_cmd->pixel_format != DRM_FORMAT_RGB888 && -	    mode_cmd->pixel_format != DRM_FORMAT_XRGB8888) -		return ERR_PTR(-EINVAL); -	if (cirrus_check_size(mode_cmd->width, mode_cmd->height, NULL) < 0) -		return ERR_PTR(-EINVAL); -	return drm_gem_fb_create_with_dirty(dev, file_priv, mode_cmd); +	const struct drm_format_info *format = drm_format_info(DRM_FORMAT_XRGB8888); +	uint64_t pitch = drm_format_info_min_pitch(format, 0, mode->hdisplay); + +	if (pitch * mode->vdisplay > CIRRUS_VRAM_SIZE) +		return MODE_MEM; + +	return MODE_OK;  }  static const struct drm_mode_config_funcs cirrus_mode_config_funcs = { -	.fb_create = cirrus_fb_create, +	.fb_create = drm_gem_fb_create_with_dirty, +	.mode_valid = cirrus_mode_config_mode_valid,  	.atomic_check = drm_atomic_helper_check,  	.atomic_commit = drm_atomic_helper_commit,  }; @@ -589,10 +704,6 @@ static int cirrus_pci_probe(struct pci_dev *pdev,  	if (ret)  		return ret; -	ret = cirrus_conn_init(cirrus); -	if (ret < 0) -		return ret; -  	ret = cirrus_pipe_init(cirrus);  	if (ret < 0)  		return ret;  |