Commit e240cc76 authored by Daniel Vetter's avatar Daniel Vetter

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
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#include <drm/drm_crtc.h> #include <drm/drm_crtc.h>
#include <drm/drm_edid.h> #include <drm/drm_edid.h>
#include <drm/drm_fourcc.h> #include <drm/drm_fourcc.h>
#include <drm/drm_managed.h>
#include <drm/drm_modeset_lock.h> #include <drm/drm_modeset_lock.h>
#include <drm/drm_atomic.h> #include <drm/drm_atomic.h>
#include <drm/drm_auth.h> #include <drm/drm_auth.h>
...@@ -240,33 +241,12 @@ struct dma_fence *drm_crtc_create_fence(struct drm_crtc *crtc) ...@@ -240,33 +241,12 @@ struct dma_fence *drm_crtc_create_fence(struct drm_crtc *crtc)
* Nearest Neighbor scaling filter * Nearest Neighbor scaling filter
*/ */
/** __printf(6, 0)
* drm_crtc_init_with_planes - Initialise a new CRTC object with static int __drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
* specified primary and cursor planes. struct drm_plane *primary,
* @dev: DRM device struct drm_plane *cursor,
* @crtc: CRTC object to init const struct drm_crtc_funcs *funcs,
* @primary: Primary plane for CRTC const char *name, va_list ap)
* @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,
struct drm_plane *primary,
struct drm_plane *cursor,
const struct drm_crtc_funcs *funcs,
const char *name, ...)
{ {
struct drm_mode_config *config = &dev->mode_config; struct drm_mode_config *config = &dev->mode_config;
int ret; int ret;
...@@ -294,11 +274,7 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc, ...@@ -294,11 +274,7 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
return ret; return ret;
if (name) { if (name) {
va_list ap;
va_start(ap, name);
crtc->name = kvasprintf(GFP_KERNEL, name, ap); crtc->name = kvasprintf(GFP_KERNEL, name, ap);
va_end(ap);
} else { } else {
crtc->name = kasprintf(GFP_KERNEL, "crtc-%d", crtc->name = kasprintf(GFP_KERNEL, "crtc-%d",
drm_num_crtcs(dev)); drm_num_crtcs(dev));
...@@ -342,8 +318,101 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc, ...@@ -342,8 +318,101 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
return 0; 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); 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 * drm_crtc_cleanup - Clean up the core crtc usage
* @crtc: CRTC to cleanup * @crtc: CRTC to cleanup
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <drm/drm_device.h> #include <drm/drm_device.h>
#include <drm/drm_drv.h> #include <drm/drm_drv.h>
#include <drm/drm_encoder.h> #include <drm/drm_encoder.h>
#include <drm/drm_managed.h>
#include "drm_crtc_internal.h" #include "drm_crtc_internal.h"
...@@ -72,7 +73,7 @@ int drm_encoder_register_all(struct drm_device *dev) ...@@ -72,7 +73,7 @@ int drm_encoder_register_all(struct drm_device *dev)
int ret = 0; int ret = 0;
drm_for_each_encoder(encoder, dev) { drm_for_each_encoder(encoder, dev) {
if (encoder->funcs->late_register) if (encoder->funcs && encoder->funcs->late_register)
ret = encoder->funcs->late_register(encoder); ret = encoder->funcs->late_register(encoder);
if (ret) if (ret)
return ret; return ret;
...@@ -86,30 +87,16 @@ void drm_encoder_unregister_all(struct drm_device *dev) ...@@ -86,30 +87,16 @@ void drm_encoder_unregister_all(struct drm_device *dev)
struct drm_encoder *encoder; struct drm_encoder *encoder;
drm_for_each_encoder(encoder, dev) { drm_for_each_encoder(encoder, dev) {
if (encoder->funcs->early_unregister) if (encoder->funcs && encoder->funcs->early_unregister)
encoder->funcs->early_unregister(encoder); encoder->funcs->early_unregister(encoder);
} }
} }
/** __printf(5, 0)
* drm_encoder_init - Init a preallocated encoder static int __drm_encoder_init(struct drm_device *dev,
* @dev: drm device struct drm_encoder *encoder,
* @encoder: the encoder to init const struct drm_encoder_funcs *funcs,
* @funcs: callbacks for this encoder int encoder_type, const char *name, va_list ap)
* @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,
struct drm_encoder *encoder,
const struct drm_encoder_funcs *funcs,
int encoder_type, const char *name, ...)
{ {
int ret; int ret;
...@@ -125,11 +112,7 @@ int drm_encoder_init(struct drm_device *dev, ...@@ -125,11 +112,7 @@ int drm_encoder_init(struct drm_device *dev,
encoder->encoder_type = encoder_type; encoder->encoder_type = encoder_type;
encoder->funcs = funcs; encoder->funcs = funcs;
if (name) { if (name) {
va_list ap;
va_start(ap, name);
encoder->name = kvasprintf(GFP_KERNEL, name, ap); encoder->name = kvasprintf(GFP_KERNEL, name, ap);
va_end(ap);
} else { } else {
encoder->name = kasprintf(GFP_KERNEL, "%s-%d", encoder->name = kasprintf(GFP_KERNEL, "%s-%d",
drm_encoder_enum_list[encoder_type].name, drm_encoder_enum_list[encoder_type].name,
...@@ -150,6 +133,44 @@ int drm_encoder_init(struct drm_device *dev, ...@@ -150,6 +133,44 @@ int drm_encoder_init(struct drm_device *dev,
return ret; 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); EXPORT_SYMBOL(drm_encoder_init);
/** /**
...@@ -181,6 +202,48 @@ void drm_encoder_cleanup(struct drm_encoder *encoder) ...@@ -181,6 +202,48 @@ void drm_encoder_cleanup(struct drm_encoder *encoder)
} }
EXPORT_SYMBOL(drm_encoder_cleanup); 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) static struct drm_crtc *drm_encoder_get_crtc(struct drm_encoder *encoder)
{ {
struct drm_connector *connector; struct drm_connector *connector;
......
...@@ -195,7 +195,7 @@ void drm_mode_config_reset(struct drm_device *dev) ...@@ -195,7 +195,7 @@ void drm_mode_config_reset(struct drm_device *dev)
crtc->funcs->reset(crtc); crtc->funcs->reset(crtc);
drm_for_each_encoder(encoder, dev) drm_for_each_encoder(encoder, dev)
if (encoder->funcs->reset) if (encoder->funcs && encoder->funcs->reset)
encoder->funcs->reset(encoder); encoder->funcs->reset(encoder);
drm_connector_list_iter_begin(dev, &conn_iter); drm_connector_list_iter_begin(dev, &conn_iter);
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include <drm/drm_file.h> #include <drm/drm_file.h>
#include <drm/drm_crtc.h> #include <drm/drm_crtc.h>
#include <drm/drm_fourcc.h> #include <drm/drm_fourcc.h>
#include <drm/drm_managed.h>
#include <drm/drm_vblank.h> #include <drm/drm_vblank.h>
#include "drm_crtc_internal.h" #include "drm_crtc_internal.h"
...@@ -154,31 +155,16 @@ static int create_in_format_blob(struct drm_device *dev, struct drm_plane *plane ...@@ -154,31 +155,16 @@ static int create_in_format_blob(struct drm_device *dev, struct drm_plane *plane
return 0; return 0;
} }
/** __printf(9, 0)
* drm_universal_plane_init - Initialize a new universal plane object static int __drm_universal_plane_init(struct drm_device *dev,
* @dev: DRM device struct drm_plane *plane,
* @plane: plane object to init uint32_t possible_crtcs,
* @possible_crtcs: bitmask of possible CRTCs const struct drm_plane_funcs *funcs,
* @funcs: callbacks for the new plane const uint32_t *formats,
* @formats: array of supported formats (DRM_FORMAT\_\*) unsigned int format_count,
* @format_count: number of elements in @formats const uint64_t *format_modifiers,
* @format_modifiers: array of struct drm_format modifiers terminated by enum drm_plane_type type,
* DRM_FORMAT_MOD_INVALID const char *name, va_list ap)
* @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,
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, ...)
{ {
struct drm_mode_config *config = &dev->mode_config; struct drm_mode_config *config = &dev->mode_config;
unsigned int format_modifier_count = 0; unsigned int format_modifier_count = 0;
...@@ -239,11 +225,7 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane, ...@@ -239,11 +225,7 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
} }
if (name) { if (name) {
va_list ap;
va_start(ap, name);
plane->name = kvasprintf(GFP_KERNEL, name, ap); plane->name = kvasprintf(GFP_KERNEL, name, ap);
va_end(ap);
} else { } else {
plane->name = kasprintf(GFP_KERNEL, "plane-%d", plane->name = kasprintf(GFP_KERNEL, "plane-%d",
drm_num_planes(dev)); drm_num_planes(dev));
...@@ -288,8 +270,102 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane, ...@@ -288,8 +270,102 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
return 0; 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); 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) int drm_plane_register_all(struct drm_device *dev)
{ {
unsigned int num_planes = 0; unsigned int num_planes = 0;
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <drm/drm_atomic.h> #include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h> #include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h> #include <drm/drm_bridge.h>
#include <drm/drm_managed.h>
#include <drm/drm_plane_helper.h> #include <drm/drm_plane_helper.h>
#include <drm/drm_probe_helper.h> #include <drm/drm_probe_helper.h>
#include <drm/drm_simple_kms_helper.h> #include <drm/drm_simple_kms_helper.h>
...@@ -55,8 +56,9 @@ static const struct drm_encoder_funcs drm_simple_encoder_funcs_cleanup = { ...@@ -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 * stored in the device structure. Free the encoder's memory as part of
* the device release function. * the device release function.
* *
* FIXME: Later improvements to DRM's resource management may allow for * Note: consider using drmm_simple_encoder_alloc() instead of
* an automated kfree() of the encoder's memory. * drm_simple_encoder_init() to let the DRM managed resource infrastructure
* take care of cleanup and deallocation.
* *
* Returns: * Returns:
* Zero on success, error code on failure. * Zero on success, error code on failure.
...@@ -71,6 +73,14 @@ int drm_simple_encoder_init(struct drm_device *dev, ...@@ -71,6 +73,14 @@ int drm_simple_encoder_init(struct drm_device *dev,
} }
EXPORT_SYMBOL(drm_simple_encoder_init); 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 static enum drm_mode_status
drm_simple_kms_crtc_mode_valid(struct drm_crtc *crtc, drm_simple_kms_crtc_mode_valid(struct drm_crtc *crtc,
const struct drm_display_mode *mode) const struct drm_display_mode *mode)
......
...@@ -28,6 +28,7 @@ config DRM_IMX_TVE ...@@ -28,6 +28,7 @@ config DRM_IMX_TVE
config DRM_IMX_LDB config DRM_IMX_LDB
tristate "Support for LVDS displays" tristate "Support for LVDS displays"
depends on DRM_IMX && MFD_SYSCON depends on DRM_IMX && MFD_SYSCON
depends on COMMON_CLK
select DRM_PANEL select DRM_PANEL
help help
Choose this to enable the internal LVDS Display Bridge (LDB) Choose this to enable the internal LVDS Display Bridge (LDB)
......
...@@ -15,23 +15,32 @@ ...@@ -15,23 +15,32 @@
#include <drm/bridge/dw_hdmi.h> #include <drm/bridge/dw_hdmi.h>
#include <drm/drm_atomic_helper.h> #include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_edid.h> #include <drm/drm_edid.h>
#include <drm/drm_encoder.h> #include <drm/drm_encoder.h>
#include <drm/drm_managed.h>
#include <drm/drm_of.h> #include <drm/drm_of.h>
#include <drm/drm_simple_kms_helper.h> #include <drm/drm_simple_kms_helper.h>
#include "imx-drm.h" #include "imx-drm.h"
struct imx_hdmi;
struct imx_hdmi_encoder {
struct drm_encoder encoder;
struct imx_hdmi *hdmi;
};
struct imx_hdmi { struct imx_hdmi {
struct device *dev; struct device *dev;
struct drm_encoder encoder; struct drm_bridge *bridge;
struct dw_hdmi *hdmi; struct dw_hdmi *hdmi;
struct regmap *regmap; struct regmap *regmap;
}; };
static inline struct imx_hdmi *enc_to_imx_hdmi(struct drm_encoder *e) static inline struct imx_hdmi *enc_to_imx_hdmi(struct drm_encoder *e)
{ {
return container_of(e, struct imx_hdmi, encoder); return container_of(e, struct imx_hdmi_encoder, encoder)->hdmi;
} }
static const struct dw_hdmi_mpll_config imx_mpll_cfg[] = { static const struct dw_hdmi_mpll_config imx_mpll_cfg[] = {
...@@ -98,19 +107,6 @@ static const struct dw_hdmi_phy_config imx_phy_config[] = { ...@@ -98,19 +107,6 @@ static const struct dw_hdmi_phy_config imx_phy_config[] = {
{ ~0UL, 0x0000, 0x0000, 0x0000} { ~0UL, 0x0000, 0x0000, 0x0000}
}; };
static int dw_hdmi_imx_parse_dt(struct imx_hdmi *hdmi)
{
struct device_node *np = hdmi->dev->of_node;
hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "gpr");
if (IS_ERR(hdmi->regmap)) {
dev_err(hdmi->dev, "Unable to get gpr\n");
return PTR_ERR(hdmi->regmap);
}
return 0;
}
static void dw_hdmi_imx_encoder_enable(struct drm_encoder *encoder) static void dw_hdmi_imx_encoder_enable(struct drm_encoder *encoder)
{ {
struct imx_hdmi *hdmi = enc_to_imx_hdmi(encoder); struct imx_hdmi *hdmi = enc_to_imx_hdmi(encoder);
...@@ -195,65 +191,36 @@ MODULE_DEVICE_TABLE(of, dw_hdmi_imx_dt_ids); ...@@ -195,65 +191,36 @@ MODULE_DEVICE_TABLE(of, dw_hdmi_imx_dt_ids);
static int dw_hdmi_imx_bind(struct device *dev, struct device *master, static int dw_hdmi_imx_bind(struct device *dev, struct device *master,
void *data) void *data)
{ {
struct platform_device *pdev = to_platform_device(dev);
const struct dw_hdmi_plat_data *plat_data;
const struct of_device_id *match;
struct drm_device *drm = data; struct drm_device *drm = data;
struct imx_hdmi_encoder *hdmi_encoder;
struct drm_encoder *encoder; struct drm_encoder *encoder;
struct imx_hdmi *hdmi;
int ret; int ret;
if (!pdev->dev.of_node) hdmi_encoder = drmm_simple_encoder_alloc(drm, struct imx_hdmi_encoder,
return -ENODEV; encoder, DRM_MODE_ENCODER_TMDS);
if (IS_ERR(hdmi_encoder))
return PTR_ERR(hdmi_encoder);
hdmi = dev_get_drvdata(dev); hdmi_encoder->hdmi = dev_get_drvdata(dev);
memset(hdmi, 0, sizeof(*hdmi)); encoder = &hdmi_encoder->encoder;
match = of_match_node(dw_hdmi_imx_dt_ids, pdev->dev.of_node);
plat_data = match->data;
hdmi->dev = &pdev->dev;
encoder = &hdmi->encoder;
ret = imx_drm_encoder_parse_of(drm, encoder, dev->of_node); ret = imx_drm_encoder_parse_of(drm, encoder, dev->of_node);
if (ret) if (ret)
return ret; return ret;
ret = dw_hdmi_imx_parse_dt(hdmi);
if (ret < 0)
return ret;
drm_encoder_helper_add(encoder, &dw_hdmi_imx_encoder_helper_funcs); drm_encoder_helper_add(encoder, &dw_hdmi_imx_encoder_helper_funcs);
drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
hdmi->hdmi = dw_hdmi_bind(pdev, encoder, plat_data);
/* return drm_bridge_attach(encoder, hdmi_encoder->hdmi->bridge, NULL, 0);
* If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(),
* which would have called the encoder cleanup. Do it manually.
*/
if (IS_ERR(hdmi->hdmi)) {
ret = PTR_ERR(hdmi->hdmi);
drm_encoder_cleanup(encoder);
}
return ret;
}
static void dw_hdmi_imx_unbind(struct device *dev, struct device *master,
void *data)
{
struct imx_hdmi *hdmi = dev_get_drvdata(dev);
dw_hdmi_unbind(hdmi->hdmi);
} }
static const struct component_ops dw_hdmi_imx_ops = { static const struct component_ops dw_hdmi_imx_ops = {
.bind = dw_hdmi_imx_bind, .bind = dw_hdmi_imx_bind,
.unbind = dw_hdmi_imx_unbind,
}; };
static int dw_hdmi_imx_probe(struct platform_device *pdev) static int dw_hdmi_imx_probe(struct platform_device *pdev)
{ {
struct device_node *np = pdev->dev.of_node;
const struct of_device_id *match = of_match_node(dw_hdmi_imx_dt_ids, np);
struct imx_hdmi *hdmi; struct imx_hdmi *hdmi;
hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL); hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
...@@ -261,13 +228,33 @@ static int dw_hdmi_imx_probe(struct platform_device *pdev) ...@@ -261,13 +228,33 @@ static int dw_hdmi_imx_probe(struct platform_device *pdev)
return -ENOMEM; return -ENOMEM;
platform_set_drvdata(pdev, hdmi); platform_set_drvdata(pdev, hdmi);
hdmi->dev = &pdev->dev;
hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "gpr");
if (IS_ERR(hdmi->regmap)) {
dev_err(hdmi->dev, "Unable to get gpr\n");
return PTR_ERR(hdmi->regmap);
}
hdmi->hdmi = dw_hdmi_probe(pdev, match->data);
if (IS_ERR(hdmi->hdmi))
return PTR_ERR(hdmi->hdmi);
hdmi->bridge = of_drm_find_bridge(np);
if (!hdmi->bridge) {
dev_err(hdmi->dev, "Unable to find bridge\n");
return -ENODEV;
}
return component_add(&pdev->dev, &dw_hdmi_imx_ops); return component_add(&pdev->dev, &dw_hdmi_imx_ops);
} }
static int dw_hdmi_imx_remove(struct platform_device *pdev) static int dw_hdmi_imx_remove(struct platform_device *pdev)
{ {
struct imx_hdmi *hdmi = platform_get_drvdata(pdev);
component_del(&pdev->dev, &dw_hdmi_imx_ops); component_del(&pdev->dev, &dw_hdmi_imx_ops);
dw_hdmi_remove(hdmi->hdmi);
return 0; return 0;
} }
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <drm/drm_atomic_helper.h> #include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h> #include <drm/drm_bridge.h>
#include <drm/drm_fb_helper.h> #include <drm/drm_fb_helper.h>
#include <drm/drm_managed.h>
#include <drm/drm_of.h> #include <drm/drm_of.h>
#include <drm/drm_panel.h> #include <drm/drm_panel.h>
#include <drm/drm_print.h> #include <drm/drm_print.h>
...@@ -47,12 +48,18 @@ ...@@ -47,12 +48,18 @@
#define LDB_DI1_VS_POL_ACT_LOW (1 << 10) #define LDB_DI1_VS_POL_ACT_LOW (1 << 10)
#define LDB_BGREF_RMODE_INT (1 << 15) #define LDB_BGREF_RMODE_INT (1 << 15)
struct imx_ldb_channel;
struct imx_ldb_encoder {
struct drm_connector connector;
struct drm_encoder encoder;
struct imx_ldb_channel *channel;
};
struct imx_ldb; struct imx_ldb;
struct imx_ldb_channel { struct imx_ldb_channel {
struct imx_ldb *ldb; struct imx_ldb *ldb;
struct drm_connector connector;
struct drm_encoder encoder;
/* Defines what is connected to the ldb, only one at a time */ /* Defines what is connected to the ldb, only one at a time */
struct drm_panel *panel; struct drm_panel *panel;
...@@ -70,12 +77,12 @@ struct imx_ldb_channel { ...@@ -70,12 +77,12 @@ struct imx_ldb_channel {
static inline struct imx_ldb_channel *con_to_imx_ldb_ch(struct drm_connector *c) static inline struct imx_ldb_channel *con_to_imx_ldb_ch(struct drm_connector *c)
{ {
return container_of(c, struct imx_ldb_channel, connector); return container_of(c, struct imx_ldb_encoder, connector)->channel;
} }
static inline struct imx_ldb_channel *enc_to_imx_ldb_ch(struct drm_encoder *e) static inline struct imx_ldb_channel *enc_to_imx_ldb_ch(struct drm_encoder *e)
{ {
return container_of(e, struct imx_ldb_channel, encoder); return container_of(e, struct imx_ldb_encoder, encoder)->channel;
} }
struct bus_mux { struct bus_mux {
...@@ -411,9 +418,20 @@ static int imx_ldb_register(struct drm_device *drm, ...@@ -411,9 +418,20 @@ static int imx_ldb_register(struct drm_device *drm,
struct imx_ldb_channel *imx_ldb_ch) struct imx_ldb_channel *imx_ldb_ch)
{ {
struct imx_ldb *ldb = imx_ldb_ch->ldb; struct imx_ldb *ldb = imx_ldb_ch->ldb;
struct drm_encoder *encoder = &imx_ldb_ch->encoder; struct imx_ldb_encoder *ldb_encoder;
struct drm_connector *connector;
struct drm_encoder *encoder;
int ret; int ret;
ldb_encoder = drmm_simple_encoder_alloc(drm, struct imx_ldb_encoder,
encoder, DRM_MODE_ENCODER_LVDS);
if (IS_ERR(ldb_encoder))
return PTR_ERR(ldb_encoder);
ldb_encoder->channel = imx_ldb_ch;
connector = &ldb_encoder->connector;
encoder = &ldb_encoder->encoder;
ret = imx_drm_encoder_parse_of(drm, encoder, imx_ldb_ch->child); ret = imx_drm_encoder_parse_of(drm, encoder, imx_ldb_ch->child);
if (ret) if (ret)
return ret; return ret;
...@@ -429,11 +447,9 @@ static int imx_ldb_register(struct drm_device *drm, ...@@ -429,11 +447,9 @@ static int imx_ldb_register(struct drm_device *drm,
} }
drm_encoder_helper_add(encoder, &imx_ldb_encoder_helper_funcs); drm_encoder_helper_add(encoder, &imx_ldb_encoder_helper_funcs);
drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_LVDS);
if (imx_ldb_ch->bridge) { if (imx_ldb_ch->bridge) {
ret = drm_bridge_attach(&imx_ldb_ch->encoder, ret = drm_bridge_attach(encoder, imx_ldb_ch->bridge, NULL, 0);
imx_ldb_ch->bridge, NULL, 0);
if (ret) { if (ret) {
DRM_ERROR("Failed to initialize bridge with drm\n"); DRM_ERROR("Failed to initialize bridge with drm\n");
return ret; return ret;
...@@ -445,13 +461,13 @@ static int imx_ldb_register(struct drm_device *drm, ...@@ -445,13 +461,13 @@ static int imx_ldb_register(struct drm_device *drm,
* historical reasons, the ldb driver can also work without * historical reasons, the ldb driver can also work without
* a panel. * a panel.
*/ */
drm_connector_helper_add(&imx_ldb_ch->connector, drm_connector_helper_add(connector,
&imx_ldb_connector_helper_funcs); &imx_ldb_connector_helper_funcs);
drm_connector_init_with_ddc(drm, &imx_ldb_ch->connector, drm_connector_init_with_ddc(drm, connector,
&imx_ldb_connector_funcs, &imx_ldb_connector_funcs,
DRM_MODE_CONNECTOR_LVDS, DRM_MODE_CONNECTOR_LVDS,
imx_ldb_ch->ddc); imx_ldb_ch->ddc);
drm_connector_attach_encoder(&imx_ldb_ch->connector, encoder); drm_connector_attach_encoder(connector, encoder);
} }
return 0; return 0;
...@@ -559,17 +575,42 @@ static int imx_ldb_panel_ddc(struct device *dev, ...@@ -559,17 +575,42 @@ static int imx_ldb_panel_ddc(struct device *dev,
static int imx_ldb_bind(struct device *dev, struct device *master, void *data) static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
{ {
struct drm_device *drm = data; struct drm_device *drm = data;
struct imx_ldb *imx_ldb = dev_get_drvdata(dev);
int ret;
int i;
for (i = 0; i < 2; i++) {
struct imx_ldb_channel *channel = &imx_ldb->channel[i];
if (!channel->ldb)
break;
ret = imx_ldb_register(drm, channel);
if (ret)
return ret;
}
return 0;
}
static const struct component_ops imx_ldb_ops = {
.bind = imx_ldb_bind,
};
static int imx_ldb_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node; struct device_node *np = dev->of_node;
const struct of_device_id *of_id = const struct of_device_id *of_id = of_match_device(imx_ldb_dt_ids, dev);
of_match_device(imx_ldb_dt_ids, dev);
struct device_node *child; struct device_node *child;
struct imx_ldb *imx_ldb; struct imx_ldb *imx_ldb;
int dual; int dual;
int ret; int ret;
int i; int i;
imx_ldb = dev_get_drvdata(dev); imx_ldb = devm_kzalloc(dev, sizeof(*imx_ldb), GFP_KERNEL);
memset(imx_ldb, 0, sizeof(*imx_ldb)); if (!imx_ldb)
return -ENOMEM;
imx_ldb->regmap = syscon_regmap_lookup_by_phandle(np, "gpr"); imx_ldb->regmap = syscon_regmap_lookup_by_phandle(np, "gpr");
if (IS_ERR(imx_ldb->regmap)) { if (IS_ERR(imx_ldb->regmap)) {
...@@ -669,25 +710,20 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data) ...@@ -669,25 +710,20 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
} }
channel->bus_format = bus_format; channel->bus_format = bus_format;
channel->child = child; channel->child = child;
ret = imx_ldb_register(drm, channel);
if (ret) {
channel->child = NULL;
goto free_child;
}
} }
return 0; platform_set_drvdata(pdev, imx_ldb);
return component_add(&pdev->dev, &imx_ldb_ops);
free_child: free_child:
of_node_put(child); of_node_put(child);
return ret; return ret;
} }
static void imx_ldb_unbind(struct device *dev, struct device *master, static int imx_ldb_remove(struct platform_device *pdev)
void *data)
{ {
struct imx_ldb *imx_ldb = dev_get_drvdata(dev); struct imx_ldb *imx_ldb = platform_get_drvdata(pdev);
int i; int i;
for (i = 0; i < 2; i++) { for (i = 0; i < 2; i++) {
...@@ -696,28 +732,7 @@ static void imx_ldb_unbind(struct device *dev, struct device *master, ...@@ -696,28 +732,7 @@ static void imx_ldb_unbind(struct device *dev, struct device *master,
kfree(channel->edid); kfree(channel->edid);
i2c_put_adapter(channel->ddc); i2c_put_adapter(channel->ddc);
} }
}
static const struct component_ops imx_ldb_ops = {
.bind = imx_ldb_bind,
.unbind = imx_ldb_unbind,
};
static int imx_ldb_probe(struct platform_device *pdev)
{
struct imx_ldb *imx_ldb;
imx_ldb = devm_kzalloc(&pdev->dev, sizeof(*imx_ldb), GFP_KERNEL);
if (!imx_ldb)
return -ENOMEM;
platform_set_drvdata(pdev, imx_ldb);
return component_add(&pdev->dev, &imx_ldb_ops);
}
static int imx_ldb_remove(struct platform_device *pdev)
{
component_del(&pdev->dev, &imx_ldb_ops); component_del(&pdev->dev, &imx_ldb_ops);
return 0; return 0;
} }
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <drm/drm_atomic_helper.h> #include <drm/drm_atomic_helper.h>
#include <drm/drm_fb_helper.h> #include <drm/drm_fb_helper.h>
#include <drm/drm_managed.h>
#include <drm/drm_probe_helper.h> #include <drm/drm_probe_helper.h>
#include <drm/drm_simple_kms_helper.h> #include <drm/drm_simple_kms_helper.h>
...@@ -99,9 +100,13 @@ enum { ...@@ -99,9 +100,13 @@ enum {
TVE_MODE_VGA, TVE_MODE_VGA,
}; };
struct imx_tve { struct imx_tve_encoder {
struct drm_connector connector; struct drm_connector connector;
struct drm_encoder encoder; struct drm_encoder encoder;
struct imx_tve *tve;
};
struct imx_tve {
struct device *dev; struct device *dev;
int mode; int mode;
int di_hsync_pin; int di_hsync_pin;
...@@ -118,12 +123,12 @@ struct imx_tve { ...@@ -118,12 +123,12 @@ struct imx_tve {
static inline struct imx_tve *con_to_tve(struct drm_connector *c) static inline struct imx_tve *con_to_tve(struct drm_connector *c)
{ {
return container_of(c, struct imx_tve, connector); return container_of(c, struct imx_tve_encoder, connector)->tve;
} }
static inline struct imx_tve *enc_to_tve(struct drm_encoder *e) static inline struct imx_tve *enc_to_tve(struct drm_encoder *e)
{ {
return container_of(e, struct imx_tve, encoder); return container_of(e, struct imx_tve_encoder, encoder)->tve;
} }
static void tve_enable(struct imx_tve *tve) static void tve_enable(struct imx_tve *tve)
...@@ -418,7 +423,7 @@ static int tve_clk_init(struct imx_tve *tve, void __iomem *base) ...@@ -418,7 +423,7 @@ static int tve_clk_init(struct imx_tve *tve, void __iomem *base)
init.parent_names = (const char **)&tve_di_parent; init.parent_names = (const char **)&tve_di_parent;
tve->clk_hw_di.init = &init; tve->clk_hw_di.init = &init;
tve->di_clk = clk_register(tve->dev, &tve->clk_hw_di); tve->di_clk = devm_clk_register(tve->dev, &tve->clk_hw_di);
if (IS_ERR(tve->di_clk)) { if (IS_ERR(tve->di_clk)) {
dev_err(tve->dev, "failed to register TVE output clock: %ld\n", dev_err(tve->dev, "failed to register TVE output clock: %ld\n",
PTR_ERR(tve->di_clk)); PTR_ERR(tve->di_clk));
...@@ -428,33 +433,6 @@ static int tve_clk_init(struct imx_tve *tve, void __iomem *base) ...@@ -428,33 +433,6 @@ static int tve_clk_init(struct imx_tve *tve, void __iomem *base)
return 0; return 0;
} }
static int imx_tve_register(struct drm_device *drm, struct imx_tve *tve)
{
int encoder_type;
int ret;
encoder_type = tve->mode == TVE_MODE_VGA ?
DRM_MODE_ENCODER_DAC : DRM_MODE_ENCODER_TVDAC;
ret = imx_drm_encoder_parse_of(drm, &tve->encoder, tve->dev->of_node);
if (ret)
return ret;
drm_encoder_helper_add(&tve->encoder, &imx_tve_encoder_helper_funcs);
drm_simple_encoder_init(drm, &tve->encoder, encoder_type);
drm_connector_helper_add(&tve->connector,
&imx_tve_connector_helper_funcs);
drm_connector_init_with_ddc(drm, &tve->connector,
&imx_tve_connector_funcs,
DRM_MODE_CONNECTOR_VGA,
tve->ddc);
drm_connector_attach_encoder(&tve->connector, &tve->encoder);
return 0;
}
static void imx_tve_disable_regulator(void *data) static void imx_tve_disable_regulator(void *data)
{ {
struct imx_tve *tve = data; struct imx_tve *tve = data;
...@@ -502,8 +480,49 @@ static int of_get_tve_mode(struct device_node *np) ...@@ -502,8 +480,49 @@ static int of_get_tve_mode(struct device_node *np)
static int imx_tve_bind(struct device *dev, struct device *master, void *data) static int imx_tve_bind(struct device *dev, struct device *master, void *data)
{ {
struct platform_device *pdev = to_platform_device(dev);
struct drm_device *drm = data; struct drm_device *drm = data;
struct imx_tve *tve = dev_get_drvdata(dev);
struct imx_tve_encoder *tvee;
struct drm_encoder *encoder;
struct drm_connector *connector;
int encoder_type;
int ret;
encoder_type = tve->mode == TVE_MODE_VGA ?
DRM_MODE_ENCODER_DAC : DRM_MODE_ENCODER_TVDAC;
tvee = drmm_simple_encoder_alloc(drm, struct imx_tve_encoder, encoder,
encoder_type);
if (IS_ERR(tvee))
return PTR_ERR(tvee);
tvee->tve = tve;
encoder = &tvee->encoder;
connector = &tvee->connector;
ret = imx_drm_encoder_parse_of(drm, encoder, tve->dev->of_node);
if (ret)
return ret;
drm_encoder_helper_add(encoder, &imx_tve_encoder_helper_funcs);
drm_connector_helper_add(connector, &imx_tve_connector_helper_funcs);
ret = drm_connector_init_with_ddc(drm, connector,
&imx_tve_connector_funcs,
DRM_MODE_CONNECTOR_VGA, tve->ddc);
if (ret)
return ret;
return drm_connector_attach_encoder(connector, encoder);
}
static const struct component_ops imx_tve_ops = {
.bind = imx_tve_bind,
};
static int imx_tve_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node; struct device_node *np = dev->of_node;
struct device_node *ddc_node; struct device_node *ddc_node;
struct imx_tve *tve; struct imx_tve *tve;
...@@ -513,8 +532,9 @@ static int imx_tve_bind(struct device *dev, struct device *master, void *data) ...@@ -513,8 +532,9 @@ static int imx_tve_bind(struct device *dev, struct device *master, void *data)
int irq; int irq;
int ret; int ret;
tve = dev_get_drvdata(dev); tve = devm_kzalloc(dev, sizeof(*tve), GFP_KERNEL);
memset(tve, 0, sizeof(*tve)); if (!tve)
return -ENOMEM;
tve->dev = dev; tve->dev = dev;
...@@ -621,28 +641,9 @@ static int imx_tve_bind(struct device *dev, struct device *master, void *data) ...@@ -621,28 +641,9 @@ static int imx_tve_bind(struct device *dev, struct device *master, void *data)
if (ret) if (ret)
return ret; return ret;
ret = imx_tve_register(drm, tve);
if (ret)
return ret;
return 0;
}
static const struct component_ops imx_tve_ops = {
.bind = imx_tve_bind,
};
static int imx_tve_probe(struct platform_device *pdev)
{
struct imx_tve *tve;
tve = devm_kzalloc(&pdev->dev, sizeof(*tve), GFP_KERNEL);
if (!tve)
return -ENOMEM;
platform_set_drvdata(pdev, tve); platform_set_drvdata(pdev, tve);
return component_add(&pdev->dev, &imx_tve_ops); return component_add(dev, &imx_tve_ops);
} }
static int imx_tve_remove(struct platform_device *pdev) static int imx_tve_remove(struct platform_device *pdev)
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <drm/drm_atomic_helper.h> #include <drm/drm_atomic_helper.h>
#include <drm/drm_fb_cma_helper.h> #include <drm/drm_fb_cma_helper.h>
#include <drm/drm_gem_cma_helper.h> #include <drm/drm_gem_cma_helper.h>
#include <drm/drm_managed.h>
#include <drm/drm_probe_helper.h> #include <drm/drm_probe_helper.h>
#include <drm/drm_vblank.h> #include <drm/drm_vblank.h>
...@@ -163,7 +164,6 @@ static void ipu_disable_vblank(struct drm_crtc *crtc) ...@@ -163,7 +164,6 @@ static void ipu_disable_vblank(struct drm_crtc *crtc)
static const struct drm_crtc_funcs ipu_crtc_funcs = { static const struct drm_crtc_funcs ipu_crtc_funcs = {
.set_config = drm_atomic_helper_set_config, .set_config = drm_atomic_helper_set_config,
.destroy = drm_crtc_cleanup,
.page_flip = drm_atomic_helper_page_flip, .page_flip = drm_atomic_helper_page_flip,
.reset = imx_drm_crtc_reset, .reset = imx_drm_crtc_reset,
.atomic_duplicate_state = imx_drm_crtc_duplicate_state, .atomic_duplicate_state = imx_drm_crtc_duplicate_state,
...@@ -322,73 +322,73 @@ static const struct drm_crtc_helper_funcs ipu_helper_funcs = { ...@@ -322,73 +322,73 @@ static const struct drm_crtc_helper_funcs ipu_helper_funcs = {
.atomic_enable = ipu_crtc_atomic_enable, .atomic_enable = ipu_crtc_atomic_enable,
}; };
static void ipu_put_resources(struct ipu_crtc *ipu_crtc) static void ipu_put_resources(struct drm_device *dev, void *ptr)
{ {
struct ipu_crtc *ipu_crtc = ptr;
if (!IS_ERR_OR_NULL(ipu_crtc->dc)) if (!IS_ERR_OR_NULL(ipu_crtc->dc))
ipu_dc_put(ipu_crtc->dc); ipu_dc_put(ipu_crtc->dc);
if (!IS_ERR_OR_NULL(ipu_crtc->di)) if (!IS_ERR_OR_NULL(ipu_crtc->di))
ipu_di_put(ipu_crtc->di); ipu_di_put(ipu_crtc->di);
} }
static int ipu_get_resources(struct ipu_crtc *ipu_crtc, static int ipu_get_resources(struct drm_device *dev, struct ipu_crtc *ipu_crtc,
struct ipu_client_platformdata *pdata) struct ipu_client_platformdata *pdata)
{ {
struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent); struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
int ret; int ret;
ipu_crtc->dc = ipu_dc_get(ipu, pdata->dc); ipu_crtc->dc = ipu_dc_get(ipu, pdata->dc);
if (IS_ERR(ipu_crtc->dc)) { if (IS_ERR(ipu_crtc->dc))
ret = PTR_ERR(ipu_crtc->dc); return PTR_ERR(ipu_crtc->dc);
goto err_out;
} ret = drmm_add_action_or_reset(dev, ipu_put_resources, ipu_crtc);
if (ret)
return ret;
ipu_crtc->di = ipu_di_get(ipu, pdata->di); ipu_crtc->di = ipu_di_get(ipu, pdata->di);
if (IS_ERR(ipu_crtc->di)) { if (IS_ERR(ipu_crtc->di))
ret = PTR_ERR(ipu_crtc->di); return PTR_ERR(ipu_crtc->di);
goto err_out;
}
return 0; return 0;
err_out:
ipu_put_resources(ipu_crtc);
return ret;
} }
static int ipu_crtc_init(struct ipu_crtc *ipu_crtc, static int ipu_drm_bind(struct device *dev, struct device *master, void *data)
struct ipu_client_platformdata *pdata, struct drm_device *drm)
{ {
struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent); struct ipu_client_platformdata *pdata = dev->platform_data;
struct drm_crtc *crtc = &ipu_crtc->base; struct ipu_soc *ipu = dev_get_drvdata(dev->parent);
struct drm_device *drm = data;
struct ipu_plane *primary_plane;
struct ipu_crtc *ipu_crtc;
struct drm_crtc *crtc;
int dp = -EINVAL; int dp = -EINVAL;
int ret; int ret;
ret = ipu_get_resources(ipu_crtc, pdata);
if (ret) {
dev_err(ipu_crtc->dev, "getting resources failed with %d.\n",
ret);
return ret;
}
if (pdata->dp >= 0) if (pdata->dp >= 0)
dp = IPU_DP_FLOW_SYNC_BG; dp = IPU_DP_FLOW_SYNC_BG;
ipu_crtc->plane[0] = ipu_plane_init(drm, ipu, pdata->dma[0], dp, 0, primary_plane = ipu_plane_init(drm, ipu, pdata->dma[0], dp, 0,
DRM_PLANE_TYPE_PRIMARY); DRM_PLANE_TYPE_PRIMARY);
if (IS_ERR(ipu_crtc->plane[0])) { if (IS_ERR(primary_plane))
ret = PTR_ERR(ipu_crtc->plane[0]); return PTR_ERR(primary_plane);
goto err_put_resources;
} ipu_crtc = drmm_crtc_alloc_with_planes(drm, struct ipu_crtc, base,
&primary_plane->base, NULL,
&ipu_crtc_funcs, NULL);
if (IS_ERR(ipu_crtc))
return PTR_ERR(ipu_crtc);
ipu_crtc->dev = dev;
ipu_crtc->plane[0] = primary_plane;
crtc = &ipu_crtc->base;
crtc->port = pdata->of_node; crtc->port = pdata->of_node;
drm_crtc_helper_add(crtc, &ipu_helper_funcs); drm_crtc_helper_add(crtc, &ipu_helper_funcs);
drm_crtc_init_with_planes(drm, crtc, &ipu_crtc->plane[0]->base, NULL,
&ipu_crtc_funcs, NULL);
ret = ipu_plane_get_resources(ipu_crtc->plane[0]); ret = ipu_get_resources(drm, ipu_crtc, pdata);
if (ret) { if (ret) {
dev_err(ipu_crtc->dev, "getting plane 0 resources failed with %d.\n", dev_err(ipu_crtc->dev, "getting resources failed with %d.\n",
ret); ret);
goto err_put_resources; return ret;
} }
/* If this crtc is using the DP, add an overlay plane */ /* If this crtc is using the DP, add an overlay plane */
...@@ -397,16 +397,8 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc, ...@@ -397,16 +397,8 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
IPU_DP_FLOW_SYNC_FG, IPU_DP_FLOW_SYNC_FG,
drm_crtc_mask(&ipu_crtc->base), drm_crtc_mask(&ipu_crtc->base),
DRM_PLANE_TYPE_OVERLAY); DRM_PLANE_TYPE_OVERLAY);
if (IS_ERR(ipu_crtc->plane[1])) { if (IS_ERR(ipu_crtc->plane[1]))
ipu_crtc->plane[1] = NULL; ipu_crtc->plane[1] = NULL;
} else {
ret = ipu_plane_get_resources(ipu_crtc->plane[1]);
if (ret) {
dev_err(ipu_crtc->dev, "getting plane 1 "
"resources failed with %d.\n", ret);
goto err_put_plane0_res;
}
}
} }
ipu_crtc->irq = ipu_plane_irq(ipu_crtc->plane[0]); ipu_crtc->irq = ipu_plane_irq(ipu_crtc->plane[0]);
...@@ -414,58 +406,21 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc, ...@@ -414,58 +406,21 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
"imx_drm", ipu_crtc); "imx_drm", ipu_crtc);
if (ret < 0) { if (ret < 0) {
dev_err(ipu_crtc->dev, "irq request failed with %d.\n", ret); dev_err(ipu_crtc->dev, "irq request failed with %d.\n", ret);
goto err_put_plane1_res; return ret;
} }
/* Only enable IRQ when we actually need it to trigger work. */ /* Only enable IRQ when we actually need it to trigger work. */
disable_irq(ipu_crtc->irq); disable_irq(ipu_crtc->irq);
return 0; return 0;
err_put_plane1_res:
if (ipu_crtc->plane[1])
ipu_plane_put_resources(ipu_crtc->plane[1]);
err_put_plane0_res:
ipu_plane_put_resources(ipu_crtc->plane[0]);
err_put_resources:
ipu_put_resources(ipu_crtc);
return ret;
}
static int ipu_drm_bind(struct device *dev, struct device *master, void *data)
{
struct ipu_client_platformdata *pdata = dev->platform_data;
struct drm_device *drm = data;
struct ipu_crtc *ipu_crtc;
ipu_crtc = dev_get_drvdata(dev);
memset(ipu_crtc, 0, sizeof(*ipu_crtc));
ipu_crtc->dev = dev;
return ipu_crtc_init(ipu_crtc, pdata, drm);
}
static void ipu_drm_unbind(struct device *dev, struct device *master,
void *data)
{
struct ipu_crtc *ipu_crtc = dev_get_drvdata(dev);
ipu_put_resources(ipu_crtc);
if (ipu_crtc->plane[1])
ipu_plane_put_resources(ipu_crtc->plane[1]);
ipu_plane_put_resources(ipu_crtc->plane[0]);
} }
static const struct component_ops ipu_crtc_ops = { static const struct component_ops ipu_crtc_ops = {
.bind = ipu_drm_bind, .bind = ipu_drm_bind,
.unbind = ipu_drm_unbind,
}; };
static int ipu_drm_probe(struct platform_device *pdev) static int ipu_drm_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct ipu_crtc *ipu_crtc;
int ret; int ret;
if (!dev->platform_data) if (!dev->platform_data)
...@@ -475,12 +430,6 @@ static int ipu_drm_probe(struct platform_device *pdev) ...@@ -475,12 +430,6 @@ static int ipu_drm_probe(struct platform_device *pdev)
if (ret) if (ret)
return ret; return ret;
ipu_crtc = devm_kzalloc(dev, sizeof(*ipu_crtc), GFP_KERNEL);
if (!ipu_crtc)
return -ENOMEM;
dev_set_drvdata(dev, ipu_crtc);
return component_add(dev, &ipu_crtc_ops); return component_add(dev, &ipu_crtc_ops);
} }
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <drm/drm_fourcc.h> #include <drm/drm_fourcc.h>
#include <drm/drm_gem_cma_helper.h> #include <drm/drm_gem_cma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_managed.h>
#include <drm/drm_plane_helper.h> #include <drm/drm_plane_helper.h>
#include <video/imx-ipu-v3.h> #include <video/imx-ipu-v3.h>
...@@ -142,8 +143,10 @@ drm_plane_state_to_vbo(struct drm_plane_state *state) ...@@ -142,8 +143,10 @@ drm_plane_state_to_vbo(struct drm_plane_state *state)
fb->format->cpp[2] * x - eba; fb->format->cpp[2] * x - eba;
} }
void ipu_plane_put_resources(struct ipu_plane *ipu_plane) static void ipu_plane_put_resources(struct drm_device *dev, void *ptr)
{ {
struct ipu_plane *ipu_plane = ptr;
if (!IS_ERR_OR_NULL(ipu_plane->dp)) if (!IS_ERR_OR_NULL(ipu_plane->dp))
ipu_dp_put(ipu_plane->dp); ipu_dp_put(ipu_plane->dp);
if (!IS_ERR_OR_NULL(ipu_plane->dmfc)) if (!IS_ERR_OR_NULL(ipu_plane->dmfc))
...@@ -154,7 +157,8 @@ void ipu_plane_put_resources(struct ipu_plane *ipu_plane) ...@@ -154,7 +157,8 @@ void ipu_plane_put_resources(struct ipu_plane *ipu_plane)
ipu_idmac_put(ipu_plane->alpha_ch); ipu_idmac_put(ipu_plane->alpha_ch);
} }
int ipu_plane_get_resources(struct ipu_plane *ipu_plane) static int ipu_plane_get_resources(struct drm_device *dev,
struct ipu_plane *ipu_plane)
{ {
int ret; int ret;
int alpha_ch; int alpha_ch;
...@@ -166,6 +170,10 @@ int ipu_plane_get_resources(struct ipu_plane *ipu_plane) ...@@ -166,6 +170,10 @@ int ipu_plane_get_resources(struct ipu_plane *ipu_plane)
return ret; return ret;
} }
ret = drmm_add_action_or_reset(dev, ipu_plane_put_resources, ipu_plane);
if (ret)
return ret;
alpha_ch = ipu_channel_alpha_channel(ipu_plane->dma); alpha_ch = ipu_channel_alpha_channel(ipu_plane->dma);
if (alpha_ch >= 0) { if (alpha_ch >= 0) {
ipu_plane->alpha_ch = ipu_idmac_get(ipu_plane->ipu, alpha_ch); ipu_plane->alpha_ch = ipu_idmac_get(ipu_plane->ipu, alpha_ch);
...@@ -181,7 +189,7 @@ int ipu_plane_get_resources(struct ipu_plane *ipu_plane) ...@@ -181,7 +189,7 @@ int ipu_plane_get_resources(struct ipu_plane *ipu_plane)
if (IS_ERR(ipu_plane->dmfc)) { if (IS_ERR(ipu_plane->dmfc)) {
ret = PTR_ERR(ipu_plane->dmfc); ret = PTR_ERR(ipu_plane->dmfc);
DRM_ERROR("failed to get dmfc: ret %d\n", ret); DRM_ERROR("failed to get dmfc: ret %d\n", ret);
goto err_out; return ret;
} }
if (ipu_plane->dp_flow >= 0) { if (ipu_plane->dp_flow >= 0) {
...@@ -189,15 +197,11 @@ int ipu_plane_get_resources(struct ipu_plane *ipu_plane) ...@@ -189,15 +197,11 @@ int ipu_plane_get_resources(struct ipu_plane *ipu_plane)
if (IS_ERR(ipu_plane->dp)) { if (IS_ERR(ipu_plane->dp)) {
ret = PTR_ERR(ipu_plane->dp); ret = PTR_ERR(ipu_plane->dp);
DRM_ERROR("failed to get dp flow: %d\n", ret); DRM_ERROR("failed to get dp flow: %d\n", ret);
goto err_out; return ret;
} }
} }
return 0; return 0;
err_out:
ipu_plane_put_resources(ipu_plane);
return ret;
} }
static bool ipu_plane_separate_alpha(struct ipu_plane *ipu_plane) static bool ipu_plane_separate_alpha(struct ipu_plane *ipu_plane)
...@@ -262,16 +266,6 @@ void ipu_plane_disable_deferred(struct drm_plane *plane) ...@@ -262,16 +266,6 @@ void ipu_plane_disable_deferred(struct drm_plane *plane)
} }
EXPORT_SYMBOL_GPL(ipu_plane_disable_deferred); EXPORT_SYMBOL_GPL(ipu_plane_disable_deferred);
static void ipu_plane_destroy(struct drm_plane *plane)
{
struct ipu_plane *ipu_plane = to_ipu_plane(plane);
DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
drm_plane_cleanup(plane);
kfree(ipu_plane);
}
static void ipu_plane_state_reset(struct drm_plane *plane) static void ipu_plane_state_reset(struct drm_plane *plane)
{ {
unsigned int zpos = (plane->type == DRM_PLANE_TYPE_PRIMARY) ? 0 : 1; unsigned int zpos = (plane->type == DRM_PLANE_TYPE_PRIMARY) ? 0 : 1;
...@@ -336,7 +330,6 @@ static bool ipu_plane_format_mod_supported(struct drm_plane *plane, ...@@ -336,7 +330,6 @@ static bool ipu_plane_format_mod_supported(struct drm_plane *plane,
static const struct drm_plane_funcs ipu_plane_funcs = { static const struct drm_plane_funcs ipu_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane, .update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane, .disable_plane = drm_atomic_helper_disable_plane,
.destroy = ipu_plane_destroy,
.reset = ipu_plane_state_reset, .reset = ipu_plane_state_reset,
.atomic_duplicate_state = ipu_plane_duplicate_state, .atomic_duplicate_state = ipu_plane_duplicate_state,
.atomic_destroy_state = ipu_plane_destroy_state, .atomic_destroy_state = ipu_plane_destroy_state,
...@@ -834,10 +827,15 @@ struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu, ...@@ -834,10 +827,15 @@ struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
DRM_DEBUG_KMS("channel %d, dp flow %d, possible_crtcs=0x%x\n", DRM_DEBUG_KMS("channel %d, dp flow %d, possible_crtcs=0x%x\n",
dma, dp, possible_crtcs); dma, dp, possible_crtcs);
ipu_plane = kzalloc(sizeof(*ipu_plane), GFP_KERNEL); ipu_plane = drmm_universal_plane_alloc(dev, struct ipu_plane, base,
if (!ipu_plane) { possible_crtcs, &ipu_plane_funcs,
DRM_ERROR("failed to allocate plane\n"); ipu_plane_formats,
return ERR_PTR(-ENOMEM); ARRAY_SIZE(ipu_plane_formats),
modifiers, type, NULL);
if (IS_ERR(ipu_plane)) {
DRM_ERROR("failed to allocate and initialize %s plane\n",
zpos ? "overlay" : "primary");
return ipu_plane;
} }
ipu_plane->ipu = ipu; ipu_plane->ipu = ipu;
...@@ -847,22 +845,23 @@ struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu, ...@@ -847,22 +845,23 @@ struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
if (ipu_prg_present(ipu)) if (ipu_prg_present(ipu))
modifiers = pre_format_modifiers; modifiers = pre_format_modifiers;
ret = drm_universal_plane_init(dev, &ipu_plane->base, possible_crtcs,
&ipu_plane_funcs, ipu_plane_formats,
ARRAY_SIZE(ipu_plane_formats),
modifiers, type, NULL);
if (ret) {
DRM_ERROR("failed to initialize plane\n");
kfree(ipu_plane);
return ERR_PTR(ret);
}
drm_plane_helper_add(&ipu_plane->base, &ipu_plane_helper_funcs); drm_plane_helper_add(&ipu_plane->base, &ipu_plane_helper_funcs);
if (dp == IPU_DP_FLOW_SYNC_BG || dp == IPU_DP_FLOW_SYNC_FG) if (dp == IPU_DP_FLOW_SYNC_BG || dp == IPU_DP_FLOW_SYNC_FG)
drm_plane_create_zpos_property(&ipu_plane->base, zpos, 0, 1); ret = drm_plane_create_zpos_property(&ipu_plane->base, zpos, 0,
1);
else else
drm_plane_create_zpos_immutable_property(&ipu_plane->base, 0); ret = drm_plane_create_zpos_immutable_property(&ipu_plane->base,
0);
if (ret)
return ERR_PTR(ret);
ret = ipu_plane_get_resources(dev, ipu_plane);
if (ret) {
DRM_ERROR("failed to get %s plane resources: %pe\n",
zpos ? "overlay" : "primary", &ret);
return ERR_PTR(ret);
}
return ipu_plane; return ipu_plane;
} }
...@@ -41,9 +41,6 @@ int ipu_plane_mode_set(struct ipu_plane *plane, struct drm_crtc *crtc, ...@@ -41,9 +41,6 @@ int ipu_plane_mode_set(struct ipu_plane *plane, struct drm_crtc *crtc,
uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_x, uint32_t src_y, uint32_t src_w,
uint32_t src_h, bool interlaced); uint32_t src_h, bool interlaced);
int ipu_plane_get_resources(struct ipu_plane *plane);
void ipu_plane_put_resources(struct ipu_plane *plane);
int ipu_plane_irq(struct ipu_plane *plane); int ipu_plane_irq(struct ipu_plane *plane);
void ipu_plane_disable(struct ipu_plane *ipu_plane, bool disable_dp_channel); void ipu_plane_disable(struct ipu_plane *ipu_plane, bool disable_dp_channel);
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <drm/drm_atomic_helper.h> #include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h> #include <drm/drm_bridge.h>
#include <drm/drm_fb_helper.h> #include <drm/drm_fb_helper.h>
#include <drm/drm_managed.h>
#include <drm/drm_of.h> #include <drm/drm_of.h>
#include <drm/drm_panel.h> #include <drm/drm_panel.h>
#include <drm/drm_probe_helper.h> #include <drm/drm_probe_helper.h>
...@@ -22,10 +23,14 @@ ...@@ -22,10 +23,14 @@
#include "imx-drm.h" #include "imx-drm.h"
struct imx_parallel_display { struct imx_parallel_display_encoder {
struct drm_connector connector; struct drm_connector connector;
struct drm_encoder encoder; struct drm_encoder encoder;
struct drm_bridge bridge; struct drm_bridge bridge;
struct imx_parallel_display *pd;
};
struct imx_parallel_display {
struct device *dev; struct device *dev;
void *edid; void *edid;
u32 bus_format; u32 bus_format;
...@@ -37,12 +42,12 @@ struct imx_parallel_display { ...@@ -37,12 +42,12 @@ struct imx_parallel_display {
static inline struct imx_parallel_display *con_to_imxpd(struct drm_connector *c) static inline struct imx_parallel_display *con_to_imxpd(struct drm_connector *c)
{ {
return container_of(c, struct imx_parallel_display, connector); return container_of(c, struct imx_parallel_display_encoder, connector)->pd;
} }
static inline struct imx_parallel_display *bridge_to_imxpd(struct drm_bridge *b) static inline struct imx_parallel_display *bridge_to_imxpd(struct drm_bridge *b)
{ {
return container_of(b, struct imx_parallel_display, bridge); return container_of(b, struct imx_parallel_display_encoder, bridge)->pd;
} }
static int imx_pd_connector_get_modes(struct drm_connector *connector) static int imx_pd_connector_get_modes(struct drm_connector *connector)
...@@ -74,7 +79,7 @@ static int imx_pd_connector_get_modes(struct drm_connector *connector) ...@@ -74,7 +79,7 @@ static int imx_pd_connector_get_modes(struct drm_connector *connector)
return ret; return ret;
drm_mode_copy(mode, &imxpd->mode); drm_mode_copy(mode, &imxpd->mode);
mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
drm_mode_probed_add(connector, mode); drm_mode_probed_add(connector, mode);
num_modes++; num_modes++;
} }
...@@ -253,12 +258,26 @@ static const struct drm_bridge_funcs imx_pd_bridge_funcs = { ...@@ -253,12 +258,26 @@ static const struct drm_bridge_funcs imx_pd_bridge_funcs = {
.atomic_get_output_bus_fmts = imx_pd_bridge_atomic_get_output_bus_fmts, .atomic_get_output_bus_fmts = imx_pd_bridge_atomic_get_output_bus_fmts,
}; };
static int imx_pd_register(struct drm_device *drm, static int imx_pd_bind(struct device *dev, struct device *master, void *data)
struct imx_parallel_display *imxpd)
{ {
struct drm_encoder *encoder = &imxpd->encoder; struct drm_device *drm = data;
struct imx_parallel_display *imxpd = dev_get_drvdata(dev);
struct imx_parallel_display_encoder *imxpd_encoder;
struct drm_connector *connector;
struct drm_encoder *encoder;
struct drm_bridge *bridge;
int ret; int ret;
imxpd_encoder = drmm_simple_encoder_alloc(drm, struct imx_parallel_display_encoder,
encoder, DRM_MODE_ENCODER_NONE);
if (IS_ERR(imxpd_encoder))
return PTR_ERR(imxpd_encoder);
imxpd_encoder->pd = imxpd;
connector = &imxpd_encoder->connector;
encoder = &imxpd_encoder->encoder;
bridge = &imxpd_encoder->bridge;
ret = imx_drm_encoder_parse_of(drm, encoder, imxpd->dev->of_node); ret = imx_drm_encoder_parse_of(drm, encoder, imxpd->dev->of_node);
if (ret) if (ret)
return ret; return ret;
...@@ -268,39 +287,37 @@ static int imx_pd_register(struct drm_device *drm, ...@@ -268,39 +287,37 @@ static int imx_pd_register(struct drm_device *drm,
* immediately since the current state is ON * immediately since the current state is ON
* at this point. * at this point.
*/ */
imxpd->connector.dpms = DRM_MODE_DPMS_OFF; connector->dpms = DRM_MODE_DPMS_OFF;
drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_NONE);
imxpd->bridge.funcs = &imx_pd_bridge_funcs;
drm_bridge_attach(encoder, &imxpd->bridge, NULL, 0);
if (!imxpd->next_bridge) { bridge->funcs = &imx_pd_bridge_funcs;
drm_connector_helper_add(&imxpd->connector, drm_bridge_attach(encoder, bridge, NULL, 0);
&imx_pd_connector_helper_funcs);
drm_connector_init(drm, &imxpd->connector,
&imx_pd_connector_funcs,
DRM_MODE_CONNECTOR_DPI);
}
if (imxpd->next_bridge) { if (imxpd->next_bridge) {
ret = drm_bridge_attach(encoder, imxpd->next_bridge, ret = drm_bridge_attach(encoder, imxpd->next_bridge, bridge, 0);
&imxpd->bridge, 0);
if (ret < 0) { if (ret < 0) {
dev_err(imxpd->dev, "failed to attach bridge: %d\n", dev_err(imxpd->dev, "failed to attach bridge: %d\n",
ret); ret);
return ret; return ret;
} }
} else { } else {
drm_connector_attach_encoder(&imxpd->connector, encoder); drm_connector_helper_add(connector,
&imx_pd_connector_helper_funcs);
drm_connector_init(drm, connector, &imx_pd_connector_funcs,
DRM_MODE_CONNECTOR_DPI);
drm_connector_attach_encoder(connector, encoder);
} }
return 0; return 0;
} }
static int imx_pd_bind(struct device *dev, struct device *master, void *data) static const struct component_ops imx_pd_ops = {
.bind = imx_pd_bind,
};
static int imx_pd_probe(struct platform_device *pdev)
{ {
struct drm_device *drm = data; struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node; struct device_node *np = dev->of_node;
const u8 *edidp; const u8 *edidp;
struct imx_parallel_display *imxpd; struct imx_parallel_display *imxpd;
...@@ -309,8 +326,9 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data) ...@@ -309,8 +326,9 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data)
u32 bus_format = 0; u32 bus_format = 0;
const char *fmt; const char *fmt;
imxpd = dev_get_drvdata(dev); imxpd = devm_kzalloc(dev, sizeof(*imxpd), GFP_KERNEL);
memset(imxpd, 0, sizeof(*imxpd)); if (!imxpd)
return -ENOMEM;
/* port@1 is the output port */ /* port@1 is the output port */
ret = drm_of_find_panel_or_bridge(np, 1, 0, &imxpd->panel, ret = drm_of_find_panel_or_bridge(np, 1, 0, &imxpd->panel,
...@@ -337,28 +355,9 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data) ...@@ -337,28 +355,9 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data)
imxpd->dev = dev; imxpd->dev = dev;
ret = imx_pd_register(drm, imxpd);
if (ret)
return ret;
return 0;
}
static const struct component_ops imx_pd_ops = {
.bind = imx_pd_bind,
};
static int imx_pd_probe(struct platform_device *pdev)
{
struct imx_parallel_display *imxpd;
imxpd = devm_kzalloc(&pdev->dev, sizeof(*imxpd), GFP_KERNEL);
if (!imxpd)
return -ENOMEM;
platform_set_drvdata(pdev, imxpd); platform_set_drvdata(pdev, imxpd);
return component_add(&pdev->dev, &imx_pd_ops); return component_add(dev, &imx_pd_ops);
} }
static int imx_pd_remove(struct platform_device *pdev) static int imx_pd_remove(struct platform_device *pdev)
......
...@@ -310,10 +310,6 @@ static void ipu_di_sync_config_noninterlaced(struct ipu_di *di, ...@@ -310,10 +310,6 @@ static void ipu_di_sync_config_noninterlaced(struct ipu_di *di,
/* unused */ /* unused */
} , { } , {
/* unused */ /* unused */
} , {
/* unused */
} , {
/* unused */
}, },
}; };
/* can't use #7 and #8 for line active and pixel active counters */ /* can't use #7 and #8 for line active and pixel active counters */
......
...@@ -1223,6 +1223,39 @@ int drm_crtc_init_with_planes(struct drm_device *dev, ...@@ -1223,6 +1223,39 @@ int drm_crtc_init_with_planes(struct drm_device *dev,
const char *name, ...); const char *name, ...);
void drm_crtc_cleanup(struct drm_crtc *crtc); void drm_crtc_cleanup(struct drm_crtc *crtc);
__printf(7, 8)
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, ...);
/**
* drm_crtc_alloc_with_planes - Allocate and initialize a new CRTC object with
* specified primary and cursor planes.
* @dev: DRM device
* @type: the type of the struct which contains struct &drm_crtc
* @member: the name of the &drm_crtc within @type.
* @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
*
* Allocates and initializes a new crtc object. Cleanup is automatically
* handled through registering drmm_crtc_cleanup() with drmm_add_action().
*
* The @drm_crtc_funcs.destroy hook must be NULL.
*
* Returns:
* Pointer to new crtc, or ERR_PTR on failure.
*/
#define drmm_crtc_alloc_with_planes(dev, type, member, primary, cursor, funcs, name, ...) \
((type *)__drmm_crtc_alloc_with_planes(dev, sizeof(type), \
offsetof(type, member), \
primary, cursor, funcs, \
name, ##__VA_ARGS__))
/** /**
* drm_crtc_index - find the index of a registered CRTC * drm_crtc_index - find the index of a registered CRTC
* @crtc: CRTC to find index for * @crtc: CRTC to find index for
......
...@@ -89,7 +89,7 @@ struct drm_encoder_funcs { ...@@ -89,7 +89,7 @@ struct drm_encoder_funcs {
* @head: list management * @head: list management
* @base: base KMS object * @base: base KMS object
* @name: human readable name, can be overwritten by the driver * @name: human readable name, can be overwritten by the driver
* @funcs: control functions * @funcs: control functions, can be NULL for simple managed encoders
* @helper_private: mid-layer private data * @helper_private: mid-layer private data
* *
* CRTCs drive pixels to encoders, which convert them into signals * CRTCs drive pixels to encoders, which convert them into signals
...@@ -194,6 +194,36 @@ int drm_encoder_init(struct drm_device *dev, ...@@ -194,6 +194,36 @@ int drm_encoder_init(struct drm_device *dev,
const struct drm_encoder_funcs *funcs, const struct drm_encoder_funcs *funcs,
int encoder_type, const char *name, ...); int encoder_type, const char *name, ...);
__printf(6, 7)
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, ...);
/**
* drmm_encoder_alloc - Allocate and initialize an encoder
* @dev: drm device
* @type: the type of the struct which contains struct &drm_encoder
* @member: the name of the &drm_encoder within @type
* @funcs: callbacks for this encoder (optional)
* @encoder_type: user visible type of the encoder
* @name: printf style format string for the encoder name, or NULL for default name
*
* Allocates and initializes an encoder. Encoder should be subclassed as part of
* driver encoder objects. Cleanup is automatically handled through registering
* drm_encoder_cleanup() with drmm_add_action().
*
* The @drm_encoder_funcs.destroy hook must be NULL.
*
* Returns:
* Pointer to new encoder, or ERR_PTR on failure.
*/
#define drmm_encoder_alloc(dev, type, member, funcs, encoder_type, name, ...) \
((type *)__drmm_encoder_alloc(dev, sizeof(type), \
offsetof(type, member), funcs, \
encoder_type, name, ##__VA_ARGS__))
/** /**
* drm_encoder_index - find the index of a registered encoder * drm_encoder_index - find the index of a registered encoder
* @encoder: encoder to find index for * @encoder: encoder to find index for
......
...@@ -764,6 +764,48 @@ int drm_plane_init(struct drm_device *dev, ...@@ -764,6 +764,48 @@ int drm_plane_init(struct drm_device *dev,
bool is_primary); bool is_primary);
void drm_plane_cleanup(struct drm_plane *plane); void drm_plane_cleanup(struct drm_plane *plane);
__printf(10, 11)
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 plane_type,
const char *name, ...);
/**
* drmm_universal_plane_alloc - Allocate and initialize an universal plane object
* @dev: DRM device
* @type: the type of the struct which contains struct &drm_plane
* @member: the name of the &drm_plane within @type
* @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
* @plane_type: type of plane (overlay, primary, cursor)
* @name: printf style format string for the plane name, or NULL for default name
*
* Allocates and initializes a plane object of type @type. Cleanup is
* automatically handled through registering drm_plane_cleanup() with
* drmm_add_action().
*
* The @drm_plane_funcs.destroy hook must be NULL.
*
* Returns:
* Pointer to new plane, or ERR_PTR on failure.
*/
#define drmm_universal_plane_alloc(dev, type, member, possible_crtcs, funcs, formats, \
format_count, format_modifiers, plane_type, name, ...) \
((type *)__drmm_universal_plane_alloc(dev, sizeof(type), \
offsetof(type, member), \
possible_crtcs, funcs, formats, \
format_count, format_modifiers, \
plane_type, name, ##__VA_ARGS__))
/** /**
* drm_plane_index - find the index of a registered plane * drm_plane_index - find the index of a registered plane
* @plane: plane to find index for * @plane: plane to find index for
......
...@@ -185,4 +185,28 @@ int drm_simple_encoder_init(struct drm_device *dev, ...@@ -185,4 +185,28 @@ int drm_simple_encoder_init(struct drm_device *dev,
struct drm_encoder *encoder, struct drm_encoder *encoder,
int encoder_type); int encoder_type);
void *__drmm_simple_encoder_alloc(struct drm_device *dev, size_t size,
size_t offset, int encoder_type);
/**
* drmm_simple_encoder_alloc - Allocate and initialize an encoder with basic
* functionality.
* @dev: drm device
* @type: the type of the struct which contains struct &drm_encoder
* @member: the name of the &drm_encoder within @type.
* @encoder_type: user visible type of the encoder
*
* Allocates and initializes an encoder that has no further functionality.
* Settings for possible CRTC and clones are left to their initial values.
* Cleanup is automatically handled through registering drm_encoder_cleanup()
* with drmm_add_action().
*
* Returns:
* Pointer to new encoder, or ERR_PTR on failure.
*/
#define drmm_simple_encoder_alloc(dev, type, member, encoder_type) \
((type *)__drmm_simple_encoder_alloc(dev, sizeof(type), \
offsetof(type, member), \
encoder_type))
#endif /* __LINUX_DRM_SIMPLE_KMS_HELPER_H */ #endif /* __LINUX_DRM_SIMPLE_KMS_HELPER_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment