diff options
Diffstat (limited to 'drivers/gpu/drm/vkms/vkms_writeback.c')
| -rw-r--r-- | drivers/gpu/drm/vkms/vkms_writeback.c | 123 |
1 files changed, 82 insertions, 41 deletions
diff --git a/drivers/gpu/drm/vkms/vkms_writeback.c b/drivers/gpu/drm/vkms/vkms_writeback.c index 0935686475a0..097ae1f0a230 100644 --- a/drivers/gpu/drm/vkms/vkms_writeback.c +++ b/drivers/gpu/drm/vkms/vkms_writeback.c @@ -1,39 +1,55 @@ // SPDX-License-Identifier: GPL-2.0+ -#include <linux/dma-buf-map.h> +#include <linux/iosys-map.h> #include <drm/drm_atomic.h> +#include <drm/drm_edid.h> #include <drm/drm_fourcc.h> #include <drm/drm_writeback.h> +#include <drm/drm_print.h> #include <drm/drm_probe_helper.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_gem_shmem_helper.h> #include "vkms_drv.h" +#include "vkms_formats.h" static const u32 vkms_wb_formats[] = { + DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB8888, + DRM_FORMAT_ABGR8888, + DRM_FORMAT_XRGB16161616, + DRM_FORMAT_ARGB16161616, + DRM_FORMAT_RGB565 }; static const struct drm_connector_funcs vkms_wb_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 vkms_wb_encoder_atomic_check(struct drm_encoder *encoder, - struct drm_crtc_state *crtc_state, - struct drm_connector_state *conn_state) +static int vkms_wb_atomic_check(struct drm_connector *connector, + struct drm_atomic_state *state) { + struct drm_connector_state *conn_state = + drm_atomic_get_new_connector_state(state, connector); + struct drm_crtc_state *crtc_state; struct drm_framebuffer *fb; - const struct drm_display_mode *mode = &crtc_state->mode; + const struct drm_display_mode *mode; + int ret; if (!conn_state->writeback_job || !conn_state->writeback_job->fb) return 0; + if (!conn_state->crtc) + return 0; + + crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc); + mode = &crtc_state->mode; + fb = conn_state->writeback_job->fb; if (fb->width != mode->hdisplay || fb->height != mode->vdisplay) { DRM_DEBUG_KMS("Invalid framebuffer size %ux%u\n", @@ -41,19 +57,13 @@ static int vkms_wb_encoder_atomic_check(struct drm_encoder *encoder, return -EINVAL; } - if (fb->format->format != vkms_wb_formats[0]) { - DRM_DEBUG_KMS("Invalid pixel format %p4cc\n", - &fb->format->format); - return -EINVAL; - } + ret = drm_atomic_helper_check_wb_connector_state(connector, state); + if (ret < 0) + return ret; return 0; } -static const struct drm_encoder_helper_funcs vkms_wb_encoder_helper_funcs = { - .atomic_check = vkms_wb_encoder_atomic_check, -}; - static int vkms_wb_connector_get_modes(struct drm_connector *connector) { struct drm_device *dev = connector->dev; @@ -65,41 +75,51 @@ static int vkms_wb_connector_get_modes(struct drm_connector *connector) static int vkms_wb_prepare_job(struct drm_writeback_connector *wb_connector, struct drm_writeback_job *job) { - struct drm_gem_object *gem_obj; - struct dma_buf_map map; + struct vkms_writeback_job *vkmsjob; int ret; if (!job->fb) return 0; - gem_obj = drm_gem_fb_get_obj(job->fb, 0); - ret = drm_gem_shmem_vmap(gem_obj, &map); + vkmsjob = kzalloc(sizeof(*vkmsjob), GFP_KERNEL); + if (!vkmsjob) + return -ENOMEM; + + ret = drm_gem_fb_vmap(job->fb, vkmsjob->wb_frame_info.map, vkmsjob->data); if (ret) { DRM_ERROR("vmap failed: %d\n", ret); - return ret; + goto err_kfree; } - job->priv = map.vaddr; + vkmsjob->wb_frame_info.fb = job->fb; + drm_framebuffer_get(vkmsjob->wb_frame_info.fb); + + job->priv = vkmsjob; return 0; + +err_kfree: + kfree(vkmsjob); + return ret; } static void vkms_wb_cleanup_job(struct drm_writeback_connector *connector, struct drm_writeback_job *job) { - struct drm_gem_object *gem_obj; - struct vkms_device *vkmsdev; - struct dma_buf_map map; + struct vkms_writeback_job *vkmsjob = job->priv; + struct vkms_output *vkms_output = container_of(connector, + struct vkms_output, + wb_connector); if (!job->fb) return; - gem_obj = drm_gem_fb_get_obj(job->fb, 0); - dma_buf_map_set_vaddr(&map, job->priv); - drm_gem_shmem_vunmap(gem_obj, &map); + drm_gem_fb_vunmap(job->fb, vkmsjob->wb_frame_info.map); + + drm_framebuffer_put(vkmsjob->wb_frame_info.fb); - vkmsdev = drm_device_to_vkms_device(gem_obj->dev); - vkms_set_composer(&vkmsdev->output, false); + vkms_set_composer(vkms_output, false); + kfree(vkmsjob); } static void vkms_wb_atomic_commit(struct drm_connector *conn, @@ -107,22 +127,33 @@ static void vkms_wb_atomic_commit(struct drm_connector *conn, { struct drm_connector_state *connector_state = drm_atomic_get_new_connector_state(state, conn); - struct vkms_device *vkmsdev = drm_device_to_vkms_device(conn->dev); - struct vkms_output *output = &vkmsdev->output; + struct vkms_output *output = drm_crtc_to_vkms_output(connector_state->crtc); struct drm_writeback_connector *wb_conn = &output->wb_connector; struct drm_connector_state *conn_state = wb_conn->base.state; struct vkms_crtc_state *crtc_state = output->composer_state; + struct drm_framebuffer *fb = connector_state->writeback_job->fb; + u16 crtc_height = crtc_state->base.mode.vdisplay; + u16 crtc_width = crtc_state->base.mode.hdisplay; + struct vkms_writeback_job *active_wb; + struct vkms_frame_info *wb_frame_info; + u32 wb_format = fb->format->format; if (!conn_state) return; - vkms_set_composer(&vkmsdev->output, true); + vkms_set_composer(output, true); + + active_wb = conn_state->writeback_job->priv; + wb_frame_info = &active_wb->wb_frame_info; spin_lock_irq(&output->composer_lock); - crtc_state->active_writeback = conn_state->writeback_job->priv; + crtc_state->active_writeback = active_wb; crtc_state->wb_pending = true; spin_unlock_irq(&output->composer_lock); drm_writeback_queue_job(wb_conn, connector_state); + active_wb->pixel_write = get_pixel_write_function(wb_format); + drm_rect_init(&wb_frame_info->src, 0, 0, crtc_width, crtc_height); + drm_rect_init(&wb_frame_info->dst, 0, 0, crtc_width, crtc_height); } static const struct drm_connector_helper_funcs vkms_wb_conn_helper_funcs = { @@ -130,18 +161,28 @@ static const struct drm_connector_helper_funcs vkms_wb_conn_helper_funcs = { .prepare_writeback_job = vkms_wb_prepare_job, .cleanup_writeback_job = vkms_wb_cleanup_job, .atomic_commit = vkms_wb_atomic_commit, + .atomic_check = vkms_wb_atomic_check, }; -int vkms_enable_writeback_connector(struct vkms_device *vkmsdev) +int vkms_enable_writeback_connector(struct vkms_device *vkmsdev, + struct vkms_output *vkms_output) { - struct drm_writeback_connector *wb = &vkmsdev->output.wb_connector; + struct drm_writeback_connector *wb = &vkms_output->wb_connector; + int ret; + + ret = drmm_encoder_init(&vkmsdev->drm, &vkms_output->wb_encoder, + NULL, DRM_MODE_ENCODER_VIRTUAL, NULL); + if (ret) + return ret; + vkms_output->wb_encoder.possible_crtcs |= drm_crtc_mask(&vkms_output->crtc); + vkms_output->wb_encoder.possible_clones |= + drm_encoder_mask(&vkms_output->wb_encoder); - vkmsdev->output.wb_connector.encoder.possible_crtcs = 1; drm_connector_helper_add(&wb->base, &vkms_wb_conn_helper_funcs); - return drm_writeback_connector_init(&vkmsdev->drm, wb, - &vkms_wb_connector_funcs, - &vkms_wb_encoder_helper_funcs, - vkms_wb_formats, - ARRAY_SIZE(vkms_wb_formats)); + return drmm_writeback_connector_init(&vkmsdev->drm, wb, + &vkms_wb_connector_funcs, + &vkms_output->wb_encoder, + vkms_wb_formats, + ARRAY_SIZE(vkms_wb_formats)); } |
