[RFC PATCH v2 1/5] video: display: add event handling, set mode and hdmi ops to cdf core

Rahul Sharma rahul.sharma at samsung.com
Thu Feb 7 03:59:33 PST 2013


This patch adds
1) Event Notification to CDF Core:
	Adds simple event notification mechanism supports multiple
	subscribers. This is used for hot-plug notification to the clients
	of hdmi display i.e. exynos-drm and alsa-codec. CDF Core maintains
	multiple subscriber list. When entity reports a event Core will
	route it to all of them. Un-superscription is not implemented which
	can be done if notification callback is Null.

2) set_mode to generic ops:
	It is meaningful for a panel like hdmi which supports multiple
	resolutions.

	HDMI needs conversion of Display Modes to Standard Display Timings.
	Though, it can be done within the driver but seems more meaningful
	if set_mode is called with Timing Details provided by CDF Core.

3) Provision for platform specific interfaces through void *private in display
entity:

	It has added void *private to display entity which can be used to
	expose interfaces which are very much specific to a particular platform.

	In exynos, hpd is connected to the soc via gpio bus. During initial
	hdmi poweron, hpd interrupt is not raised as there is no change in the
	gpio status. This is solved by providing a platform specific interface
	which is queried by the drm to get the hpd state. This interface may
	not be required by all platforms.

4) hdmi ops:
	get_edid: to query raw EDID data and length from the panel.
	check_mode: To check if a given mode is supported by exynos HDMI IP
			"AND" Connected HDMI Sink (tv/monitor).
	init_audio: Configure hdmi audio registers for Audio interface type
	(i2s/ spdif), SF, Audio Channels, BPS.
	set_audiostate: enable disable audio.

Signed-off-by: Rahul Sharma <rahul.sharma at samsung.com>
---
 drivers/video/display/display-core.c |  85 +++++++++++++++++++++++++++
 include/video/display.h              | 111 ++++++++++++++++++++++++++++++++++-
 2 files changed, 193 insertions(+), 3 deletions(-)

diff --git a/drivers/video/display/display-core.c b/drivers/video/display/display-core.c
index 55a7399..12fb882 100644
--- a/drivers/video/display/display-core.c
+++ b/drivers/video/display/display-core.c
@@ -99,6 +99,14 @@ int display_entity_get_modes(struct display_entity *entity,
 }
 EXPORT_SYMBOL_GPL(display_entity_get_modes);
 
+int display_entity_set_mode(struct display_entity *entity,
+		   const struct videomode *mode)
+{
+	if (!entity->opt_ctrl.hdmi || !entity->ops.ctrl->set_mode)
+		return 0;
+	return entity->ops.ctrl->set_mode(entity, mode);
+}
+EXPORT_SYMBOL_GPL(display_entity_set_mode);
 /**
 * display_entity_get_size - Get display entity physical size
 * @entity: The display entity
@@ -140,6 +148,37 @@ int display_entity_get_params(struct display_entity *entity,
 }
 EXPORT_SYMBOL_GPL(display_entity_get_params);
 
+int display_entity_subscribe_event(struct display_entity *entity,
+		struct display_event_subscriber *subscriber)
+{
+	if (!entity || !subscriber || !subscriber->notify)
+		return -EINVAL;
+
+	mutex_lock(&entity->entity_mutex);
+	list_add_tail(&subscriber->list, &entity->list_subscribers);
+	mutex_unlock(&entity->entity_mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(display_entity_subscribe_event);
+
+int display_entity_notify_event_subscriber(struct display_entity *entity,
+		enum display_entity_event_type type, unsigned int value)
+{
+	struct display_event_subscriber *subscriber;
+
+	if (!entity || type < 0)
+		return -EINVAL;
+
+	mutex_lock(&entity->entity_mutex);
+	list_for_each_entry(subscriber, &entity->list_subscribers, list) {
+		subscriber->notify(entity, type, value, subscriber->context);
+	}
+	mutex_unlock(&entity->entity_mutex);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(display_entity_notify_event_subscriber);
+
 /* -----------------------------------------------------------------------------
 * Video operations
 */
@@ -312,6 +351,9 @@ int __must_check __display_entity_register(struct display_entity *entity,
 	kref_init(&entity->ref);
 	entity->owner = owner;
 	entity->state = DISPLAY_ENTITY_STATE_OFF;
+	entity->list_subscribers.next = &entity->list_subscribers;
+	entity->list_subscribers.prev = &entity->list_subscribers;
+	mutex_init(&entity->entity_mutex);
 
 	mutex_lock(&display_entity_mutex);
 	list_add(&entity->list, &display_entity_list);
@@ -357,6 +399,49 @@ void display_entity_unregister(struct display_entity *entity)
 }
 EXPORT_SYMBOL_GPL(display_entity_unregister);
 
+/* -----------------------------------------------------------------------------
+ * Display Entity Hdmi ops
+ */
+
+int display_entity_hdmi_get_edid(struct display_entity *entity,
+			struct display_entity_edid *edid)
+{
+	if (!entity->opt_ctrl.hdmi || !entity->opt_ctrl.hdmi->get_edid)
+		return 0;
+
+	return entity->opt_ctrl.hdmi->get_edid(entity, edid);
+}
+EXPORT_SYMBOL_GPL(display_entity_hdmi_get_edid);
+
+int display_entity_hdmi_check_mode(struct display_entity *entity,
+		   const struct videomode *mode)
+{
+	if (!entity->opt_ctrl.hdmi || !entity->opt_ctrl.hdmi->check_mode)
+		return 0;
+
+	return entity->opt_ctrl.hdmi->check_mode(entity, mode);
+}
+EXPORT_SYMBOL_GPL(display_entity_hdmi_check_mode);
+
+int display_entity_hdmi_init_audio(struct display_entity *entity,
+		const struct display_entity_audio_params *params)
+{
+	if (!entity->opt_ctrl.hdmi || !entity->opt_ctrl.hdmi->init_audio)
+		return 0;
+
+	return entity->opt_ctrl.hdmi->init_audio(entity, params);
+}
+EXPORT_SYMBOL_GPL(display_entity_hdmi_init_audio);
+
+int display_entity_hdmi_set_audiostate(struct display_entity *entity,
+	enum display_entity_audiostate state)
+{
+	if (!entity->opt_ctrl.hdmi || !entity->opt_ctrl.hdmi->set_audiostate)
+		return 0;
+
+	return entity->opt_ctrl.hdmi->set_audiostate(entity, state);
+}
+EXPORT_SYMBOL_GPL(display_entity_hdmi_set_audiostate);
 MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart at ideasonboard.com>");
 MODULE_DESCRIPTION("Display Core");
 MODULE_LICENSE("GPL");
diff --git a/include/video/display.h b/include/video/display.h
index 817f4ae..eae373f 100644
--- a/include/video/display.h
+++ b/include/video/display.h
@@ -66,22 +66,64 @@ enum display_entity_stream_state {
 	DISPLAY_ENTITY_STREAM_CONTINUOUS,
 };
 
+enum display_entity_event_type {
+	DISPLAY_ENTITY_HDMI_HOTPLUG,
+};
+
 enum display_entity_interface_type {
 	DISPLAY_ENTITY_INTERFACE_DPI,
+	DISPLAY_ENTITY_INTERFACE_HDMI,
+};
+
+enum display_entity_audio_interface {
+	DISPLAY_ENTITY_AUDIO_I2S,
+	DISPLAY_ENTITY_AUDIO_SPDIF,
+};
+
+enum display_entity_audiostate {
+	DISPLAY_ENTITY_AUDIOSTATE_OFF,
+	DISPLAY_ENTITY_AUDIOSTATE_ON,
 };
 
 struct display_entity_interface_params {
 	enum display_entity_interface_type type;
 };
 
+struct display_event_subscriber {
+	struct list_head list;
+	void(*notify)(struct display_entity *ent,
+		enum display_entity_event_type type,
+		unsigned int value, void *context);
+	void *context;
+};
+
+struct display_entity_edid {
+	u8		*edid;
+	int		len;
+};
+
+struct display_entity_audio_params {
+	enum display_entity_audio_interface	type;
+	int	channels;
+	int	sf;
+	int	bits_per_sample;
+};
+
 struct display_entity_control_ops {
 	int (*set_state)(struct display_entity *ent,
 			enum display_entity_state state);
+
 	int (*update)(struct display_entity *ent);
+
 	int (*get_modes)(struct display_entity *ent,
 			const struct videomode **modes);
+
+	int (*set_mode)(struct display_entity *entity,
+		const struct videomode *modes);
+
 	int (*get_params)(struct display_entity *ent,
 			struct display_entity_interface_params *params);
+
 	int (*get_size)(struct display_entity *ent,
 			unsigned int *width, unsigned int *height);
 };
@@ -91,8 +133,29 @@ struct display_entity_video_ops {
 			enum display_entity_stream_state state);
 };
 
+struct display_entity_hdmi_control_ops {
+
+	int (*get_edid)(struct display_entity *ent,
+		struct display_entity_edid *edid);
+
+	int (*check_mode)(struct display_entity *entity,
+		const struct videomode *modes);
+
+	int (*init_audio)(struct display_entity *entity,
+		const struct display_entity_audio_params *params);
+
+	int (*set_audiostate)(struct display_entity *entity,
+		enum display_entity_audiostate state);
+};
+
+struct display_entity_hdmi_video_ops {
+	int (*get_edid)(struct display_entity *ent,
+			    enum display_entity_stream_state state);
+};
+
 struct display_entity {
 	struct list_head list;
+	struct list_head list_subscribers;
 	struct device *dev;
 	struct module *owner;
 	struct kref ref;
@@ -104,26 +167,51 @@ struct display_entity {
 		const struct display_entity_video_ops *video;
 	} ops;
 
+	union {
+		const struct display_entity_hdmi_control_ops *hdmi;
+	} opt_ctrl;
+
+	union {
+		const struct display_entity_hdmi_video_ops *hdmi;
+	} opt_video;
+
 	void(*release)(struct display_entity *ent);
 
 	enum display_entity_state state;
+	struct mutex	entity_mutex;
+	void		*private;
 };
 
+/* generic display entity ops */
+
 int display_entity_set_state(struct display_entity *entity,
 				enum display_entity_state state);
+
 int display_entity_update(struct display_entity *entity);
+
 int display_entity_get_modes(struct display_entity *entity,
 				const struct videomode **modes);
+
+int display_entity_set_mode(struct display_entity *entity,
+		const struct videomode *modes);
+
 int display_entity_get_params(struct display_entity *entity,
-				struct display_entity_interface_params *params);
+		struct display_entity_interface_params *params);
+
 int display_entity_get_size(struct display_entity *entity,
-			unsigned int *width, unsigned int *height);
+		unsigned int *width, unsigned int *height);
 
 int display_entity_set_stream(struct display_entity *entity,
 				enum display_entity_stream_state state);
 
+int display_entity_subscribe_event(struct display_entity *entity,
+		struct display_event_subscriber *subscriber);
+
+int display_entity_notify_event_subscriber(struct display_entity *entity,
+		enum display_entity_event_type type, unsigned int value);
+
 static inline void display_entity_connect(struct display_entity *source,
-					struct display_entity *sink)
+				struct display_entity *sink)
 {
 	sink->source = source;
 }
@@ -147,4 +235,21 @@ void display_entity_unregister_notifier(struct display_entity_notifier *notifier
 #define display_entity_register(display_entity) \
 	__display_entity_register(display_entity, THIS_MODULE)
 
+/* hdmi ops */
+
+int display_entity_hdmi_get_edid(struct display_entity *entity,
+		struct display_entity_edid *edid);
+
+int display_entity_hdmi_check_mode(struct display_entity *entity,
+		const struct videomode *modes);
+
+int display_entity_hdmi_get_hpdstate(struct display_entity *entity,
+			unsigned int *hpd_state);
+
+int display_entity_hdmi_init_audio(struct display_entity *entity,
+	const struct display_entity_audio_params *params);
+
+int display_entity_hdmi_set_audiostate(struct display_entity *entity,
+	enum display_entity_audiostate state);
+
 #endif /* __DISPLAY_H__ */
-- 
1.8.0



More information about the dri-devel mailing list