From patchwork Thu Feb 7 11:59:33 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rahul Sharma X-Patchwork-Id: 2110131 Return-Path: X-Original-To: patchwork-linux-media@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by patchwork2.kernel.org (Postfix) with ESMTP id B9AEDE00DA for ; Thu, 7 Feb 2013 11:41:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1757949Ab3BGLlF (ORCPT ); Thu, 7 Feb 2013 06:41:05 -0500 Received: from mailout2.samsung.com ([203.254.224.25]:9213 "EHLO mailout2.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1757316Ab3BGLlD (ORCPT ); Thu, 7 Feb 2013 06:41:03 -0500 Received: from epcpsbgm1.samsung.com (epcpsbgm1 [203.254.230.26]) by mailout2.samsung.com (Oracle Communications Messaging Server 7u4-24.01(7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTP id <0MHU00HE6LSBQHR0@mailout2.samsung.com>; Thu, 07 Feb 2013 20:41:01 +0900 (KST) Received: from epcpsbgm1.samsung.com ( [172.20.52.123]) by epcpsbgm1.samsung.com (EPCPMTA) with SMTP id 2D.98.03918.DC293115; Thu, 07 Feb 2013 20:41:01 +0900 (KST) X-AuditID: cbfee61a-b7f7d6d000000f4e-7b-511392cd01fc Received: from epmmp2 ( [203.254.227.17]) by epcpsbgm1.samsung.com (EPCPMTA) with SMTP id 8C.98.03918.DC293115; Thu, 07 Feb 2013 20:41:01 +0900 (KST) Received: from chrome-ubuntu.sisodomain.com ([107.108.73.106]) by mmp2.samsung.com (Oracle Communications Messaging Server 7u4-24.01(7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTPA id <0MHU009VILNWAF10@mmp2.samsung.com>; Thu, 07 Feb 2013 20:41:01 +0900 (KST) From: Rahul Sharma To: linux-media@vger.kernel.org, dri-devel@lists.freedesktop.org, alsa-devel@alsa-project.org, linux-fbdev@vger.kernel.org Cc: tomi.valkeinen@ti.com, laurent.pinchart@ideasonboard.com, broonie@opensource.wolfsonmicro.com, inki.dae@samsung.com, kyungmin.park@samsung.com, r.sh.open@gmail.com, joshi@samsung.com Subject: [RFC PATCH v2 1/5] video: display: add event handling, set mode and hdmi ops to cdf core Date: Thu, 07 Feb 2013 06:59:33 -0500 Message-id: <1360238377-14806-2-git-send-email-rahul.sharma@samsung.com> X-Mailer: git-send-email 1.8.0 In-reply-to: <1360238377-14806-1-git-send-email-rahul.sharma@samsung.com> References: <1360238377-14806-1-git-send-email-rahul.sharma@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFvrJLMWRmVeSWpSXmKPExsWyRsSkWvfsJOFAgy3T9C1O9H1gtejZsJXV gcnj8ya5AMYoLpuU1JzMstQifbsErozPm64xFUwKr+ia1sbUwPjVs4uRk0NCwETi+bm3zBC2 mMSFe+vZuhi5OIQEljJK/P+2nhWm6P/jU8wQiemMEn9+zmWBcHqZJNb/+MEGUsUmoCsx++Az RhBbRKBGYu7XHWCjmAX2MUrMbL7JDpIQFkiWWDbnIguIzSKgKrFjcgvYCl4BD4nfv4+xQ6yT k/iw5xGYzSngKbH7z0ewBUJANUeWTwIbKiFwn01i0q7ZTBCDBCS+TT4ENJQDKCErsekA1D+S EgdX3GCZwCi8gJFhFaNoakFyQXFSeq6hXnFibnFpXrpecn7uJkZgQJ7+90xqB+PKBotDjAIc jEo8vDeWCgUKsSaWFVfmHmKU4GBWEuE9WSMcKMSbklhZlVqUH19UmpNafIgxGWj5RGYp0eR8 YLTklcQbGpuYmxqbWhoZmZmakiasJM7LeOpJgJBAemJJanZqakFqEcwWJg5OqQZGu5JNTTWV VS91nbkrOAKFq96dau/udbz0aN1evvXqkZXpZgZ7a7Pz6h/dnLBd48ZqaRajh3z2O9dmHttk pBtz4OjHSSVBDoXX2BeZ8sVvm1n9bq9qck/sBEmJ01zPf/4pUbs6Y+K893Ner358Qb7I5iM3 R/2UBytfznAJy2QL2S2pHXPm16HLSizFGYmGWsxFxYkAtvuwUowCAAA= X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFlrBIsWRmVeSWpSXmKPExsVy+t9jQd2zk4QDDbauVrQ40feB1aJnw1ZW ByaPz5vkAhijGhhtMlITU1KLFFLzkvNTMvPSbZW8g+Od403NDAx1DS0tzJUU8hJzU22VXHwC dN0yc4BGKymUJeaUAoUCEouLlfTtME0IDXHTtYBpjND1DQmC6zEyQAMJaxgzPm+6xlQwKbyi a1obUwPjV88uRk4OCQETif+PTzFD2GISF+6tZ+ti5OIQEpjOKPHn51wWCKeXSWL9jx9sIFVs AroSsw8+YwSxRQRqJOZ+3QHWwSywj1FiZvNNdpCEsECyxLI5F1lAbBYBVYkdk1tYQWxeAQ+J 37+PsUOsk5P4sOcRmM0p4Cmx+89HsAVCQDVHlk9im8DIu4CRYRWjaGpBckFxUnquoV5xYm5x aV66XnJ+7iZGcLg/k9rBuLLB4hCjAAejEg/vjaVCgUKsiWXFlbmHGCU4mJVEeE/WCAcK8aYk VlalFuXHF5XmpBYfYkwGumois5Rocj4wFvNK4g2NTcxNjU0tTSxMzCxJE1YS52U89SRASCA9 sSQ1OzW1ILUIZgsTB6dUA6NByOX/kmcDBHctDN1TOCvz34vHJ790/e+v4Tt91ub78uWRrPkh Xxr+L+S58+zgy7UzQ55J3RK86+7jfq7fUnfPzvVT7zxN+xShV37iUxPj5DkfN86vuXTs6ePD tjE/TrzeaHv3cd/1lCObdPm0gp6tOGpvoRl7Y/mPsw837pUoY9RasVsoNdfyvBJLcUaioRZz UXEiANClTZG7AgAA DLP-Filter: Pass X-MTR: 20000000000000000@CPGS X-CFilter-Loop: Reflected Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org 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 --- 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 "); 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__ */