All of lore.kernel.org
 help / color / mirror / Atom feed
From: Daniel Vetter <daniel@ffwll.ch>
To: "Noralf Trønnes" <noralf@tronnes.org>
Cc: thomas.petazzoni@free-electrons.com, dri-devel@lists.freedesktop.org
Subject: Re: [RFC v2 3/8] drm: Add helper for simple kms drivers
Date: Wed, 13 Apr 2016 13:05:53 +0200	[thread overview]
Message-ID: <20160413110553.GY2510@phenom.ffwll.local> (raw)
In-Reply-To: <1460135110-24121-4-git-send-email-noralf@tronnes.org>

On Fri, Apr 08, 2016 at 07:05:05PM +0200, Noralf Trønnes wrote:
> Provides helper functions for drivers that have a simple display
> pipeline. Plane, crtc and encoder are collapsed into one entity.
> 
> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>

Looks good. A few comments below, but the big thing is adding kerneldoc
and cross-referencing it (e.g. from drm_panel to drm_panel_connector).
-Daniel

> ---
>  drivers/gpu/drm/Kconfig                 |   7 +
>  drivers/gpu/drm/Makefile                |   1 +
>  drivers/gpu/drm/drm_simple_kms_helper.c | 262 ++++++++++++++++++++++++++++++++
>  include/drm/drm_simple_kms_helper.h     |  44 ++++++
>  4 files changed, 314 insertions(+)
>  create mode 100644 drivers/gpu/drm/drm_simple_kms_helper.c
>  create mode 100644 include/drm/drm_simple_kms_helper.h
> 
> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> index 8ae7ab6..cb62cd9 100644
> --- a/drivers/gpu/drm/Kconfig
> +++ b/drivers/gpu/drm/Kconfig
> @@ -31,6 +31,13 @@ config DRM_KMS_HELPER
>  	help
>  	  CRTC helpers for KMS drivers.
>  
> +config DRM_SIMPLE_KMS_HELPER
> +	tristate
> +	depends on DRM
> +	select DRM_KMS_HELPER
> +	help
> +	  Helpers for very simple KMS drivers.
> +
>  config DRM_KMS_FB_HELPER
>  	bool
>  	depends on DRM_KMS_HELPER
> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> index 61766de..ea9bf59 100644
> --- a/drivers/gpu/drm/Makefile
> +++ b/drivers/gpu/drm/Makefile
> @@ -28,6 +28,7 @@ drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o
>  drm_kms_helper-$(CONFIG_DRM_KMS_CMA_HELPER) += drm_fb_cma_helper.o
>  
>  obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o
> +obj-$(CONFIG_DRM_SIMPLE_KMS_HELPER) += drm_simple_kms_helper.o
>  
>  CFLAGS_drm_trace_points.o := -I$(src)
>  
> diff --git a/drivers/gpu/drm/drm_simple_kms_helper.c b/drivers/gpu/drm/drm_simple_kms_helper.c
> new file mode 100644
> index 0000000..e193f7db
> --- /dev/null
> +++ b/drivers/gpu/drm/drm_simple_kms_helper.c
> @@ -0,0 +1,262 @@
> +/*
> + * Copyright (C) 2016 Noralf Trønnes
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + */
> +
> +#include <drm/drmP.h>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_crtc_helper.h>
> +#include <drm/drm_panel.h>
> +#include <drm/drm_plane_helper.h>
> +#include <drm/drm_simple_kms_helper.h>
> +#include <linux/slab.h>
> +
> +struct drm_simple_kms_connector {
> +	struct drm_connector base;
> +	struct drm_panel *panel;
> +};
> +
> +static inline struct drm_simple_kms_connector *
> +to_simple_connector(struct drm_connector *connector)
> +{
> +	return container_of(connector, struct drm_simple_kms_connector, base);
> +}
> +
> +static int drm_simple_kms_connector_get_modes(struct drm_connector *connector)
> +{
> +	return drm_panel_get_modes(to_simple_connector(connector)->panel);
> +}
> +
> +static struct drm_encoder *
> +drm_simple_kms_connector_best_encoder(struct drm_connector *connector)
> +{
> +	return drm_encoder_find(connector->dev, connector->encoder_ids[0]);
> +}

I think this would be useful for atomic drivers in general. I even thought
we have it already somewhere ...

> +
> +static const struct drm_connector_helper_funcs drm_simple_kms_connector_helper_funcs = {
> +	.get_modes = drm_simple_kms_connector_get_modes,
> +	.best_encoder = drm_simple_kms_connector_best_encoder,
> +};
> +
> +static enum drm_connector_status
> +drm_simple_kms_connector_detect(struct drm_connector *connector, bool force)
> +{
> +	if (drm_device_is_unplugged(connector->dev))
> +		return connector_status_disconnected;
> +
> +	return connector->status;
> +}
> +
> +static void drm_simple_kms_connector_destroy(struct drm_connector *connector)
> +{
> +	struct drm_simple_kms_connector *panel_connector;
> +
> +	panel_connector = to_simple_connector(connector);
> +	drm_panel_detach(panel_connector->panel);
> +	drm_panel_remove(panel_connector->panel);
> +	drm_connector_unregister(connector);
> +	drm_connector_cleanup(connector);
> +	kfree(panel_connector);
> +}
> +
> +static const struct drm_connector_funcs drm_simple_kms_connector_funcs = {
> +	.dpms = drm_atomic_helper_connector_dpms,
> +	.reset = drm_atomic_helper_connector_reset,
> +	.detect = drm_simple_kms_connector_detect,
> +	.fill_modes = drm_helper_probe_single_connector_modes,
> +	.destroy = drm_simple_kms_connector_destroy,
> +	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
> +	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> +};

drm_simple_kms_panel_connector is toooooooooooo long ;-) What about just
drm_panel_connector instead? Also not entirely sure whether this is best
placed here, or better in drm_panel.c, or maybe even in a new
drm_panel_helper.c.

Imo drm_panel_connector and drm_simple_display_pipe should work as
orthogonal helpers.

Or 3rd option: You just expose the above helpers for detect/get_modes
only.

> +
> +/**
> + * drm_simple_kms_panel_connector_create - Create simple connector for panel
> + * @dev: DRM device
> + * @panel: DRM panel
> + * @connector_type: user visible type of the connector
> + *
> + * Creates a simple connector for a panel.
> + * The panel needs to provide a get_modes() function.
> + *
> + * Returns:
> + * Pointer to new connector or ERR_PTR on failure.
> + */
> +struct drm_connector *
> +drm_simple_kms_panel_connector_create(struct drm_device *dev,
> +				      struct drm_panel *panel,
> +				      int connector_type)
> +{
> +	struct drm_simple_kms_connector *panel_connector;
> +	struct drm_connector *connector;
> +	int ret;
> +
> +	panel_connector = kzalloc(sizeof(*panel_connector), GFP_KERNEL);
> +	if (!panel_connector)
> +		return ERR_PTR(-ENOMEM);
> +
> +	panel_connector->panel = panel;
> +	connector = &panel_connector->base;
> +	drm_connector_helper_add(connector, &drm_simple_kms_connector_helper_funcs);
> +	ret = drm_connector_init(dev, connector, &drm_simple_kms_connector_funcs,
> +				 connector_type);
> +	if (ret) {
> +		kfree(panel_connector);
> +		return ERR_PTR(ret);
> +	}
> +
> +	connector->status = connector_status_connected;
> +	drm_panel_init(panel);
> +	drm_panel_add(panel);
> +	drm_panel_attach(panel, connector);
> +
> +	return connector;
> +}
> +EXPORT_SYMBOL(drm_simple_kms_panel_connector_create);
> +
> +static void drm_simple_kms_encoder_disable(struct drm_encoder *encoder)
> +{
> +}
> +
> +static void drm_simple_kms_encoder_enable(struct drm_encoder *encoder)
> +{
> +}
> +
> +static int drm_simple_kms_encoder_atomic_check(struct drm_encoder *encoder,
> +					struct drm_crtc_state *crtc_state,
> +					struct drm_connector_state *conn_state)
> +{
> +	return 0;
> +}

Above dummy functions shouldn't be necessary.

> +
> +static const struct drm_encoder_helper_funcs drm_simple_kms_encoder_helper_funcs = {
> +	.disable = drm_simple_kms_encoder_disable,
> +	.enable = drm_simple_kms_encoder_enable,
> +	.atomic_check = drm_simple_kms_encoder_atomic_check,
> +};
> +
> +static const struct drm_encoder_funcs drm_simple_kms_encoder_funcs = {
> +	.destroy = drm_encoder_cleanup,
> +};
> +
> +static void drm_simple_kms_crtc_enable(struct drm_crtc *crtc)
> +{
> +	struct drm_simple_display_pipe *pipe;
> +
> +	pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
> +	if (!pipe->funcs || !pipe->funcs->enable)
> +		return;
> +
> +	pipe->funcs->enable(pipe, crtc->state);
> +}
> +
> +static void drm_simple_kms_crtc_disable(struct drm_crtc *crtc)
> +{
> +	struct drm_simple_display_pipe *pipe;
> +
> +	pipe = container_of(crtc, struct drm_simple_display_pipe, crtc);
> +	if (!pipe->funcs || !pipe->funcs->disable)
> +		return;
> +
> +	pipe->funcs->disable(pipe);
> +}
> +
> +static const struct drm_crtc_helper_funcs drm_simple_kms_crtc_helper_funcs = {
> +	.disable = drm_simple_kms_crtc_disable,
> +	.enable = drm_simple_kms_crtc_enable,
> +};
> +
> +static const struct drm_crtc_funcs drm_simple_kms_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 void drm_simple_kms_plane_atomic_update(struct drm_plane *plane,
> +					struct drm_plane_state *old_state)
> +{
> +	struct drm_simple_display_pipe *pipe;
> +
> +	pipe = container_of(plane, struct drm_simple_display_pipe, plane);
> +	if (!pipe->funcs || !pipe->funcs->plane_update)
> +		return;
> +
> +	pipe->funcs->plane_update(pipe, old_state);
> +}
> +
> +static const struct drm_plane_helper_funcs drm_simple_kms_plane_helper_funcs = {
> +	.atomic_update = drm_simple_kms_plane_atomic_update,
> +};
> +
> +static const struct drm_plane_funcs drm_simple_kms_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_simple_display_pipe_init - Initialize a simple display pipe
> + * @dev: DRM device
> + * @pipe: simple display pipe object to initialize
> + * @funcs: callbacks for the display pipe
> + * @formats: array of supported formats (%DRM_FORMAT_*)
> + * @format_count: number of elements in @formats
> + * @connector: connector to attach and register
> + *
> + * Sets up a display pipe which consist of a really simple plane-crtc-encoder
> + * pipe coupled with the provided connector.
> + *
> + * Returns:
> + * Zero on success, error code on failure.
> + */
> +int drm_simple_display_pipe_init(struct drm_device *dev,
> +				 struct drm_simple_display_pipe *pipe,
> +				 struct drm_simple_display_pipe_funcs *funcs,
> +				 const uint32_t *formats, unsigned int format_count,
> +				 struct drm_connector *connector)
> +{
> +	struct drm_encoder *encoder = &pipe->encoder;
> +	struct drm_plane *plane = &pipe->plane;
> +	struct drm_crtc *crtc = &pipe->crtc;
> +	int ret;
> +
> +	pipe->funcs = funcs;
> +
> +	drm_plane_helper_add(plane, &drm_simple_kms_plane_helper_funcs);
> +	ret = drm_universal_plane_init(dev, plane, 0, &drm_simple_kms_plane_funcs,
> +				       formats, format_count,
> +				       DRM_PLANE_TYPE_PRIMARY, NULL);
> +	if (ret)
> +		return ret;
> +
> +	drm_crtc_helper_add(crtc, &drm_simple_kms_crtc_helper_funcs);
> +	ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL,
> +					&drm_simple_kms_crtc_funcs, NULL);
> +	if (ret)
> +		return ret;
> +
> +	encoder->possible_crtcs = 1 << drm_crtc_index(crtc);
> +	drm_encoder_helper_add(encoder, &drm_simple_kms_encoder_helper_funcs);
> +	ret = drm_encoder_init(dev, encoder, &drm_simple_kms_encoder_funcs,
> +			       DRM_MODE_ENCODER_NONE, NULL);
> +	if (ret)
> +		return ret;
> +
> +	ret = drm_mode_connector_attach_encoder(connector, encoder);
> +	if (ret)
> +		return ret;
> +
> +	return drm_connector_register(connector);
> +}
> +EXPORT_SYMBOL(drm_simple_display_pipe_init);
> +
> +MODULE_LICENSE("GPL");
> diff --git a/include/drm/drm_simple_kms_helper.h b/include/drm/drm_simple_kms_helper.h
> new file mode 100644
> index 0000000..0f7461b
> --- /dev/null
> +++ b/include/drm/drm_simple_kms_helper.h
> @@ -0,0 +1,44 @@
> +/*
> + * Copyright (C) 2016 Noralf Trønnes
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + */
> +
> +#ifndef __LINUX_DRM_SIMPLE_KMS_HELPER_H
> +#define __LINUX_DRM_SIMPLE_KMS_HELPER_H
> +
> +struct drm_simple_display_pipe;
> +
> +struct drm_simple_display_pipe_funcs {
> +	void (*enable)(struct drm_simple_display_pipe *pipe,
> +		       struct drm_crtc_state *crtc_state);
> +	void (*disable)(struct drm_simple_display_pipe *pipe);
> +	void (*plane_update)(struct drm_simple_display_pipe *pipe,
> +			     struct drm_plane_state *plane_state);

On 2nd thought maybe we want an atomic_check in here too, with same
parameters *pipe, *crtc_state and *plane_state (so that it's useful for
both plane-only updates and modeset changes).

> +};
> +
> +struct drm_simple_display_pipe {
> +	struct drm_crtc crtc;
> +	struct drm_plane plane;
> +	struct drm_encoder encoder;
> +	struct drm_connector *connector;
> +
> +	struct drm_simple_display_pipe_funcs *funcs;
> +};
> +
> +int drm_simple_display_pipe_init(struct drm_device *dev,
> +				 struct drm_simple_display_pipe *pipe,
> +				 struct drm_simple_display_pipe_funcs *funcs,
> +				 const uint32_t *formats, unsigned int format_count,
> +				 struct drm_connector *connector);
> +struct drm_connector *
> +drm_simple_kms_panel_connector_create(struct drm_device *dev,
> +				      struct drm_panel *panel,
> +				      int connector_type);
> +
> +
> +
> +#endif /* __LINUX_DRM_SIMPLE_KMS_HELPER_H */
> -- 
> 2.2.2
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

  reply	other threads:[~2016-04-13 11:05 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-04-08 17:05 [RFC v2 0/8] drm: Add support for tiny LCD displays Noralf Trønnes
2016-04-08 17:05 ` [RFC v2 1/8] drm/fb-helper: Add fb_deferred_io support Noralf Trønnes
2016-04-13 10:57   ` Daniel Vetter
2016-04-13 11:09   ` Daniel Vetter
2016-04-18 15:15     ` Noralf Trønnes
2016-04-20 11:12       ` Daniel Vetter
2016-04-20 15:22         ` Noralf Trønnes
2016-04-20 22:29       ` Dave Airlie
2016-04-21  6:53         ` Daniel Vetter
2016-04-08 17:05 ` [RFC v2 2/8] drm/fb-cma-helper: " Noralf Trønnes
2016-04-13 11:19   ` Daniel Vetter
2016-04-08 17:05 ` [RFC v2 3/8] drm: Add helper for simple kms drivers Noralf Trønnes
2016-04-13 11:05   ` Daniel Vetter [this message]
2016-05-02 15:55     ` Noralf Trønnes
2016-05-02 20:20       ` Daniel Vetter
2016-04-08 17:05 ` [RFC v2 4/8] drm: Add DRM support for tiny LCD displays Noralf Trønnes
2016-04-08 17:05 ` [RFC v2 5/8] drm/tinydrm: Add lcd register abstraction Noralf Trønnes
2016-04-08 17:05 ` [RFC v2 6/8] drm/tinydrm/lcdreg: Add SPI support Noralf Trønnes
2016-04-08 17:05 ` [RFC v2 7/8] drm/tinydrm: Add mipi-dbi support Noralf Trønnes
2016-04-08 17:05 ` [RFC v2 8/8] drm/tinydrm: Add support for several Adafruit TFT displays Noralf Trønnes
2016-04-13 11:11 ` [RFC v2 0/8] drm: Add support for tiny LCD displays Daniel Vetter

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20160413110553.GY2510@phenom.ffwll.local \
    --to=daniel@ffwll.ch \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=noralf@tronnes.org \
    --cc=thomas.petazzoni@free-electrons.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.