Commit e240cc76 authored by Daniel Vetter's avatar Daniel Vetter
Browse files

Merge tag 'imx-drm-next-2021-01-04' of git://git.pengutronix.de/git/pza/linux into drm-next



drm/imx: fixes and drm managed resources

- Reduce stack usage in ipu-di.
- Fix imx-ldb for compile tests.
- Make drm encoder control functions optional.
- Add drm managed variants drmm_encoder_alloc(),
  drmm_simple_encoder_alloc(), drmm_universal_plane_alloc(), and
  drmm_crtc_alloc_with_planes() for drm_encoder_init(),
  drm_simple_encoder_init(), drm_universal_plane_init(), and
  drm_crtc_init_with_planes(), respectively.
- Update imx-drm to use the new functions for drm managed resource
  allocation, moving initialization from bind to probe where possible.
- Fix imx-tve clock provider leak.

Signed-off-by: default avatarDaniel Vetter <daniel.vetter@intel.com>
[danvet: Fix conflict between doc changes by both Philipp and Simon
Ser, see 9999587b ("drm: rework description of primary and cursor
planes")]
From: Philipp Zabel <p.zabel@pengutronix.de>
Link: https://patchwork.freedesktop.org/patch/msgid/c745fc1596898932c9454fd2979297b4242566a2.camel@pengutronix.de
parents 5beed15e 16da8e9a
Loading
Loading
Loading
Loading
+100 −31
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@
#include <drm/drm_crtc.h>
#include <drm/drm_edid.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_managed.h>
#include <drm/drm_modeset_lock.h>
#include <drm/drm_atomic.h>
#include <drm/drm_auth.h>
@@ -240,33 +241,12 @@ struct dma_fence *drm_crtc_create_fence(struct drm_crtc *crtc)
 * 		Nearest Neighbor scaling filter
 */

/**
 * drm_crtc_init_with_planes - Initialise a new CRTC object with
 *    specified primary and cursor planes.
 * @dev: DRM device
 * @crtc: CRTC object to init
 * @primary: Primary plane for CRTC
 * @cursor: Cursor plane for CRTC
 * @funcs: callbacks for the new CRTC
 * @name: printf style format string for the CRTC name, or NULL for default name
 *
 * Inits a new object created as base part of a driver crtc object. Drivers
 * should use this function instead of drm_crtc_init(), which is only provided
 * for backwards compatibility with drivers which do not yet support universal
 * planes). For really simple hardware which has only 1 plane look at
 * drm_simple_display_pipe_init() instead.
 *
 * The @primary and @cursor planes are only relevant for legacy uAPI, see
 * &drm_crtc.primary and &drm_crtc.cursor.
 *
 * Returns:
 * Zero on success, error code on failure.
 */
int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
__printf(6, 0)
static int __drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
				       struct drm_plane *primary,
				       struct drm_plane *cursor,
				       const struct drm_crtc_funcs *funcs,
			      const char *name, ...)
				       const char *name, va_list ap)
{
	struct drm_mode_config *config = &dev->mode_config;
	int ret;
@@ -294,11 +274,7 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
		return ret;

	if (name) {
		va_list ap;

		va_start(ap, name);
		crtc->name = kvasprintf(GFP_KERNEL, name, ap);
		va_end(ap);
	} else {
		crtc->name = kasprintf(GFP_KERNEL, "crtc-%d",
				       drm_num_crtcs(dev));
@@ -342,8 +318,101 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,

	return 0;
}

/**
 * drm_crtc_init_with_planes - Initialise a new CRTC object with
 *    specified primary and cursor planes.
 * @dev: DRM device
 * @crtc: CRTC object to init
 * @primary: Primary plane for CRTC
 * @cursor: Cursor plane for CRTC
 * @funcs: callbacks for the new CRTC
 * @name: printf style format string for the CRTC name, or NULL for default name
 *
 * Inits a new object created as base part of a driver crtc object. Drivers
 * should use this function instead of drm_crtc_init(), which is only provided
 * for backwards compatibility with drivers which do not yet support universal
 * planes). For really simple hardware which has only 1 plane look at
 * drm_simple_display_pipe_init() instead.
 * The &drm_crtc_funcs.destroy hook should call drm_crtc_cleanup() and kfree()
 * the crtc structure. The crtc structure should not be allocated with
 * devm_kzalloc().
 *
 * The @primary and @cursor planes are only relevant for legacy uAPI, see
 * &drm_crtc.primary and &drm_crtc.cursor.
 *
 * Note: consider using drmm_crtc_alloc_with_planes() instead of
 * drm_crtc_init_with_planes() to let the DRM managed resource infrastructure
 * take care of cleanup and deallocation.
 *
 * Returns:
 * Zero on success, error code on failure.
 */
int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
			      struct drm_plane *primary,
			      struct drm_plane *cursor,
			      const struct drm_crtc_funcs *funcs,
			      const char *name, ...)
{
	va_list ap;
	int ret;

	WARN_ON(!funcs->destroy);

	va_start(ap, name);
	ret = __drm_crtc_init_with_planes(dev, crtc, primary, cursor, funcs,
					  name, ap);
	va_end(ap);

	return ret;
}
EXPORT_SYMBOL(drm_crtc_init_with_planes);

static void drmm_crtc_alloc_with_planes_cleanup(struct drm_device *dev,
						void *ptr)
{
	struct drm_crtc *crtc = ptr;

	drm_crtc_cleanup(crtc);
}

void *__drmm_crtc_alloc_with_planes(struct drm_device *dev,
				    size_t size, size_t offset,
				    struct drm_plane *primary,
				    struct drm_plane *cursor,
				    const struct drm_crtc_funcs *funcs,
				    const char *name, ...)
{
	void *container;
	struct drm_crtc *crtc;
	va_list ap;
	int ret;

	if (WARN_ON(!funcs || funcs->destroy))
		return ERR_PTR(-EINVAL);

	container = drmm_kzalloc(dev, size, GFP_KERNEL);
	if (!container)
		return ERR_PTR(-ENOMEM);

	crtc = container + offset;

	va_start(ap, name);
	ret = __drm_crtc_init_with_planes(dev, crtc, primary, cursor, funcs,
					  name, ap);
	va_end(ap);
	if (ret)
		return ERR_PTR(ret);

	ret = drmm_add_action_or_reset(dev, drmm_crtc_alloc_with_planes_cleanup,
				       crtc);
	if (ret)
		return ERR_PTR(ret);

	return container;
}
EXPORT_SYMBOL(__drmm_crtc_alloc_with_planes);

/**
 * drm_crtc_cleanup - Clean up the core crtc usage
 * @crtc: CRTC to cleanup
+88 −25
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@
#include <drm/drm_device.h>
#include <drm/drm_drv.h>
#include <drm/drm_encoder.h>
#include <drm/drm_managed.h>

#include "drm_crtc_internal.h"

@@ -72,7 +73,7 @@ int drm_encoder_register_all(struct drm_device *dev)
	int ret = 0;

	drm_for_each_encoder(encoder, dev) {
		if (encoder->funcs->late_register)
		if (encoder->funcs && encoder->funcs->late_register)
			ret = encoder->funcs->late_register(encoder);
		if (ret)
			return ret;
@@ -86,30 +87,16 @@ void drm_encoder_unregister_all(struct drm_device *dev)
	struct drm_encoder *encoder;

	drm_for_each_encoder(encoder, dev) {
		if (encoder->funcs->early_unregister)
		if (encoder->funcs && encoder->funcs->early_unregister)
			encoder->funcs->early_unregister(encoder);
	}
}

/**
 * drm_encoder_init - Init a preallocated encoder
 * @dev: drm device
 * @encoder: the encoder to init
 * @funcs: callbacks for this encoder
 * @encoder_type: user visible type of the encoder
 * @name: printf style format string for the encoder name, or NULL for default name
 *
 * Initialises a preallocated encoder. Encoder should be subclassed as part of
 * driver encoder objects. At driver unload time drm_encoder_cleanup() should be
 * called from the driver's &drm_encoder_funcs.destroy hook.
 *
 * Returns:
 * Zero on success, error code on failure.
 */
int drm_encoder_init(struct drm_device *dev,
__printf(5, 0)
static int __drm_encoder_init(struct drm_device *dev,
			      struct drm_encoder *encoder,
			      const struct drm_encoder_funcs *funcs,
		     int encoder_type, const char *name, ...)
			      int encoder_type, const char *name, va_list ap)
{
	int ret;

@@ -125,11 +112,7 @@ int drm_encoder_init(struct drm_device *dev,
	encoder->encoder_type = encoder_type;
	encoder->funcs = funcs;
	if (name) {
		va_list ap;

		va_start(ap, name);
		encoder->name = kvasprintf(GFP_KERNEL, name, ap);
		va_end(ap);
	} else {
		encoder->name = kasprintf(GFP_KERNEL, "%s-%d",
					  drm_encoder_enum_list[encoder_type].name,
@@ -150,6 +133,44 @@ int drm_encoder_init(struct drm_device *dev,

	return ret;
}

/**
 * drm_encoder_init - Init a preallocated encoder
 * @dev: drm device
 * @encoder: the encoder to init
 * @funcs: callbacks for this encoder
 * @encoder_type: user visible type of the encoder
 * @name: printf style format string for the encoder name, or NULL for default name
 *
 * Initializes a preallocated encoder. Encoder should be subclassed as part of
 * driver encoder objects. At driver unload time the driver's
 * &drm_encoder_funcs.destroy hook should call drm_encoder_cleanup() and kfree()
 * the encoder structure. The encoder structure should not be allocated with
 * devm_kzalloc().
 *
 * Note: consider using drmm_encoder_alloc() instead of drm_encoder_init() to
 * let the DRM managed resource infrastructure take care of cleanup and
 * deallocation.
 *
 * Returns:
 * Zero on success, error code on failure.
 */
int drm_encoder_init(struct drm_device *dev,
		     struct drm_encoder *encoder,
		     const struct drm_encoder_funcs *funcs,
		     int encoder_type, const char *name, ...)
{
	va_list ap;
	int ret;

	WARN_ON(!funcs->destroy);

	va_start(ap, name);
	ret = __drm_encoder_init(dev, encoder, funcs, encoder_type, name, ap);
	va_end(ap);

	return ret;
}
EXPORT_SYMBOL(drm_encoder_init);

/**
@@ -181,6 +202,48 @@ void drm_encoder_cleanup(struct drm_encoder *encoder)
}
EXPORT_SYMBOL(drm_encoder_cleanup);

static void drmm_encoder_alloc_release(struct drm_device *dev, void *ptr)
{
	struct drm_encoder *encoder = ptr;

	if (WARN_ON(!encoder->dev))
		return;

	drm_encoder_cleanup(encoder);
}

void *__drmm_encoder_alloc(struct drm_device *dev, size_t size, size_t offset,
			   const struct drm_encoder_funcs *funcs,
			   int encoder_type, const char *name, ...)
{
	void *container;
	struct drm_encoder *encoder;
	va_list ap;
	int ret;

	if (WARN_ON(funcs && funcs->destroy))
		return ERR_PTR(-EINVAL);

	container = drmm_kzalloc(dev, size, GFP_KERNEL);
	if (!container)
		return ERR_PTR(-EINVAL);

	encoder = container + offset;

	va_start(ap, name);
	ret = __drm_encoder_init(dev, encoder, funcs, encoder_type, name, ap);
	va_end(ap);
	if (ret)
		return ERR_PTR(ret);

	ret = drmm_add_action_or_reset(dev, drmm_encoder_alloc_release, encoder);
	if (ret)
		return ERR_PTR(ret);

	return container;
}
EXPORT_SYMBOL(__drmm_encoder_alloc);

static struct drm_crtc *drm_encoder_get_crtc(struct drm_encoder *encoder)
{
	struct drm_connector *connector;
+1 −1
Original line number Diff line number Diff line
@@ -195,7 +195,7 @@ void drm_mode_config_reset(struct drm_device *dev)
			crtc->funcs->reset(crtc);

	drm_for_each_encoder(encoder, dev)
		if (encoder->funcs->reset)
		if (encoder->funcs && encoder->funcs->reset)
			encoder->funcs->reset(encoder);

	drm_connector_list_iter_begin(dev, &conn_iter);
+105 −29
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@
#include <drm/drm_file.h>
#include <drm/drm_crtc.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_managed.h>
#include <drm/drm_vblank.h>

#include "drm_crtc_internal.h"
@@ -154,31 +155,16 @@ static int create_in_format_blob(struct drm_device *dev, struct drm_plane *plane
	return 0;
}

/**
 * drm_universal_plane_init - Initialize a new universal plane object
 * @dev: DRM device
 * @plane: plane object to init
 * @possible_crtcs: bitmask of possible CRTCs
 * @funcs: callbacks for the new plane
 * @formats: array of supported formats (DRM_FORMAT\_\*)
 * @format_count: number of elements in @formats
 * @format_modifiers: array of struct drm_format modifiers terminated by
 *                    DRM_FORMAT_MOD_INVALID
 * @type: type of plane (overlay, primary, cursor)
 * @name: printf style format string for the plane name, or NULL for default name
 *
 * Initializes a plane object of type @type.
 *
 * Returns:
 * Zero on success, error code on failure.
 */
int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
__printf(9, 0)
static int __drm_universal_plane_init(struct drm_device *dev,
				      struct drm_plane *plane,
				      uint32_t possible_crtcs,
				      const struct drm_plane_funcs *funcs,
			     const uint32_t *formats, unsigned int format_count,
				      const uint32_t *formats,
				      unsigned int format_count,
				      const uint64_t *format_modifiers,
				      enum drm_plane_type type,
			     const char *name, ...)
				      const char *name, va_list ap)
{
	struct drm_mode_config *config = &dev->mode_config;
	unsigned int format_modifier_count = 0;
@@ -239,11 +225,7 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
	}

	if (name) {
		va_list ap;

		va_start(ap, name);
		plane->name = kvasprintf(GFP_KERNEL, name, ap);
		va_end(ap);
	} else {
		plane->name = kasprintf(GFP_KERNEL, "plane-%d",
					drm_num_planes(dev));
@@ -288,8 +270,102 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,

	return 0;
}

/**
 * drm_universal_plane_init - Initialize a new universal plane object
 * @dev: DRM device
 * @plane: plane object to init
 * @possible_crtcs: bitmask of possible CRTCs
 * @funcs: callbacks for the new plane
 * @formats: array of supported formats (DRM_FORMAT\_\*)
 * @format_count: number of elements in @formats
 * @format_modifiers: array of struct drm_format modifiers terminated by
 *                    DRM_FORMAT_MOD_INVALID
 * @type: type of plane (overlay, primary, cursor)
 * @name: printf style format string for the plane name, or NULL for default name
 *
 * Initializes a plane object of type @type. The &drm_plane_funcs.destroy hook
 * should call drm_plane_cleanup() and kfree() the plane structure. The plane
 * structure should not be allocated with devm_kzalloc().
 *
 * Note: consider using drmm_universal_plane_alloc() instead of
 * drm_universal_plane_init() to let the DRM managed resource infrastructure
 * take care of cleanup and deallocation.
 *
 * Returns:
 * Zero on success, error code on failure.
 */
int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
			     uint32_t possible_crtcs,
			     const struct drm_plane_funcs *funcs,
			     const uint32_t *formats, unsigned int format_count,
			     const uint64_t *format_modifiers,
			     enum drm_plane_type type,
			     const char *name, ...)
{
	va_list ap;
	int ret;

	WARN_ON(!funcs->destroy);

	va_start(ap, name);
	ret = __drm_universal_plane_init(dev, plane, possible_crtcs, funcs,
					 formats, format_count, format_modifiers,
					 type, name, ap);
	va_end(ap);
	return ret;
}
EXPORT_SYMBOL(drm_universal_plane_init);

static void drmm_universal_plane_alloc_release(struct drm_device *dev, void *ptr)
{
	struct drm_plane *plane = ptr;

	if (WARN_ON(!plane->dev))
		return;

	drm_plane_cleanup(plane);
}

void *__drmm_universal_plane_alloc(struct drm_device *dev, size_t size,
				   size_t offset, uint32_t possible_crtcs,
				   const struct drm_plane_funcs *funcs,
				   const uint32_t *formats, unsigned int format_count,
				   const uint64_t *format_modifiers,
				   enum drm_plane_type type,
				   const char *name, ...)
{
	void *container;
	struct drm_plane *plane;
	va_list ap;
	int ret;

	if (WARN_ON(!funcs || funcs->destroy))
		return ERR_PTR(-EINVAL);

	container = drmm_kzalloc(dev, size, GFP_KERNEL);
	if (!container)
		return ERR_PTR(-ENOMEM);

	plane = container + offset;

	va_start(ap, name);
	ret = __drm_universal_plane_init(dev, plane, possible_crtcs, funcs,
					 formats, format_count, format_modifiers,
					 type, name, ap);
	va_end(ap);
	if (ret)
		return ERR_PTR(ret);

	ret = drmm_add_action_or_reset(dev, drmm_universal_plane_alloc_release,
				       plane);
	if (ret)
		return ERR_PTR(ret);

	return container;
}
EXPORT_SYMBOL(__drmm_universal_plane_alloc);

int drm_plane_register_all(struct drm_device *dev)
{
	unsigned int num_planes = 0;
+12 −2
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_managed.h>
#include <drm/drm_plane_helper.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_simple_kms_helper.h>
@@ -55,8 +56,9 @@ static const struct drm_encoder_funcs drm_simple_encoder_funcs_cleanup = {
 * stored in the device structure. Free the encoder's memory as part of
 * the device release function.
 *
 * FIXME: Later improvements to DRM's resource management may allow for
 *        an automated kfree() of the encoder's memory.
 * Note: consider using drmm_simple_encoder_alloc() instead of
 * drm_simple_encoder_init() to let the DRM managed resource infrastructure
 * take care of cleanup and deallocation.
 *
 * Returns:
 * Zero on success, error code on failure.
@@ -71,6 +73,14 @@ int drm_simple_encoder_init(struct drm_device *dev,
}
EXPORT_SYMBOL(drm_simple_encoder_init);

void *__drmm_simple_encoder_alloc(struct drm_device *dev, size_t size,
				  size_t offset, int encoder_type)
{
	return __drmm_encoder_alloc(dev, size, offset, NULL, encoder_type,
				    NULL);
}
EXPORT_SYMBOL(__drmm_simple_encoder_alloc);

static enum drm_mode_status
drm_simple_kms_crtc_mode_valid(struct drm_crtc *crtc,
			       const struct drm_display_mode *mode)
Loading