drm/udl: Convert to struct drm_simple_display_pipe

Udl has a single display pipeline with a primary plane; perfect for
simple-pipe helpers. Convert it over. The old encoder and CRTC code
becomes unused and obsolete.

Exported formats for the primary plane are RGB565 and XRGB8888, with
the latter being emulated. The 16-bit format is the default and what
is used when communicating with the device.

This patch enables atomic modesetting for udl devices.

v3:
	* remove unused field crtc from struct udl_device
	* set crtc_state->no_vblank at beginning of enable()
v2:
	* move suspend/resume changes into separate patch
	* remove non-atomic code

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Reviewed-by: Emil Velikov <emil.l.velikov@gmail.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20191210084905.5570-3-tzimmermann@suse.de
This commit is contained in:
Thomas Zimmermann 2019-12-10 09:48:58 +01:00
Родитель e829cf0b30
Коммит 9fda81e00e
6 изменённых файлов: 92 добавлений и 183 удалений

Просмотреть файл

@ -1,4 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
udl-y := udl_drv.o udl_modeset.o udl_connector.o udl_encoder.o udl_main.o udl_fb.o udl_transfer.o udl_gem.o
udl-y := udl_drv.o udl_modeset.o udl_connector.o udl_main.o udl_fb.o udl_transfer.o udl_gem.o
obj-$(CONFIG_DRM_UDL) := udl.o

Просмотреть файл

@ -7,6 +7,7 @@
* Copyright (C) 2009 Bernie Thompson <bernie@plugable.com>
*/
#include <drm/drm_atomic_state_helper.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_probe_helper.h>
@ -90,13 +91,6 @@ udl_detect(struct drm_connector *connector, bool force)
return connector_status_connected;
}
static int udl_connector_set_property(struct drm_connector *connector,
struct drm_property *property,
uint64_t val)
{
return 0;
}
static void udl_connector_destroy(struct drm_connector *connector)
{
struct udl_drm_connector *udl_connector =
@ -116,10 +110,12 @@ static const struct drm_connector_helper_funcs udl_connector_helper_funcs = {
static const struct drm_connector_funcs udl_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.reset = drm_atomic_helper_connector_reset,
.detect = udl_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
.destroy = udl_connector_destroy,
.set_property = udl_connector_set_property,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
struct drm_connector *udl_connector_init(struct drm_device *dev)

Просмотреть файл

@ -45,7 +45,7 @@ static void udl_driver_release(struct drm_device *dev)
}
static struct drm_driver driver = {
.driver_features = DRIVER_MODESET | DRIVER_GEM,
.driver_features = DRIVER_ATOMIC | DRIVER_GEM | DRIVER_MODESET,
.release = udl_driver_release,
/* gem hooks */

Просмотреть файл

@ -17,8 +17,8 @@
#include <drm/drm_device.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem.h>
#include <drm/drm_simple_kms_helper.h>
struct drm_encoder;
struct drm_mode_create_dumb;
#define DRIVER_NAME "udl"
@ -51,7 +51,8 @@ struct udl_device {
struct drm_device drm;
struct device *dev;
struct usb_device *udev;
struct drm_crtc *crtc;
struct drm_simple_display_pipe display_pipe;
/* active framebuffer on the 16-bit channel */
const struct drm_framebuffer *active_fb_16;
@ -75,8 +76,6 @@ void udl_modeset_restore(struct drm_device *dev);
void udl_modeset_cleanup(struct drm_device *dev);
struct drm_connector *udl_connector_init(struct drm_device *dev);
struct drm_encoder *udl_encoder_init(struct drm_device *dev);
struct urb *udl_get_urb(struct drm_device *dev);
int udl_submit_urb(struct drm_device *dev, struct urb *urb, size_t len);

Просмотреть файл

@ -1,70 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012 Red Hat
* based in parts on udlfb.c:
* Copyright (C) 2009 Roberto De Ioris <roberto@unbit.it>
* Copyright (C) 2009 Jaya Kumar <jayakumar.lkml@gmail.com>
* Copyright (C) 2009 Bernie Thompson <bernie@plugable.com>
*/
#include <drm/drm_encoder.h>
#include <drm/drm_modeset_helper_vtables.h>
#include "udl_drv.h"
/* dummy encoder */
static void udl_enc_destroy(struct drm_encoder *encoder)
{
drm_encoder_cleanup(encoder);
kfree(encoder);
}
static void udl_encoder_disable(struct drm_encoder *encoder)
{
}
static void udl_encoder_prepare(struct drm_encoder *encoder)
{
}
static void udl_encoder_commit(struct drm_encoder *encoder)
{
}
static void udl_encoder_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
}
static void
udl_encoder_dpms(struct drm_encoder *encoder, int mode)
{
}
static const struct drm_encoder_helper_funcs udl_helper_funcs = {
.dpms = udl_encoder_dpms,
.prepare = udl_encoder_prepare,
.mode_set = udl_encoder_mode_set,
.commit = udl_encoder_commit,
.disable = udl_encoder_disable,
};
static const struct drm_encoder_funcs udl_enc_funcs = {
.destroy = udl_enc_destroy,
};
struct drm_encoder *udl_encoder_init(struct drm_device *dev)
{
struct drm_encoder *encoder;
encoder = kzalloc(sizeof(struct drm_encoder), GFP_KERNEL);
if (!encoder)
return NULL;
drm_encoder_init(dev, encoder, &udl_enc_funcs, DRM_MODE_ENCODER_TMDS,
NULL);
drm_encoder_helper_add(encoder, &udl_helper_funcs);
encoder->possible_crtcs = 1;
return encoder;
}

Просмотреть файл

@ -9,12 +9,16 @@
*/
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_vblank.h>
#include "udl_drv.h"
#define UDL_COLOR_DEPTH_16BPP 0
/*
* All DisplayLink bulk operations start with 0xAF, followed by specific code
* All operations are written to buffers which then later get sent to device
@ -277,48 +281,44 @@ static void udl_crtc_dpms(struct drm_crtc *crtc, int mode)
}
#if 0
static int
udl_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
int x, int y, enum mode_set_atomic state)
/*
* Simple display pipeline
*/
static const uint32_t udl_simple_display_pipe_formats[] = {
DRM_FORMAT_RGB565,
DRM_FORMAT_XRGB8888,
};
static enum drm_mode_status
udl_simple_display_pipe_mode_valid(struct drm_simple_display_pipe *pipe,
const struct drm_display_mode *mode)
{
return 0;
return MODE_OK;
}
static int
udl_pipe_set_base(struct drm_crtc *crtc, int x, int y,
struct drm_framebuffer *old_fb)
{
return 0;
}
#endif
static int udl_crtc_mode_set(struct drm_crtc *crtc,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode,
int x, int y,
struct drm_framebuffer *old_fb)
static void
udl_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe,
struct drm_crtc_state *crtc_state,
struct drm_plane_state *plane_state)
{
struct drm_crtc *crtc = &pipe->crtc;
struct drm_device *dev = crtc->dev;
struct drm_framebuffer *fb = crtc->primary->fb;
struct drm_framebuffer *fb = plane_state->fb;
struct udl_device *udl = dev->dev_private;
struct drm_display_mode *mode = &crtc_state->mode;
char *buf;
char *wrptr;
int color_depth = 0;
int color_depth = UDL_COLOR_DEPTH_16BPP;
udl->crtc = crtc;
crtc_state->no_vblank = true;
buf = (char *)udl->mode_buf;
/* for now we just clip 24 -> 16 - if we fix that fix this */
/*if (crtc->fb->bits_per_pixel != 16)
color_depth = 1; */
/* This first section has to do with setting the base address on the
* controller * associated with the display. There are 2 base
* pointers, currently, we only * use the 16 bpp segment.
*/
* controller associated with the display. There are 2 base
* pointers, currently, we only use the 16 bpp segment.
*/
wrptr = udl_vidreg_lock(buf);
wrptr = udl_set_color_depth(wrptr, color_depth);
/* set base for 16bpp segment to 0 */
@ -326,7 +326,7 @@ static int udl_crtc_mode_set(struct drm_crtc *crtc,
/* set base for 8bpp segment to end of fb */
wrptr = udl_set_base8bpp(wrptr, 2 * mode->vdisplay * mode->hdisplay);
wrptr = udl_set_vid_cmds(wrptr, adjusted_mode);
wrptr = udl_set_vid_cmds(wrptr, mode);
wrptr = udl_set_blank(wrptr, DRM_MODE_DPMS_ON);
wrptr = udl_vidreg_unlock(wrptr);
@ -337,92 +337,68 @@ static int udl_crtc_mode_set(struct drm_crtc *crtc,
spin_unlock(&udl->active_fb_16_lock);
udl->mode_buf_len = wrptr - buf;
/* damage all of it */
udl_handle_damage(fb, 0, 0, fb->width, fb->height);
udl_crtc_dpms(&pipe->crtc, DRM_MODE_DPMS_ON);
}
static void
udl_simple_display_pipe_disable(struct drm_simple_display_pipe *pipe)
{
udl_crtc_dpms(&pipe->crtc, DRM_MODE_DPMS_OFF);
}
static int
udl_simple_display_pipe_check(struct drm_simple_display_pipe *pipe,
struct drm_plane_state *plane_state,
struct drm_crtc_state *crtc_state)
{
return 0;
}
static void udl_crtc_disable(struct drm_crtc *crtc)
static void
udl_simple_display_pipe_update(struct drm_simple_display_pipe *pipe,
struct drm_plane_state *old_plane_state)
{
udl_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
}
static void udl_crtc_destroy(struct drm_crtc *crtc)
{
drm_crtc_cleanup(crtc);
kfree(crtc);
}
static int udl_crtc_page_flip(struct drm_crtc *crtc,
struct drm_framebuffer *fb,
struct drm_pending_vblank_event *event,
uint32_t page_flip_flags,
struct drm_modeset_acquire_ctx *ctx)
{
struct drm_device *dev = crtc->dev;
struct drm_device *dev = pipe->crtc.dev;
struct udl_device *udl = dev->dev_private;
struct drm_framebuffer *fb = pipe->plane.state->fb;
spin_lock(&udl->active_fb_16_lock);
udl->active_fb_16 = fb;
spin_unlock(&udl->active_fb_16_lock);
if (!fb)
return;
udl_handle_damage(fb, 0, 0, fb->width, fb->height);
spin_lock_irq(&dev->event_lock);
if (event)
drm_crtc_send_vblank_event(crtc, event);
spin_unlock_irq(&dev->event_lock);
crtc->primary->fb = fb;
return 0;
}
static void udl_crtc_prepare(struct drm_crtc *crtc)
{
}
static void udl_crtc_commit(struct drm_crtc *crtc)
{
udl_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
}
static const struct drm_crtc_helper_funcs udl_helper_funcs = {
.dpms = udl_crtc_dpms,
.mode_set = udl_crtc_mode_set,
.prepare = udl_crtc_prepare,
.commit = udl_crtc_commit,
.disable = udl_crtc_disable,
static const
struct drm_simple_display_pipe_funcs udl_simple_display_pipe_funcs = {
.mode_valid = udl_simple_display_pipe_mode_valid,
.enable = udl_simple_display_pipe_enable,
.disable = udl_simple_display_pipe_disable,
.check = udl_simple_display_pipe_check,
.update = udl_simple_display_pipe_update,
.prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb,
};
static const struct drm_crtc_funcs udl_crtc_funcs = {
.set_config = drm_crtc_helper_set_config,
.destroy = udl_crtc_destroy,
.page_flip = udl_crtc_page_flip,
};
static int udl_crtc_init(struct drm_device *dev)
{
struct drm_crtc *crtc;
crtc = kzalloc(sizeof(struct drm_crtc) + sizeof(struct drm_connector *), GFP_KERNEL);
if (crtc == NULL)
return -ENOMEM;
drm_crtc_init(dev, crtc, &udl_crtc_funcs);
drm_crtc_helper_add(crtc, &udl_helper_funcs);
return 0;
}
/*
* Modesetting
*/
static const struct drm_mode_config_funcs udl_mode_funcs = {
.fb_create = udl_fb_user_fb_create,
.atomic_check = drm_atomic_helper_check,
.atomic_commit = drm_atomic_helper_commit,
};
int udl_modeset_init(struct drm_device *dev)
{
size_t format_count = ARRAY_SIZE(udl_simple_display_pipe_formats);
struct udl_device *udl = dev->dev_private;
struct drm_connector *connector;
struct drm_encoder *encoder;
int ret;
drm_mode_config_init(dev);
@ -444,10 +420,16 @@ int udl_modeset_init(struct drm_device *dev)
goto err_drm_mode_config_cleanup;
}
udl_crtc_init(dev);
format_count = ARRAY_SIZE(udl_simple_display_pipe_formats);
encoder = udl_encoder_init(dev);
drm_connector_attach_encoder(connector, encoder);
ret = drm_simple_display_pipe_init(dev, &udl->display_pipe,
&udl_simple_display_pipe_funcs,
udl_simple_display_pipe_formats,
format_count, NULL, connector);
if (ret)
goto err_drm_mode_config_cleanup;
drm_mode_config_reset(dev);
return 0;
@ -459,12 +441,14 @@ err_drm_mode_config_cleanup:
void udl_modeset_restore(struct drm_device *dev)
{
struct udl_device *udl = dev->dev_private;
struct drm_framebuffer *fb;
struct drm_crtc *crtc = &udl->display_pipe.crtc;
struct drm_plane *primary = &udl->display_pipe.plane;
struct drm_framebuffer *fb = primary->fb;
if (!udl->crtc || !udl->crtc->primary->fb)
if (!fb)
return;
udl_crtc_commit(udl->crtc);
fb = udl->crtc->primary->fb;
udl_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
udl_handle_damage(fb, 0, 0, fb->width, fb->height);
}