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.
-----BEGIN PGP SIGNATURE-----
iI0EABYIADUWIQRRO6F6WdpH1R0vGibVhaclGDdiwAUCX/M62RcccC56YWJlbEBw
ZW5ndXRyb25peC5kZQAKCRDVhaclGDdiwPdlAP4/zZ401iFrj+ZiRTYFNGHaRrBI
ldQ97lk2Ndzgp5tHzQD/dsAMFymw5+fYlp2xa25kB4LQJLzOC+KzlZwFKF5W4QM=
=I3bV
-----END PGP SIGNATURE-----
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: Daniel Vetter <daniel.vetter@intel.com>
[danvet: Fix conflict between doc changes by both Philipp and Simon
Ser, see 9999587b68
("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
This commit is contained in:
commit
e240cc7665
|
@ -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,
|
||||
struct drm_plane *primary,
|
||||
struct drm_plane *cursor,
|
||||
const struct drm_crtc_funcs *funcs,
|
||||
const char *name, ...)
|
||||
__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, 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
|
||||
|
|
|
@ -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,
|
||||
struct drm_encoder *encoder,
|
||||
const struct drm_encoder_funcs *funcs,
|
||||
int encoder_type, const char *name, ...)
|
||||
__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, 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 @@ out_put:
|
|||
|
||||
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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 @@ done:
|
|||
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,
|
||||
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, ...)
|
||||
__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 uint64_t *format_modifiers,
|
||||
enum drm_plane_type type,
|
||||
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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -28,6 +28,7 @@ config DRM_IMX_TVE
|
|||
config DRM_IMX_LDB
|
||||
tristate "Support for LVDS displays"
|
||||
depends on DRM_IMX && MFD_SYSCON
|
||||
depends on COMMON_CLK
|
||||
select DRM_PANEL
|
||||
help
|
||||
Choose this to enable the internal LVDS Display Bridge (LDB)
|
||||
|
|
|
@ -15,23 +15,32 @@
|
|||
|
||||
#include <drm/bridge/dw_hdmi.h>
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_bridge.h>
|
||||
#include <drm/drm_edid.h>
|
||||
#include <drm/drm_encoder.h>
|
||||
#include <drm/drm_managed.h>
|
||||
#include <drm/drm_of.h>
|
||||
#include <drm/drm_simple_kms_helper.h>
|
||||
|
||||
#include "imx-drm.h"
|
||||
|
||||
struct imx_hdmi;
|
||||
|
||||
struct imx_hdmi_encoder {
|
||||
struct drm_encoder encoder;
|
||||
struct imx_hdmi *hdmi;
|
||||
};
|
||||
|
||||
struct imx_hdmi {
|
||||
struct device *dev;
|
||||
struct drm_encoder encoder;
|
||||
struct drm_bridge *bridge;
|
||||
struct dw_hdmi *hdmi;
|
||||
struct regmap *regmap;
|
||||
};
|
||||
|
||||
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[] = {
|
||||
|
@ -98,19 +107,6 @@ static const struct dw_hdmi_phy_config imx_phy_config[] = {
|
|||
{ ~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)
|
||||
{
|
||||
struct imx_hdmi *hdmi = enc_to_imx_hdmi(encoder);
|
||||
|
@ -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,
|
||||
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 imx_hdmi_encoder *hdmi_encoder;
|
||||
struct drm_encoder *encoder;
|
||||
struct imx_hdmi *hdmi;
|
||||
int ret;
|
||||
|
||||
if (!pdev->dev.of_node)
|
||||
return -ENODEV;
|
||||
hdmi_encoder = drmm_simple_encoder_alloc(drm, struct imx_hdmi_encoder,
|
||||
encoder, DRM_MODE_ENCODER_TMDS);
|
||||
if (IS_ERR(hdmi_encoder))
|
||||
return PTR_ERR(hdmi_encoder);
|
||||
|
||||
hdmi = dev_get_drvdata(dev);
|
||||
memset(hdmi, 0, sizeof(*hdmi));
|
||||
|
||||
match = of_match_node(dw_hdmi_imx_dt_ids, pdev->dev.of_node);
|
||||
plat_data = match->data;
|
||||
hdmi->dev = &pdev->dev;
|
||||
encoder = &hdmi->encoder;
|
||||
hdmi_encoder->hdmi = dev_get_drvdata(dev);
|
||||
encoder = &hdmi_encoder->encoder;
|
||||
|
||||
ret = imx_drm_encoder_parse_of(drm, encoder, dev->of_node);
|
||||
if (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_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
|
||||
|
||||
hdmi->hdmi = dw_hdmi_bind(pdev, encoder, plat_data);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
return drm_bridge_attach(encoder, hdmi_encoder->hdmi->bridge, NULL, 0);
|
||||
}
|
||||
|
||||
static const struct component_ops dw_hdmi_imx_ops = {
|
||||
.bind = dw_hdmi_imx_bind,
|
||||
.unbind = dw_hdmi_imx_unbind,
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
|
||||
|
@ -261,13 +228,33 @@ static int dw_hdmi_imx_probe(struct platform_device *pdev)
|
|||
return -ENOMEM;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
dw_hdmi_remove(hdmi->hdmi);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_bridge.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
#include <drm/drm_managed.h>
|
||||
#include <drm/drm_of.h>
|
||||
#include <drm/drm_panel.h>
|
||||
#include <drm/drm_print.h>
|
||||
|
@ -47,12 +48,18 @@
|
|||
#define LDB_DI1_VS_POL_ACT_LOW (1 << 10)
|
||||
#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_channel {
|
||||
struct imx_ldb *ldb;
|
||||
struct drm_connector connector;
|
||||
struct drm_encoder encoder;
|
||||
|
||||
/* Defines what is connected to the ldb, only one at a time */
|
||||
struct drm_panel *panel;
|
||||
|
@ -70,12 +77,12 @@ struct imx_ldb_channel {
|
|||
|
||||
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)
|
||||
{
|
||||
return container_of(e, struct imx_ldb_channel, encoder);
|
||||
return container_of(e, struct imx_ldb_encoder, encoder)->channel;
|
||||
}
|
||||
|
||||
struct bus_mux {
|
||||
|
@ -411,9 +418,20 @@ static int imx_ldb_register(struct drm_device *drm,
|
|||
struct imx_ldb_channel *imx_ldb_ch)
|
||||
{
|
||||
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;
|
||||
|
||||
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);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -429,11 +447,9 @@ static int imx_ldb_register(struct drm_device *drm,
|
|||
}
|
||||
|
||||
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) {
|
||||
ret = drm_bridge_attach(&imx_ldb_ch->encoder,
|
||||
imx_ldb_ch->bridge, NULL, 0);
|
||||
ret = drm_bridge_attach(encoder, imx_ldb_ch->bridge, NULL, 0);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to initialize bridge with drm\n");
|
||||
return ret;
|
||||
|
@ -445,13 +461,13 @@ static int imx_ldb_register(struct drm_device *drm,
|
|||
* historical reasons, the ldb driver can also work without
|
||||
* a panel.
|
||||
*/
|
||||
drm_connector_helper_add(&imx_ldb_ch->connector,
|
||||
&imx_ldb_connector_helper_funcs);
|
||||
drm_connector_init_with_ddc(drm, &imx_ldb_ch->connector,
|
||||
drm_connector_helper_add(connector,
|
||||
&imx_ldb_connector_helper_funcs);
|
||||
drm_connector_init_with_ddc(drm, connector,
|
||||
&imx_ldb_connector_funcs,
|
||||
DRM_MODE_CONNECTOR_LVDS,
|
||||
imx_ldb_ch->ddc);
|
||||
drm_connector_attach_encoder(&imx_ldb_ch->connector, encoder);
|
||||
drm_connector_attach_encoder(connector, encoder);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -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)
|
||||
{
|
||||
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;
|
||||
const struct of_device_id *of_id =
|
||||
of_match_device(imx_ldb_dt_ids, dev);
|
||||
const struct of_device_id *of_id = of_match_device(imx_ldb_dt_ids, dev);
|
||||
struct device_node *child;
|
||||
struct imx_ldb *imx_ldb;
|
||||
int dual;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
imx_ldb = dev_get_drvdata(dev);
|
||||
memset(imx_ldb, 0, sizeof(*imx_ldb));
|
||||
imx_ldb = devm_kzalloc(dev, sizeof(*imx_ldb), GFP_KERNEL);
|
||||
if (!imx_ldb)
|
||||
return -ENOMEM;
|
||||
|
||||
imx_ldb->regmap = syscon_regmap_lookup_by_phandle(np, "gpr");
|
||||
if (IS_ERR(imx_ldb->regmap)) {
|
||||
|
@ -669,25 +710,20 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
|
|||
}
|
||||
channel->bus_format = bus_format;
|
||||
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:
|
||||
of_node_put(child);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void imx_ldb_unbind(struct device *dev, struct device *master,
|
||||
void *data)
|
||||
static int imx_ldb_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct imx_ldb *imx_ldb = dev_get_drvdata(dev);
|
||||
struct imx_ldb *imx_ldb = platform_get_drvdata(pdev);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
|
@ -696,28 +732,7 @@ static void imx_ldb_unbind(struct device *dev, struct device *master,
|
|||
kfree(channel->edid);
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
#include <drm/drm_managed.h>
|
||||
#include <drm/drm_probe_helper.h>
|
||||
#include <drm/drm_simple_kms_helper.h>
|
||||
|
||||
|
@ -99,9 +100,13 @@ enum {
|
|||
TVE_MODE_VGA,
|
||||
};
|
||||
|
||||
struct imx_tve {
|
||||
struct imx_tve_encoder {
|
||||
struct drm_connector connector;
|
||||
struct drm_encoder encoder;
|
||||
struct imx_tve *tve;
|
||||
};
|
||||
|
||||
struct imx_tve {
|
||||
struct device *dev;
|
||||
int mode;
|
||||
int di_hsync_pin;
|
||||
|
@ -118,12 +123,12 @@ struct imx_tve {
|
|||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
|
@ -418,7 +423,7 @@ static int tve_clk_init(struct imx_tve *tve, void __iomem *base)
|
|||
init.parent_names = (const char **)&tve_di_parent;
|
||||
|
||||
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)) {
|
||||
dev_err(tve->dev, "failed to register TVE output clock: %ld\n",
|
||||
PTR_ERR(tve->di_clk));
|
||||
|
@ -428,33 +433,6 @@ static int tve_clk_init(struct imx_tve *tve, void __iomem *base)
|
|||
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)
|
||||
{
|
||||
struct imx_tve *tve = data;
|
||||
|
@ -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)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
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 *ddc_node;
|
||||
struct imx_tve *tve;
|
||||
|
@ -513,8 +532,9 @@ static int imx_tve_bind(struct device *dev, struct device *master, void *data)
|
|||
int irq;
|
||||
int ret;
|
||||
|
||||
tve = dev_get_drvdata(dev);
|
||||
memset(tve, 0, sizeof(*tve));
|
||||
tve = devm_kzalloc(dev, sizeof(*tve), GFP_KERNEL);
|
||||
if (!tve)
|
||||
return -ENOMEM;
|
||||
|
||||
tve->dev = dev;
|
||||
|
||||
|
@ -621,28 +641,9 @@ static int imx_tve_bind(struct device *dev, struct device *master, void *data)
|
|||
if (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);
|
||||
|
||||
return component_add(&pdev->dev, &imx_tve_ops);
|
||||
return component_add(dev, &imx_tve_ops);
|
||||
}
|
||||
|
||||
static int imx_tve_remove(struct platform_device *pdev)
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_fb_cma_helper.h>
|
||||
#include <drm/drm_gem_cma_helper.h>
|
||||
#include <drm/drm_managed.h>
|
||||
#include <drm/drm_probe_helper.h>
|
||||
#include <drm/drm_vblank.h>
|
||||
|
||||
|
@ -163,7 +164,6 @@ static void ipu_disable_vblank(struct drm_crtc *crtc)
|
|||
|
||||
static const struct drm_crtc_funcs ipu_crtc_funcs = {
|
||||
.set_config = drm_atomic_helper_set_config,
|
||||
.destroy = drm_crtc_cleanup,
|
||||
.page_flip = drm_atomic_helper_page_flip,
|
||||
.reset = imx_drm_crtc_reset,
|
||||
.atomic_duplicate_state = imx_drm_crtc_duplicate_state,
|
||||
|
@ -322,73 +322,73 @@ static const struct drm_crtc_helper_funcs ipu_helper_funcs = {
|
|||
.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))
|
||||
ipu_dc_put(ipu_crtc->dc);
|
||||
if (!IS_ERR_OR_NULL(ipu_crtc->di))
|
||||
ipu_di_put(ipu_crtc->di);
|
||||
}
|
||||
|
||||
static int ipu_get_resources(struct ipu_crtc *ipu_crtc,
|
||||
struct ipu_client_platformdata *pdata)
|
||||
static int ipu_get_resources(struct drm_device *dev, struct ipu_crtc *ipu_crtc,
|
||||
struct ipu_client_platformdata *pdata)
|
||||
{
|
||||
struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
|
||||
int ret;
|
||||
|
||||
ipu_crtc->dc = ipu_dc_get(ipu, pdata->dc);
|
||||
if (IS_ERR(ipu_crtc->dc)) {
|
||||
ret = PTR_ERR(ipu_crtc->dc);
|
||||
goto err_out;
|
||||
}
|
||||
if (IS_ERR(ipu_crtc->dc))
|
||||
return PTR_ERR(ipu_crtc->dc);
|
||||
|
||||
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);
|
||||
if (IS_ERR(ipu_crtc->di)) {
|
||||
ret = PTR_ERR(ipu_crtc->di);
|
||||
goto err_out;
|
||||
}
|
||||
if (IS_ERR(ipu_crtc->di))
|
||||
return PTR_ERR(ipu_crtc->di);
|
||||
|
||||
return 0;
|
||||
err_out:
|
||||
ipu_put_resources(ipu_crtc);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
|
||||
struct ipu_client_platformdata *pdata, struct drm_device *drm)
|
||||
static int ipu_drm_bind(struct device *dev, struct device *master, void *data)
|
||||
{
|
||||
struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
|
||||
struct drm_crtc *crtc = &ipu_crtc->base;
|
||||
struct ipu_client_platformdata *pdata = dev->platform_data;
|
||||
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 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)
|
||||
dp = IPU_DP_FLOW_SYNC_BG;
|
||||
ipu_crtc->plane[0] = ipu_plane_init(drm, ipu, pdata->dma[0], dp, 0,
|
||||
DRM_PLANE_TYPE_PRIMARY);
|
||||
if (IS_ERR(ipu_crtc->plane[0])) {
|
||||
ret = PTR_ERR(ipu_crtc->plane[0]);
|
||||
goto err_put_resources;
|
||||
}
|
||||
primary_plane = ipu_plane_init(drm, ipu, pdata->dma[0], dp, 0,
|
||||
DRM_PLANE_TYPE_PRIMARY);
|
||||
if (IS_ERR(primary_plane))
|
||||
return PTR_ERR(primary_plane);
|
||||
|
||||
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;
|
||||
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) {
|
||||
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);
|
||||
goto err_put_resources;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* 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,
|
|||
IPU_DP_FLOW_SYNC_FG,
|
||||
drm_crtc_mask(&ipu_crtc->base),
|
||||
DRM_PLANE_TYPE_OVERLAY);
|
||||
if (IS_ERR(ipu_crtc->plane[1])) {
|
||||
if (IS_ERR(ipu_crtc->plane[1]))
|
||||
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]);
|
||||
|
@ -414,58 +406,21 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
|
|||
"imx_drm", ipu_crtc);
|
||||
if (ret < 0) {
|
||||
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. */
|
||||
disable_irq(ipu_crtc->irq);
|
||||
|
||||
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 = {
|
||||
.bind = ipu_drm_bind,
|
||||
.unbind = ipu_drm_unbind,
|
||||
};
|
||||
|
||||
static int ipu_drm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct ipu_crtc *ipu_crtc;
|
||||
int ret;
|
||||
|
||||
if (!dev->platform_data)
|
||||
|
@ -475,12 +430,6 @@ static int ipu_drm_probe(struct platform_device *pdev)
|
|||
if (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);
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <drm/drm_fourcc.h>
|
||||
#include <drm/drm_gem_cma_helper.h>
|
||||
#include <drm/drm_gem_framebuffer_helper.h>
|
||||
#include <drm/drm_managed.h>
|
||||
#include <drm/drm_plane_helper.h>
|
||||
|
||||
#include <video/imx-ipu-v3.h>
|
||||
|
@ -142,8 +143,10 @@ drm_plane_state_to_vbo(struct drm_plane_state *state)
|
|||
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))
|
||||
ipu_dp_put(ipu_plane->dp);
|
||||
if (!IS_ERR_OR_NULL(ipu_plane->dmfc))
|
||||
|
@ -154,7 +157,8 @@ void ipu_plane_put_resources(struct ipu_plane *ipu_plane)
|
|||
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 alpha_ch;
|
||||
|
@ -166,6 +170,10 @@ int ipu_plane_get_resources(struct ipu_plane *ipu_plane)
|
|||
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);
|
||||
if (alpha_ch >= 0) {
|
||||
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)
|
|||
if (IS_ERR(ipu_plane->dmfc)) {
|
||||
ret = PTR_ERR(ipu_plane->dmfc);
|
||||
DRM_ERROR("failed to get dmfc: ret %d\n", ret);
|
||||
goto err_out;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ipu_plane->dp_flow >= 0) {
|
||||
|
@ -189,15 +197,11 @@ int ipu_plane_get_resources(struct ipu_plane *ipu_plane)
|
|||
if (IS_ERR(ipu_plane->dp)) {
|
||||
ret = PTR_ERR(ipu_plane->dp);
|
||||
DRM_ERROR("failed to get dp flow: %d\n", ret);
|
||||
goto err_out;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
err_out:
|
||||
ipu_plane_put_resources(ipu_plane);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool ipu_plane_separate_alpha(struct ipu_plane *ipu_plane)
|
||||
|
@ -262,16 +266,6 @@ void ipu_plane_disable_deferred(struct drm_plane *plane)
|
|||
}
|
||||
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)
|
||||
{
|
||||
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,
|
|||
static const struct drm_plane_funcs ipu_plane_funcs = {
|
||||
.update_plane = drm_atomic_helper_update_plane,
|
||||
.disable_plane = drm_atomic_helper_disable_plane,
|
||||
.destroy = ipu_plane_destroy,
|
||||
.reset = ipu_plane_state_reset,
|
||||
.atomic_duplicate_state = ipu_plane_duplicate_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,
|
|||
DRM_DEBUG_KMS("channel %d, dp flow %d, possible_crtcs=0x%x\n",
|
||||
dma, dp, possible_crtcs);
|
||||
|
||||
ipu_plane = kzalloc(sizeof(*ipu_plane), GFP_KERNEL);
|
||||
if (!ipu_plane) {
|
||||
DRM_ERROR("failed to allocate plane\n");
|
||||
return ERR_PTR(-ENOMEM);
|
||||
ipu_plane = drmm_universal_plane_alloc(dev, struct ipu_plane, base,
|
||||
possible_crtcs, &ipu_plane_funcs,
|
||||
ipu_plane_formats,
|
||||
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;
|
||||
|
@ -847,22 +845,23 @@ struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
|
|||
if (ipu_prg_present(ipu))
|
||||
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);
|
||||
|
||||
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
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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_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);
|
||||
|
||||
void ipu_plane_disable(struct ipu_plane *ipu_plane, bool disable_dp_channel);
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_bridge.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
#include <drm/drm_managed.h>
|
||||
#include <drm/drm_of.h>
|
||||
#include <drm/drm_panel.h>
|
||||
#include <drm/drm_probe_helper.h>
|
||||
|
@ -22,10 +23,14 @@
|
|||
|
||||
#include "imx-drm.h"
|
||||
|
||||
struct imx_parallel_display {
|
||||
struct imx_parallel_display_encoder {
|
||||
struct drm_connector connector;
|
||||
struct drm_encoder encoder;
|
||||
struct drm_bridge bridge;
|
||||
struct imx_parallel_display *pd;
|
||||
};
|
||||
|
||||
struct imx_parallel_display {
|
||||
struct device *dev;
|
||||
void *edid;
|
||||
u32 bus_format;
|
||||
|
@ -37,12 +42,12 @@ struct imx_parallel_display {
|
|||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
|
@ -74,7 +79,7 @@ static int imx_pd_connector_get_modes(struct drm_connector *connector)
|
|||
return ret;
|
||||
|
||||
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);
|
||||
num_modes++;
|
||||
}
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
static int imx_pd_register(struct drm_device *drm,
|
||||
struct imx_parallel_display *imxpd)
|
||||
static int imx_pd_bind(struct device *dev, struct device *master, void *data)
|
||||
{
|
||||
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;
|
||||
|
||||
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);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -268,39 +287,37 @@ static int imx_pd_register(struct drm_device *drm,
|
|||
* immediately since the current state is ON
|
||||
* 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) {
|
||||
drm_connector_helper_add(&imxpd->connector,
|
||||
&imx_pd_connector_helper_funcs);
|
||||
drm_connector_init(drm, &imxpd->connector,
|
||||
&imx_pd_connector_funcs,
|
||||
DRM_MODE_CONNECTOR_DPI);
|
||||
}
|
||||
bridge->funcs = &imx_pd_bridge_funcs;
|
||||
drm_bridge_attach(encoder, bridge, NULL, 0);
|
||||
|
||||
if (imxpd->next_bridge) {
|
||||
ret = drm_bridge_attach(encoder, imxpd->next_bridge,
|
||||
&imxpd->bridge, 0);
|
||||
ret = drm_bridge_attach(encoder, imxpd->next_bridge, bridge, 0);
|
||||
if (ret < 0) {
|
||||
dev_err(imxpd->dev, "failed to attach bridge: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
|
||||
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;
|
||||
const u8 *edidp;
|
||||
struct imx_parallel_display *imxpd;
|
||||
|
@ -309,8 +326,9 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data)
|
|||
u32 bus_format = 0;
|
||||
const char *fmt;
|
||||
|
||||
imxpd = dev_get_drvdata(dev);
|
||||
memset(imxpd, 0, sizeof(*imxpd));
|
||||
imxpd = devm_kzalloc(dev, sizeof(*imxpd), GFP_KERNEL);
|
||||
if (!imxpd)
|
||||
return -ENOMEM;
|
||||
|
||||
/* port@1 is the output port */
|
||||
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)
|
|||
|
||||
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);
|
||||
|
||||
return component_add(&pdev->dev, &imx_pd_ops);
|
||||
return component_add(dev, &imx_pd_ops);
|
||||
}
|
||||
|
||||
static int imx_pd_remove(struct platform_device *pdev)
|
||||
|
|
|
@ -310,10 +310,6 @@ static void ipu_di_sync_config_noninterlaced(struct ipu_di *di,
|
|||
/* unused */
|
||||
} , {
|
||||
/* unused */
|
||||
} , {
|
||||
/* unused */
|
||||
} , {
|
||||
/* unused */
|
||||
},
|
||||
};
|
||||
/* 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,
|
|||
const char *name, ...);
|
||||
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
|
||||
* @crtc: CRTC to find index for
|
||||
|
|
|
@ -89,7 +89,7 @@ struct drm_encoder_funcs {
|
|||
* @head: list management
|
||||
* @base: base KMS object
|
||||
* @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
|
||||
*
|
||||
* CRTCs drive pixels to encoders, which convert them into signals
|
||||
|
@ -194,6 +194,36 @@ int drm_encoder_init(struct drm_device *dev,
|
|||
const struct drm_encoder_funcs *funcs,
|
||||
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
|
||||
* @encoder: encoder to find index for
|
||||
|
|
|
@ -764,6 +764,48 @@ int drm_plane_init(struct drm_device *dev,
|
|||
bool is_primary);
|
||||
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
|
||||
* @plane: plane to find index for
|
||||
|
|
|
@ -185,4 +185,28 @@ int drm_simple_encoder_init(struct drm_device *dev,
|
|||
struct drm_encoder *encoder,
|
||||
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 */
|
||||
|
|
Loading…
Reference in New Issue