diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c
index ab7cb7d896c3..225aa17895bd 100644
--- a/drivers/gpu/drm/drm_gem_shmem_helper.c
+++ b/drivers/gpu/drm/drm_gem_shmem_helper.c
@@ -71,7 +71,12 @@ __drm_gem_shmem_create(struct drm_device *dev, size_t size, bool private, bool f
 
 	size = PAGE_ALIGN(size);
 
-	if (dev->driver->gem_create_object) {
+	if (dev->driver->gem_create_object_fbdev && fbdev) {
+		obj = dev->driver->gem_create_object_fbdev(dev, size);
+		if (IS_ERR(obj))
+			return ERR_CAST(obj);
+		shmem = to_drm_gem_shmem_obj(obj);
+	} else if (dev->driver->gem_create_object) {
 		obj = dev->driver->gem_create_object(dev, size);
 		if (IS_ERR(obj))
 			return ERR_CAST(obj);
diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.c b/drivers/gpu/drm/virtio/virtgpu_drv.c
index 5f25a8d15464..ee414f6e785a 100644
--- a/drivers/gpu/drm/virtio/virtgpu_drv.c
+++ b/drivers/gpu/drm/virtio/virtgpu_drv.c
@@ -203,6 +203,7 @@ static const struct drm_driver driver = {
 	.postclose = virtio_gpu_driver_postclose,
 
 	.dumb_create = virtio_gpu_mode_dumb_create,
+	.dumb_create_fbdev = virtio_gpu_mode_dumb_create, // same as dumb_create
 	.dumb_map_offset = virtio_gpu_mode_dumb_mmap,
 
 #if defined(CONFIG_DEBUG_FS)
@@ -215,6 +216,7 @@ static const struct drm_driver driver = {
 	.gem_prime_import_sg_table = virtgpu_gem_prime_import_sg_table,
 
 	.gem_create_object = virtio_gpu_create_object,
+	.gem_create_object_fbdev = virtio_gpu_create_object_fbdev,
 	.fops = &virtio_gpu_driver_fops,
 
 	.ioctls = virtio_gpu_ioctls,
diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h
index 0a194aaad419..71556c21c029 100644
--- a/drivers/gpu/drm/virtio/virtgpu_drv.h
+++ b/drivers/gpu/drm/virtio/virtgpu_drv.h
@@ -449,6 +449,8 @@ void virtio_gpu_fence_event_process(struct virtio_gpu_device *vdev,
 void virtio_gpu_cleanup_object(struct virtio_gpu_object *bo);
 struct drm_gem_object *virtio_gpu_create_object(struct drm_device *dev,
 						size_t size);
+struct drm_gem_object *virtio_gpu_create_object_fbdev(struct drm_device *dev,
+						      size_t size);
 int virtio_gpu_object_create(struct virtio_gpu_device *vgdev,
 			     struct virtio_gpu_object_params *params,
 			     struct virtio_gpu_object **bo_ptr,
diff --git a/drivers/gpu/drm/virtio/virtgpu_object.c b/drivers/gpu/drm/virtio/virtgpu_object.c
index f293e6ad52da..255f2d650451 100644
--- a/drivers/gpu/drm/virtio/virtgpu_object.c
+++ b/drivers/gpu/drm/virtio/virtgpu_object.c
@@ -132,8 +132,8 @@ bool virtio_gpu_is_shmem(struct virtio_gpu_object *bo)
 	return bo->base.base.funcs == &virtio_gpu_shmem_funcs;
 }
 
-struct drm_gem_object *virtio_gpu_create_object(struct drm_device *dev,
-						size_t size)
+static struct drm_gem_object *__virtio_gpu_create_object(struct drm_device *dev,
+							 size_t size)
 {
 	struct virtio_gpu_object_shmem *shmem;
 	struct drm_gem_shmem_object *dshmem;
@@ -143,10 +143,58 @@ struct drm_gem_object *virtio_gpu_create_object(struct drm_device *dev,
 		return ERR_PTR(-ENOMEM);
 
 	dshmem = &shmem->base.base;
-	dshmem->base.funcs = &virtio_gpu_shmem_funcs;
 	return &dshmem->base;
 }
 
+struct drm_gem_object *virtio_gpu_create_object(struct drm_device *dev,
+						size_t size)
+{
+	struct drm_gem_object *obj;
+
+	obj = __virtio_gpu_create_object(dev, size);
+	if (IS_ERR(obj))
+		return obj;
+	obj->funcs = &virtio_gpu_shmem_funcs;
+
+	return obj;
+}
+
+#if defined(CONFIG_DRM_FBDEV_EMULATION)
+static const struct drm_gem_object_funcs virtio_gpu_shmem_funcs_fbdev = {
+	.free = virtio_gpu_free_object,
+	.open = virtio_gpu_gem_object_open,
+	.close = virtio_gpu_gem_object_close,
+	.print_info = drm_gem_shmem_object_print_info,
+	.export = virtgpu_gem_prime_export,
+	.pin = drm_gem_shmem_object_pin,
+	.unpin = drm_gem_shmem_object_unpin,
+	.get_sg_table = drm_gem_shmem_object_get_sg_table,
+	.vmap = drm_gem_shmem_object_vmap,
+	.vunmap = drm_gem_shmem_object_vunmap,
+	.mmap = drm_gem_shmem_object_mmap_fbdev,
+	.vm_ops = &drm_gem_shmem_vm_ops_fbdev,
+};
+
+struct drm_gem_object *virtio_gpu_create_object_fbdev(struct drm_device *dev,
+						      size_t size)
+{
+	struct drm_gem_object *obj;
+
+	obj = __virtio_gpu_create_object(dev, size);
+	if (IS_ERR(obj))
+		return obj;
+	obj->funcs = &virtio_gpu_shmem_funcs_fbdev;
+
+	return obj;
+}
+#else
+struct drm_gem_object *virtio_gpu_create_object_fbdev(struct drm_device *dev,
+						      size_t size)
+{
+	return ERR_PTR(-ENOSYS);
+}
+#endif
+
 static int virtio_gpu_object_shmem_init(struct virtio_gpu_device *vgdev,
 					struct virtio_gpu_object *bo,
 					struct virtio_gpu_mem_entry **ents,
diff --git a/include/drm/drm_drv.h b/include/drm/drm_drv.h
index da4a095de1e7..9081281c1f39 100644
--- a/include/drm/drm_drv.h
+++ b/include/drm/drm_drv.h
@@ -298,6 +298,16 @@ struct drm_driver {
 	struct drm_gem_object *(*gem_create_object)(struct drm_device *dev,
 						    size_t size);
 
+	/**
+	 * @gem_create_object_fbdev: constructor for gem objects that back fbdev
+	 *
+	 * Hook for allocating the GEM object struct, for use by the CMA
+	 * and SHMEM GEM helpers. Returns a GEM object on success, or an
+	 * ERR_PTR()-encoded error code otherwise.
+	 */
+	struct drm_gem_object *(*gem_create_object_fbdev)(struct drm_device *dev,
+							  size_t size);
+
 	/**
 	 * @prime_handle_to_fd:
 	 *
