* [RFC PATCH v2 1/5] video: display: add event handling, set mode and hdmi ops to cdf core
From: Rahul Sharma @ 2013-02-07 11:59 UTC (permalink / raw)
To: linux-media, dri-devel, alsa-devel, linux-fbdev
Cc: tomi.valkeinen, laurent.pinchart, broonie, inki.dae,
kyungmin.park, r.sh.open, joshi
In-Reply-To: <1360238377-14806-1-git-send-email-rahul.sharma@samsung.com>
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@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@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
^ permalink raw reply related
* [RFC PATCH v2 0/5] exynos-hdmi to CDF compliant display driver
From: Rahul Sharma @ 2013-02-07 11:59 UTC (permalink / raw)
To: linux-media, dri-devel, alsa-devel, linux-fbdev
Cc: tomi.valkeinen, laurent.pinchart, broonie, inki.dae,
kyungmin.park, r.sh.open, joshi
V2:
1) Adding hdmi sound card using cdf based hdmi audio codec.
2) DAPM and JACK control to hdmi codec.
3) Offload event handler by adding work queue.
4) Rework based on v1 comments.
Tested for:
1) Mode setting and switching using modetest.
2) Video with HPD and Power related scenarios.
3) Audio playback with Hotplug-Scenarios.
4) DAPM control for hdmi playback.
Pending:
1) Not moved exynos_hdmi to driver/video/display since it will make it
difficult to analyze the code changes.
V1:
This patch set is a proposal to change Exynos Drm Hdmi driver to a CDF
complaint panel driver. This migration serves 2 purposes. One is to eliminate
duplication due to v4l and drm hdmi drivers. Second is to add support for Hdmi
audio ALSA codec which is not possible with drm/v4l hdmi driver (specially for
exynos as hdmi audio and hdmi core registers are intermixed.).
This patch series is based on the Second RFC of CDF from Laurent Pinchart,
(http://lists.freedesktop.org/archives/dri-devel/2012-November/030888.html)
applied to 'for-next' branch at
git.kernel.org/pub/scm/linux/kernel/git/kgene/linux-samsung.git.
[PATCH 1/4] video: display: add event handling, set mode and hdmi ops to cdf
core
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-subscription 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.
[PATCH 2/4] drm/edid: temporarily exposing generic edid-read interface from drm
It exposes generic interface from drm_edid.c to get the edid data and length
by any display entity. Once I get clear idea about edid handling in CDF, I need
to revert these temporary changes.
[PATCH 3/4] drm/exynos: moved drm hdmi driver to cdf framework
This patch implements exynos_hdmi_cdf.c which is a glue component between
exynos DRM and hdmi cdf panel. It is a platform driver register through
exynos_drm_drv.c. Exynos_hdmi.c is modified to register hdmi as display panel.
exynos_hdmi_cdf.c registers for exynos hdmi display entity and if successful,
proceeds for mode setting.
[PATCH 4/4] alsa/soc: add hdmi audio codec based on cdf
It registers hdmi-audio codec to the ALSA framework. This is the second client
to the hdmi panel. Once notified by the CDF Core it proceeds towards audio
setting and audio control. It also subscribes for hpd notification to implement
hpd related audio requirements.
Rahul Sharma (5):
video: display: add event handling, set mode and hdmi ops to cdf core
drm/edid: temporarily exposing generic edid-read interface from drm
drm/exynos: moved drm hdmi driver to cdf framework
alsa/soc: add hdmi audio codec based on cdf
alsa/soc: add hdmi audio card using cdf based hdmi codec
drivers/gpu/drm/drm_edid.c | 88 ++++++
drivers/gpu/drm/exynos/Kconfig | 6 +
drivers/gpu/drm/exynos/Makefile | 1 +
drivers/gpu/drm/exynos/exynos_drm_drv.c | 24 ++
drivers/gpu/drm/exynos/exynos_drm_drv.h | 1 +
drivers/gpu/drm/exynos/exynos_hdmi.c | 445 ++++++++++++++++---------------
drivers/gpu/drm/exynos/exynos_hdmi_cdf.c | 370 +++++++++++++++++++++++++
drivers/video/display/display-core.c | 85 ++++++
include/video/display.h | 111 +++++++-
include/video/exynos_hdmi.h | 25 ++
sound/soc/codecs/Kconfig | 3 +
sound/soc/codecs/Makefile | 2 +
sound/soc/codecs/exynos_hdmi_audio.c | 424 +++++++++++++++++++++++++++++
sound/soc/samsung/Kconfig | 8 +
sound/soc/samsung/Makefile | 2 +
sound/soc/samsung/hdmi.c | 260 ++++++++++++++++++
16 files changed, 1638 insertions(+), 217 deletions(-)
create mode 100644 drivers/gpu/drm/exynos/exynos_hdmi_cdf.c
create mode 100644 include/video/exynos_hdmi.h
create mode 100644 sound/soc/codecs/exynos_hdmi_audio.c
create mode 100644 sound/soc/samsung/hdmi.c
--
1.8.0
^ permalink raw reply
* [RFC PATCH v2 5/5] alsa/soc: add hdmi audio card using cdf based hdmi codec
From: Rahul Sharma @ 2013-02-07 11:54 UTC (permalink / raw)
To: linux-media, dri-devel, alsa-devel, linux-fbdev
Cc: tomi.valkeinen, laurent.pinchart, broonie, inki.dae,
kyungmin.park, r.sh.open, joshi
In-Reply-To: <1360239132-15557-1-git-send-email-rahul.sharma@samsung.com>
It registers hdmi-audio card to ALSA framework which associates i2s dai and
cdf based hdmi audio codec.
Signed-off-by: Rahul Sharma <rahul.sharma@samsung.com>
---
sound/soc/samsung/Kconfig | 8 ++
sound/soc/samsung/Makefile | 2 +
sound/soc/samsung/hdmi.c | 260 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 270 insertions(+)
create mode 100644 sound/soc/samsung/hdmi.c
diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig
index 90e7e66..d5b92ab 100644
--- a/sound/soc/samsung/Kconfig
+++ b/sound/soc/samsung/Kconfig
@@ -185,6 +185,14 @@ config SND_SOC_SMDK_WM8994_PCM
help
Say Y if you want to add support for SoC audio on the SMDK
+config SND_SOC_EXYNOS_HDMI_AUDIO
+ tristate "SoC I2S Audio support for HDMI"
+ depends on SND_SOC_SAMSUNG && DRM_EXYNOS_HDMI_CDF
+ select SND_SAMSUNG_I2S
+ select SND_SOC_EXYNOS_HDMI_CODEC
+ help
+ Say Y if you want to add support for hdmi audio on the Exynos.
+
config SND_SOC_SPEYSIDE
tristate "Audio support for Wolfson Speyside"
depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410
diff --git a/sound/soc/samsung/Makefile b/sound/soc/samsung/Makefile
index 709f605..ab1c151 100644
--- a/sound/soc/samsung/Makefile
+++ b/sound/soc/samsung/Makefile
@@ -8,6 +8,7 @@ snd-soc-s3c-i2s-v2-objs := s3c-i2s-v2.o
snd-soc-samsung-spdif-objs := spdif.o
snd-soc-pcm-objs := pcm.o
snd-soc-i2s-objs := i2s.o
+snd-soc-hdmi-objs := hdmi.o
obj-$(CONFIG_SND_SOC_SAMSUNG) += snd-soc-s3c24xx.o
obj-$(CONFIG_SND_S3C24XX_I2S) += snd-soc-s3c24xx-i2s.o
@@ -18,6 +19,7 @@ obj-$(CONFIG_SND_SAMSUNG_SPDIF) += snd-soc-samsung-spdif.o
obj-$(CONFIG_SND_SAMSUNG_PCM) += snd-soc-pcm.o
obj-$(CONFIG_SND_SAMSUNG_I2S) += snd-soc-i2s.o
obj-$(CONFIG_SND_SAMSUNG_I2S) += snd-soc-idma.o
+obj-$(CONFIG_SND_SOC_EXYNOS_HDMI_AUDIO) += snd-soc-hdmi.o
# S3C24XX Machine Support
snd-soc-jive-wm8750-objs := jive_wm8750.o
diff --git a/sound/soc/samsung/hdmi.c b/sound/soc/samsung/hdmi.c
new file mode 100644
index 0000000..a600a84
--- /dev/null
+++ b/sound/soc/samsung/hdmi.c
@@ -0,0 +1,260 @@
+/*
+ * ALSA SoC Card driver for HDMI audio on Samsung Exynos processors.
+ * Copyright (C) 2013 Samsung corp.
+ * Author: Rahul Sharma <rahul.sharma@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/clk.h>
+
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "i2s.h"
+
+/* platform device pointer for eynos hdmi audio device. */
+static struct platform_device *exynos_hdmi_audio_pdev;
+
+static int set_epll_rate(unsigned long rate)
+{
+ int ret;
+ struct clk *fout_epll;
+
+ fout_epll = clk_get(NULL, "fout_epll");
+
+ if (IS_ERR(fout_epll))
+ return PTR_ERR(fout_epll);
+
+ if (rate = clk_get_rate(fout_epll))
+ goto out;
+
+ ret = clk_set_rate(fout_epll, rate);
+ if (ret < 0)
+ goto out;
+
+out:
+ clk_put(fout_epll);
+
+ return 0;
+}
+
+static int hdmi_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int bfs, psr, rfs, ret;
+ unsigned long rclk;
+ unsigned long xtal;
+ struct clk *xtal_clk;
+
+ dev_dbg(rtd->dev, "[%d][%s]\n", __LINE__, __func__);
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_U24:
+ case SNDRV_PCM_FORMAT_S24:
+ bfs = 48;
+ break;
+ case SNDRV_PCM_FORMAT_U16_LE:
+ case SNDRV_PCM_FORMAT_S16_LE:
+ bfs = 32;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (params_rate(params)) {
+ case 16000:
+ case 22050:
+ case 24000:
+ case 32000:
+ case 44100:
+ case 48000:
+ case 88200:
+ case 96000:
+ if (bfs = 48)
+ rfs = 384;
+ else
+ rfs = 256;
+ break;
+ case 64000:
+ rfs = 384;
+ break;
+ case 8000:
+ case 11025:
+ case 12000:
+ if (bfs = 48)
+ rfs = 768;
+ else
+ rfs = 512;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ rclk = params_rate(params) * rfs;
+
+ switch (rclk) {
+ case 4096000:
+ case 5644800:
+ case 6144000:
+ case 8467200:
+ case 9216000:
+ psr = 8;
+ break;
+ case 8192000:
+ case 11289600:
+ case 12288000:
+ case 16934400:
+ case 18432000:
+ psr = 4;
+ break;
+ case 22579200:
+ case 24576000:
+ case 33868800:
+ case 36864000:
+ psr = 2;
+ break;
+ case 67737600:
+ case 73728000:
+ psr = 1;
+ break;
+ default:
+ dev_err(rtd->dev, "rclk = %lu is not yet supported!\n", rclk);
+ return -EINVAL;
+ }
+
+ ret = set_epll_rate(rclk * psr);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ return ret;
+
+ xtal_clk = clk_get(NULL, "xtal"); /*xtal clk is input to codec MCLK1*/
+ if (IS_ERR(xtal_clk)) {
+ dev_err(rtd->dev, "%s: failed to get xtal clock\n", __func__);
+ return PTR_ERR(xtal_clk);
+ }
+
+ xtal = clk_get_rate(xtal_clk);
+ clk_put(xtal_clk);
+
+ ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_CDCLK,
+ 0, SND_SOC_CLOCK_OUT);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dai_set_clkdiv(cpu_dai, SAMSUNG_I2S_DIV_BCLK, bfs);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+/*
+ * HDMI DAI operations.
+ */
+static struct snd_soc_ops hdmi_ops = {
+ .hw_params = hdmi_hw_params,
+};
+
+static struct snd_soc_dai_link hdmi_dai[] = {
+ { /* HDMI Playback i/f */
+ .name = "HDMI Playback",
+ .stream_name = "i2s_Dai",
+ .cpu_dai_name = "samsung-i2s.0",
+ .codec_dai_name = "exynos-hdmi-audio-dai",
+ .platform_name = "samsung-i2s.0",
+ .codec_name = "exynos-hdmi-audio-codec",
+ .ops = &hdmi_ops,
+ },
+};
+
+static struct snd_soc_card hdmi = {
+ .name = "HDMI-AUDIO",
+ .owner = THIS_MODULE,
+ .dai_link = hdmi_dai,
+ .num_links = ARRAY_SIZE(hdmi_dai),
+};
+
+static int hdmi_audio_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct snd_soc_card *card = &hdmi;
+
+ card->dev = &pdev->dev;
+ dev_dbg(&pdev->dev, "[%d][%s]\n", __LINE__, __func__);
+
+ ret = snd_soc_register_card(card);
+ if (ret)
+ dev_err(&pdev->dev, "snd_soc_register_card() failed:%d\n", ret);
+
+ return ret;
+}
+
+static int hdmi_audio_remove(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+ snd_soc_unregister_card(card);
+
+ return 0;
+}
+
+static struct platform_driver hdmi_audio_driver = {
+ .driver = {
+ .name = "exynos-hdmi-audio",
+ .owner = THIS_MODULE,
+ .pm = &snd_soc_pm_ops,
+ },
+ .probe = hdmi_audio_probe,
+ .remove = hdmi_audio_remove,
+};
+
+static int __init hdmi_audio_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&hdmi_audio_driver);
+ if (ret < 0)
+ return -EINVAL;
+
+ exynos_hdmi_audio_pdev = platform_device_register_simple
+ ("exynos-hdmi-audio", -1, NULL, 0);
+ if (IS_ERR_OR_NULL(exynos_hdmi_audio_pdev)) {
+ ret = PTR_ERR(exynos_hdmi_audio_pdev);
+ platform_driver_unregister(&hdmi_audio_driver);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void __exit hdmi_audio_exit(void)
+{
+ platform_driver_unregister(&hdmi_audio_driver);
+ platform_device_unregister(exynos_hdmi_audio_pdev);
+}
+
+module_init(hdmi_audio_init);
+module_exit(hdmi_audio_exit);
+
+MODULE_AUTHOR("Rahul Sharma <rahul.sharma@samsung.com>");
+MODULE_DESCRIPTION("ALSA SoC HDMI AUDIO Card");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:hdmi-audio");
--
1.8.0
^ permalink raw reply related
* [RFC PATCH v2 4/5] alsa/soc: add hdmi audio codec based on cdf
From: Rahul Sharma @ 2013-02-07 11:53 UTC (permalink / raw)
To: linux-media, dri-devel, alsa-devel, linux-fbdev
Cc: tomi.valkeinen, laurent.pinchart, broonie, inki.dae,
kyungmin.park, r.sh.open, joshi
In-Reply-To: <1360239132-15557-1-git-send-email-rahul.sharma@samsung.com>
V2:
- DAPM and JACK control to hdmi codec.
This patch registers hdmi-audio codec to the ALSA framework. This is the second
client to the hdmi panel. Once notified by the CDF Core it proceeds towards
audio setting and audio control. It also subscribes for hpd notification to
implement hpd related audio requirements.
Signed-off-by: Rahul Sharma <rahul.sharma@samsung.com>
---
sound/soc/codecs/Kconfig | 3 +
sound/soc/codecs/Makefile | 2 +
sound/soc/codecs/exynos_hdmi_audio.c | 424 +++++++++++++++++++++++++++++++++++
3 files changed, 429 insertions(+)
create mode 100644 sound/soc/codecs/exynos_hdmi_audio.c
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 3a84782..d3e0874 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -512,3 +512,6 @@ config SND_SOC_ML26124
config SND_SOC_TPA6130A2
tristate
+
+config SND_SOC_EXYNOS_HDMI_CODEC
+ tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index f6e8e36..388da28 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -115,6 +115,7 @@ snd-soc-wm9705-objs := wm9705.o
snd-soc-wm9712-objs := wm9712.o
snd-soc-wm9713-objs := wm9713.o
snd-soc-wm-hubs-objs := wm_hubs.o
+snd-soc-exynos-hdmi-audio-objs := exynos_hdmi_audio.o
# Amp
snd-soc-max9877-objs := max9877.o
@@ -236,6 +237,7 @@ obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o
obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o
obj-$(CONFIG_SND_SOC_WM_ADSP) += snd-soc-wm-adsp.o
obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o
+obj-$(CONFIG_SND_SOC_EXYNOS_HDMI_CODEC) += snd-soc-exynos-hdmi-audio.o
# Amp
obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o
diff --git a/sound/soc/codecs/exynos_hdmi_audio.c b/sound/soc/codecs/exynos_hdmi_audio.c
new file mode 100644
index 0000000..e2cf94c
--- /dev/null
+++ b/sound/soc/codecs/exynos_hdmi_audio.c
@@ -0,0 +1,424 @@
+/*
+ * ALSA SoC codec driver for HDMI audio on Samsung Exynos processors.
+ * Copyright (C) 2013 Samsung corp.
+ * Author: Rahul Sharma <rahul.sharma@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ */
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+
+#include <video/display.h>
+#include <video/exynos_hdmi.h>
+
+#define get_ctx(dev) ((struct hdmi_audio_context *)platform_get_drvdata\
+ (to_platform_device((struct device *)dev)))
+
+/* platform device pointer for eynos hdmi audio codec device. */
+static struct platform_device *exynos_hdmi_codec_pdev;
+
+struct hdmi_audio_context {
+ struct platform_device *pdev;
+ atomic_t plugged;
+ atomic_t enabled;
+ struct workqueue_struct *event_wq;
+ struct delayed_work hotplug_work;
+ struct display_entity_audio_params audio_params;
+ struct display_entity *entity;
+ struct display_entity_notifier notf;
+ struct display_event_subscriber subscriber;
+ struct snd_soc_jack hdmi_jack;
+};
+
+static int exynos_hdmi_audio_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct hdmi_audio_context *ctx = snd_soc_codec_get_drvdata(codec);
+ int ret;
+
+ dev_dbg(codec->dev, "[%d] %s\n", __LINE__, __func__);
+
+ /* report failure if hdmi sink is unplugged. */
+ if (!atomic_read(&ctx->plugged))
+ return -ENODEV;
+
+ ctx->audio_params.type = DISPLAY_ENTITY_AUDIO_I2S;
+
+ switch (params_channels(params)) {
+ case 6:
+ case 4:
+ case 2:
+ case 1:
+ ctx->audio_params.channels = params_channels(params);
+ break;
+ default:
+ dev_err(codec->dev, "%d channels not supported\n",
+ params_channels(params));
+ return -EINVAL;
+ }
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S8:
+ ctx->audio_params.bits_per_sample = 8;
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ ctx->audio_params.bits_per_sample = 12;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ ctx->audio_params.bits_per_sample = 16;
+ break;
+ default:
+ dev_err(codec->dev, "Format(%d) not supported\n",
+ params_format(params));
+ return -EINVAL;
+ }
+
+ switch (params_rate(params)) {
+ case 32000:
+ case 44100:
+ case 88200:
+ case 176400:
+ case 48000:
+ case 96000:
+ case 192000:
+ ctx->audio_params.sf = params_rate(params);
+ break;
+ default:
+ dev_err(codec->dev, "%d Rate supported\n",
+ params_rate(params));
+ return -EINVAL;
+ }
+
+ ret + display_entity_hdmi_init_audio(ctx->entity, &ctx->audio_params);
+ if (ret)
+ dev_err(codec->dev, "initaudio failed ret %d\n", ret);
+ return ret;
+}
+
+static int exynos_hdmi_audio_trigger(struct snd_pcm_substream *substream,
+ int cmd, struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct hdmi_audio_context *ctx = snd_soc_codec_get_drvdata(codec);
+ int ret;
+
+ dev_dbg(codec->dev, "[%d] %s\n", __LINE__, __func__);
+
+ /* report failure if hdmi sink is unplugged. */
+ if (!atomic_read(&ctx->plugged))
+ return -EINVAL;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ /* Don't start if hdmi audio is disabled. return Success. */
+ if (!atomic_read(&ctx->enabled))
+ return 0;
+
+ ret = display_entity_hdmi_set_audiostate(ctx->entity,
+ DISPLAY_ENTITY_AUDIOSTATE_ON);
+ if (ret) {
+ dev_err(codec->dev, "audio enable failed.\n");
+ return -EINVAL;
+ }
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ ret = display_entity_hdmi_set_audiostate(ctx->entity,
+ DISPLAY_ENTITY_AUDIOSTATE_OFF);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static const struct snd_soc_dai_ops exynos_hdmi_audio_dai_ops = {
+ .hw_params = exynos_hdmi_audio_hw_params,
+ .trigger = exynos_hdmi_audio_trigger,
+};
+
+static struct snd_soc_dai_driver hdmi_codec_dai = {
+ .name = "exynos-hdmi-audio-dai",
+ .playback = {
+ .channels_min = 2,
+ .channels_max = 8,
+ .rates = SNDRV_PCM_RATE_32000 |
+ SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ },
+ .ops = &exynos_hdmi_audio_dai_ops,
+};
+
+void hdmi_audio_event_notify(struct display_entity *entity,
+ enum display_entity_event_type type,
+ unsigned int value, void *context)
+{
+ struct hdmi_audio_context *ctx = (struct hdmi_audio_context *)context;
+
+ if (type = DISPLAY_ENTITY_HDMI_HOTPLUG) {
+ dev_dbg(&ctx->pdev->dev, "[%d][%s] hpd(%d)\n", __LINE__,
+ __func__, value);
+ atomic_set(&ctx->plugged, !!value);
+
+ /* should set audio regs after ip, phy got stable. 5ms suff */
+ queue_delayed_work(ctx->event_wq, &ctx->hotplug_work,
+ msecs_to_jiffies(5));
+ }
+}
+
+static void hotplug_event_handler(struct work_struct *work)
+{
+ struct hdmi_audio_context *ctx = container_of(work,
+ struct hdmi_audio_context, hotplug_work.work);
+
+ if (atomic_read(&ctx->plugged)) {
+ display_entity_hdmi_init_audio(ctx->entity,
+ &ctx->audio_params);
+
+ if (atomic_read(&ctx->enabled))
+ display_entity_hdmi_set_audiostate(ctx->entity,
+ DISPLAY_ENTITY_AUDIOSTATE_ON);
+ else
+ display_entity_hdmi_set_audiostate(ctx->entity,
+ DISPLAY_ENTITY_AUDIOSTATE_OFF);
+ }
+
+ snd_soc_jack_report(&ctx->hdmi_jack,
+ atomic_read(&ctx->plugged) ? SND_JACK_AVOUT
+ : 0, SND_JACK_AVOUT);
+}
+
+int exynos_hdmi_audio_notification(struct display_entity_notifier *notf,
+ struct display_entity *entity, int status)
+{
+ struct hdmi_audio_context *ctx = container_of(notf,
+ struct hdmi_audio_context, notf);
+ struct exynos_hdmi_control_ops *exynos_ops + (struct exynos_hdmi_control_ops *)entity->private;
+ int hpd;
+
+ if (status != DISPLAY_ENTITY_NOTIFIER_CONNECT && entity)
+ return -EINVAL;
+
+ dev_dbg(&ctx->pdev->dev, "[%d][%s]\n", __LINE__, __func__);
+
+ ctx->entity = entity;
+
+ ctx->subscriber.context = ctx;
+ ctx->subscriber.notify = hdmi_audio_event_notify;
+
+ display_entity_subscribe_event(entity, &ctx->subscriber);
+
+ exynos_ops->get_hpdstate(entity, &hpd);
+ atomic_set(&ctx->plugged, !!hpd);
+
+ return 0;
+}
+
+static int get_hdmi(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hdmi_audio_context *ctx = get_ctx(kcontrol->private_value);
+
+ if (!ctx) {
+ dev_err(&ctx->pdev->dev, "invalid context.\n");
+ return 0;
+ }
+
+ ucontrol->value.integer.value[0] = atomic_read(&ctx->enabled);
+ return 1;
+}
+
+static int put_hdmi(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hdmi_audio_context *ctx = get_ctx(kcontrol->private_value);
+ int enable = (int)ucontrol->value.integer.value[0];
+
+ if (!ctx) {
+ dev_err(&ctx->pdev->dev, "invalid context.\n");
+ return 0;
+ }
+
+ atomic_set(&ctx->enabled, !!enable);
+
+ if (!atomic_read(&ctx->plugged))
+ return 1;
+ else if (enable)
+ display_entity_hdmi_set_audiostate(ctx->entity,
+ DISPLAY_ENTITY_AUDIOSTATE_ON);
+ else
+ display_entity_hdmi_set_audiostate(ctx->entity,
+ DISPLAY_ENTITY_AUDIOSTATE_OFF);
+
+ return 1;
+}
+
+static struct snd_kcontrol_new hdmi_dapm_controls[] = {
+ SOC_SINGLE_BOOL_EXT("HDMI Playback Switch", 0, get_hdmi, put_hdmi),
+};
+
+static int hdmi_codec_init(struct snd_soc_codec *codec)
+{
+ struct hdmi_audio_context *ctx = get_ctx(codec->dev);
+ int ret;
+
+ ret = snd_soc_jack_new(codec, "HDMI Jack",
+ SND_JACK_AVOUT, &ctx->hdmi_jack);
+ if (ret) {
+ dev_err(codec->dev, "audio enable failed.\n");
+ return ret;
+ }
+
+ hdmi_dapm_controls[0].private_value = (unsigned long)codec->dev;
+ return 0;
+}
+
+static struct snd_soc_codec_driver hdmi_codec = {
+ .probe = hdmi_codec_init,
+ .controls = hdmi_dapm_controls,
+ .num_controls = ARRAY_SIZE(hdmi_dapm_controls),
+};
+
+static int hdmi_codec_probe(struct platform_device *pdev)
+{
+ struct hdmi_audio_context *ctx;
+ struct device_node *dev_node;
+ struct platform_device *disp_pdev;
+ int ret;
+
+ dev_dbg(&pdev->dev, "[%d][%s]\n", __LINE__, __func__);
+
+ ret = snd_soc_register_codec(&pdev->dev, &hdmi_codec,
+ &hdmi_codec_dai, 1);
+ if (ret) {
+ dev_err(&pdev->dev, "register_codec failed (%d)\n", ret);
+ return ret;
+ }
+
+ ctx = devm_kzalloc(&pdev->dev, sizeof(struct hdmi_audio_context),
+ GFP_KERNEL);
+ if (ctx = NULL)
+ return -ENOMEM;
+
+ ctx->pdev = pdev;
+ atomic_set(&ctx->enabled, 1);
+ platform_set_drvdata(pdev, ctx);
+
+ /* create workqueue and hotplug work */
+ ctx->event_wq = alloc_workqueue("hdmi-audio-event",
+ WQ_UNBOUND | WQ_NON_REENTRANT, 1);
+ if (ctx->event_wq = NULL) {
+ dev_err(&pdev->dev, "failed to create workqueue\n");
+ ret = -ENOMEM;
+ }
+ INIT_DELAYED_WORK(&ctx->hotplug_work, hotplug_event_handler);
+
+ dev_node = of_find_compatible_node(NULL, NULL,
+ "samsung,exynos5-hdmi");
+ if (!dev_node) {
+ dev_err(&pdev->dev, "[%d][%s] dt node not found.\n",
+ __LINE__, __func__);
+ return -EINVAL;
+ }
+
+ disp_pdev = of_find_device_by_node(dev_node);
+ if (!disp_pdev) {
+ dev_err(&pdev->dev, "[ERROR][%d][%s] No pdev\n",
+ __LINE__, __func__);
+ return -EINVAL;
+ }
+
+ ctx->notf.dev = &disp_pdev->dev;
+ ctx->notf.notify = exynos_hdmi_audio_notification;
+
+ ret = display_entity_register_notifier(&ctx->notf);
+ if (ret) {
+ dev_err(&pdev->dev, "[%d][%s] entity registe failed.\n",
+ __LINE__, __func__);
+ ret = -EINVAL;
+ goto err_workq;
+ }
+
+ return 0;
+
+err_workq:
+ destroy_workqueue(ctx->event_wq);
+ return ret;
+}
+
+static int hdmi_codec_remove(struct platform_device *pdev)
+{
+ struct hdmi_audio_context *ctx = get_ctx(&pdev->dev);
+ dev_dbg(&pdev->dev, "[%d][%s]\n", __LINE__, __func__);
+ mdelay(1000);
+
+ display_entity_register_notifier(&ctx->notf);
+ snd_soc_unregister_codec(&pdev->dev);
+ destroy_workqueue(ctx->event_wq);
+ return 0;
+}
+
+static struct platform_driver hdmi_codec_driver = {
+ .driver = {
+ .name = "exynos-hdmi-audio-codec",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = hdmi_codec_probe,
+ .remove = hdmi_codec_remove,
+};
+
+static int __init hdmi_audio_codec_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&hdmi_codec_driver);
+ if (ret < 0)
+ return -EINVAL;
+
+ exynos_hdmi_codec_pdev = platform_device_register_simple
+ ("exynos-hdmi-audio-codec", -1, NULL, 0);
+ if (IS_ERR_OR_NULL(exynos_hdmi_codec_pdev)) {
+ ret = PTR_ERR(exynos_hdmi_codec_pdev);
+ platform_driver_unregister(&hdmi_codec_driver);
+ return ret;
+ }
+
+ return 0;
+}
+static void __exit hdmi_audio_codec_exit(void)
+{
+ platform_driver_unregister(&hdmi_codec_driver);
+ platform_device_unregister(exynos_hdmi_codec_pdev);
+}
+
+module_init(hdmi_audio_codec_init);
+module_exit(hdmi_audio_codec_exit);
+
+MODULE_AUTHOR("Rahul Sharma <rahul.sharma@samsung.com>");
+MODULE_DESCRIPTION("ASoC EXYNOS HDMI codec driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:exynos-hdmi-codec");
--
1.8.0
^ permalink raw reply related
* [RFC PATCH v2 3/5] drm/exynos: moved drm hdmi driver to cdf framework
From: Rahul Sharma @ 2013-02-07 11:52 UTC (permalink / raw)
To: linux-media, dri-devel, alsa-devel, linux-fbdev
Cc: tomi.valkeinen, laurent.pinchart, broonie, inki.dae,
kyungmin.park, r.sh.open, joshi
This patch implements exynos_hdmi_cdf.c which is a glue component between
exynos DRM and hdmi cdf panel. It is a platform driver register through
exynos_drm_drv.c. Exynos_hdmi.c is modified to register hdmi as display panel.
exynos_hdmi_cdf.c registers for exynos hdmi display entity and if successful,
proceeds for mode setting.
Signed-off-by: Rahul Sharma <rahul.sharma@samsung.com>
---
drivers/gpu/drm/exynos/Kconfig | 6 +
drivers/gpu/drm/exynos/Makefile | 1 +
drivers/gpu/drm/exynos/exynos_drm_drv.c | 24 ++
drivers/gpu/drm/exynos/exynos_drm_drv.h | 1 +
drivers/gpu/drm/exynos/exynos_hdmi.c | 445 ++++++++++++++++---------------
drivers/gpu/drm/exynos/exynos_hdmi_cdf.c | 370 +++++++++++++++++++++++++
include/video/exynos_hdmi.h | 25 ++
7 files changed, 658 insertions(+), 214 deletions(-)
create mode 100644 drivers/gpu/drm/exynos/exynos_hdmi_cdf.c
create mode 100644 include/video/exynos_hdmi.h
diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig
index 1d1f1e5..309e62a 100644
--- a/drivers/gpu/drm/exynos/Kconfig
+++ b/drivers/gpu/drm/exynos/Kconfig
@@ -34,6 +34,12 @@ config DRM_EXYNOS_HDMI
help
Choose this option if you want to use Exynos HDMI for DRM.
+config DRM_EXYNOS_HDMI_CDF
+ bool "Exynos DRM HDMI using CDF"
+ depends on DRM_EXYNOS_HDMI && DRM_EXYNOS && !VIDEO_SAMSUNG_S5P_TV
+ help
+ Choose this option if you want to use Exynos HDMI for DRM using CDF.
+
config DRM_EXYNOS_VIDI
bool "Exynos DRM Virtual Display"
depends on DRM_EXYNOS
diff --git a/drivers/gpu/drm/exynos/Makefile b/drivers/gpu/drm/exynos/Makefile
index 639b49e..e946ed6 100644
--- a/drivers/gpu/drm/exynos/Makefile
+++ b/drivers/gpu/drm/exynos/Makefile
@@ -20,5 +20,6 @@ exynosdrm-$(CONFIG_DRM_EXYNOS_IPP) += exynos_drm_ipp.o
exynosdrm-$(CONFIG_DRM_EXYNOS_FIMC) += exynos_drm_fimc.o
exynosdrm-$(CONFIG_DRM_EXYNOS_ROTATOR) += exynos_drm_rotator.o
exynosdrm-$(CONFIG_DRM_EXYNOS_GSC) += exynos_drm_gsc.o
+exynosdrm-$(CONFIG_DRM_EXYNOS_HDMI_CDF) += exynos_hdmi_cdf.o
obj-$(CONFIG_DRM_EXYNOS) += exynosdrm.o
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index 3da5c2d..7876c3c 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -40,6 +40,9 @@
/* platform device pointer for eynos drm device. */
static struct platform_device *exynos_drm_pdev;
+/* platform device pointer for eynos hdmi cdf device. */
+static struct platform_device *exynos_hdmi_cdf_pdev;
+
static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
{
struct exynos_drm_private *private;
@@ -331,6 +334,18 @@ static int __init exynos_drm_init(void)
#endif
#ifdef CONFIG_DRM_EXYNOS_HDMI
+
+ ret = platform_driver_register(&hdmi_cdf_driver);
+ if (ret < 0)
+ goto out_hdmi_cdf_driver;
+
+ exynos_hdmi_cdf_pdev = platform_device_register_simple(
+ "exynos-hdmi-cdf", -1, NULL, 0);
+ if (IS_ERR_OR_NULL(exynos_hdmi_cdf_pdev)) {
+ ret = PTR_ERR(exynos_hdmi_cdf_pdev);
+ goto out_hdmi_cdf_device;
+ }
+
ret = platform_driver_register(&hdmi_driver);
if (ret < 0)
goto out_hdmi;
@@ -438,6 +453,13 @@ out_common_hdmi:
out_mixer:
platform_driver_unregister(&hdmi_driver);
out_hdmi:
+
+out_hdmi_cdf_device:
+ platform_device_unregister(exynos_hdmi_cdf_pdev);
+
+out_hdmi_cdf_driver:
+ platform_driver_unregister(&hdmi_cdf_driver);
+
#endif
#ifdef CONFIG_DRM_EXYNOS_FIMD
@@ -480,6 +502,8 @@ static void __exit exynos_drm_exit(void)
platform_driver_unregister(&exynos_drm_common_hdmi_driver);
platform_driver_unregister(&mixer_driver);
platform_driver_unregister(&hdmi_driver);
+ platform_driver_unregister(&hdmi_cdf_driver);
+ platform_device_unregister(exynos_hdmi_cdf_pdev);
#endif
#ifdef CONFIG_DRM_EXYNOS_VIDI
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index b9e51bc..961fe14 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -332,6 +332,7 @@ void exynos_platform_device_hdmi_unregister(void);
extern struct platform_driver fimd_driver;
extern struct platform_driver hdmi_driver;
extern struct platform_driver mixer_driver;
+extern struct platform_driver hdmi_cdf_driver;
extern struct platform_driver exynos_drm_common_hdmi_driver;
extern struct platform_driver vidi_driver;
extern struct platform_driver g2d_driver;
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index 6f844b1..548cd32 100755
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -34,13 +34,12 @@
#include <linux/regulator/consumer.h>
#include <linux/io.h>
#include <linux/of_gpio.h>
+#include <video/display.h>
+#include "video/exynos_hdmi.h"
#include <plat/gpio-cfg.h>
#include <drm/exynos_drm.h>
-#include "exynos_drm_drv.h"
-#include "exynos_drm_hdmi.h"
-
#include "exynos_hdmi.h"
#include <linux/gpio.h>
@@ -157,14 +156,12 @@ struct hdmi_v14_conf {
struct hdmi_context {
struct device *dev;
- struct drm_device *drm_dev;
bool hpd;
bool powered;
bool dvi_mode;
struct mutex hdmi_mutex;
void __iomem *regs;
- void *parent_ctx;
int external_irq;
int internal_irq;
@@ -180,6 +177,7 @@ struct hdmi_context {
int hpd_gpio;
enum hdmi_type type;
+ struct display_entity entity;
};
/* HDMI Version 1.3 */
@@ -973,39 +971,8 @@ static void hdmi_reg_infoframe(struct hdmi_context *hdata,
}
}
-static bool hdmi_is_connected(void *ctx)
-{
- struct hdmi_context *hdata = ctx;
-
- return hdata->hpd;
-}
-
-static int hdmi_get_edid(void *ctx, struct drm_connector *connector,
- u8 *edid, int len)
-{
- struct edid *raw_edid;
- struct hdmi_context *hdata = ctx;
-
- DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
- if (!hdata->ddc_port)
- return -ENODEV;
-
- raw_edid = drm_get_edid(connector, hdata->ddc_port->adapter);
- if (raw_edid) {
- hdata->dvi_mode = !drm_detect_hdmi_monitor(raw_edid);
- memcpy(edid, raw_edid, min((1 + raw_edid->extensions)
- * EDID_LENGTH, len));
- DRM_DEBUG_KMS("%s : width[%d] x height[%d]\n",
- (hdata->dvi_mode ? "dvi monitor" : "hdmi monitor"),
- raw_edid->width_cm, raw_edid->height_cm);
- kfree(raw_edid);
- } else {
- return -ENODEV;
- }
-
- return 0;
-}
+extern int generic_drm_get_edid(struct i2c_adapter *adapter,
+ struct display_entity_edid *edid);
static int hdmi_v13_check_timing(struct fb_videomode *check_timing)
{
@@ -1061,22 +1028,6 @@ static int hdmi_v14_check_timing(struct fb_videomode *check_timing)
return -EINVAL;
}
-static int hdmi_check_timing(void *ctx, struct fb_videomode *timing)
-{
- struct hdmi_context *hdata = ctx;
-
- DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
- DRM_DEBUG_KMS("[%d]x[%d] [%d]Hz [%x]\n", timing->xres,
- timing->yres, timing->refresh,
- timing->vmode);
-
- if (hdata->type = HDMI_TYPE13)
- return hdmi_v13_check_timing(timing);
- else
- return hdmi_v14_check_timing(timing);
-}
-
static void hdmi_set_acr(u32 freq, u8 *acr)
{
u32 n, cts;
@@ -1143,15 +1094,22 @@ static void hdmi_reg_acr(struct hdmi_context *hdata, u8 *acr)
hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4);
}
-static void hdmi_audio_init(struct hdmi_context *hdata)
+static void hdmi_spdif_audio_init(struct hdmi_context *hdata,
+ const struct display_entity_audio_params *params)
+{
+ DRM_ERROR("SPDIF AUDIO NOT IMPLEMENTED YET");
+}
+
+static void hdmi_i2s_audio_init(struct hdmi_context *hdata,
+ const struct display_entity_audio_params *params)
{
u32 sample_rate, bits_per_sample, frame_size_code;
u32 data_num, bit_ch, sample_frq;
u32 val;
u8 acr[7];
- sample_rate = 44100;
- bits_per_sample = 16;
+ sample_rate = params->sf;
+ bits_per_sample = params->bits_per_sample;
frame_size_code = 0;
switch (bits_per_sample) {
@@ -1685,8 +1643,6 @@ static void hdmi_conf_apply(struct hdmi_context *hdata)
hdmi_conf_init(hdata);
mutex_unlock(&hdata->hdmi_mutex);
- hdmi_audio_init(hdata);
-
/* setting core registers */
hdmi_timing_apply(hdata);
hdmi_audio_control(hdata, true);
@@ -1694,58 +1650,6 @@ static void hdmi_conf_apply(struct hdmi_context *hdata)
hdmi_regs_dump(hdata, "start");
}
-static void hdmi_mode_fixup(void *ctx, struct drm_connector *connector,
- const struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
-{
- struct drm_display_mode *m;
- struct hdmi_context *hdata = ctx;
- int index;
-
- DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
- drm_mode_set_crtcinfo(adjusted_mode, 0);
-
- if (hdata->type = HDMI_TYPE13)
- index = hdmi_v13_conf_index(adjusted_mode);
- else
- index = hdmi_v14_find_phy_conf(adjusted_mode->clock * 1000);
-
- /* just return if user desired mode exists. */
- if (index >= 0)
- return;
-
- /*
- * otherwise, find the most suitable mode among modes and change it
- * to adjusted_mode.
- */
- list_for_each_entry(m, &connector->modes, head) {
- if (hdata->type = HDMI_TYPE13)
- index = hdmi_v13_conf_index(m);
- else
- index = hdmi_v14_find_phy_conf(m->clock * 1000);
-
- if (index >= 0) {
- struct drm_mode_object base;
- struct list_head head;
-
- DRM_INFO("desired mode doesn't exist so\n");
- DRM_INFO("use the most suitable mode among modes.\n");
-
- DRM_DEBUG_KMS("Adjusted Mode: [%d]x[%d] [%d]Hz\n",
- m->hdisplay, m->vdisplay, m->vrefresh);
-
- /* preserve display mode header while copying. */
- head = adjusted_mode->head;
- base = adjusted_mode->base;
- memcpy(adjusted_mode, m, sizeof(*m));
- adjusted_mode->head = head;
- adjusted_mode->base = base;
- break;
- }
- }
-}
-
static void hdmi_set_reg(u8 *reg_pair, int num_bytes, u32 value)
{
int i;
@@ -1862,42 +1766,6 @@ static void hdmi_v14_mode_set(struct hdmi_context *hdata,
}
-static void hdmi_mode_set(void *ctx, void *mode)
-{
- struct hdmi_context *hdata = ctx;
- int conf_idx;
-
- DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
- if (hdata->type = HDMI_TYPE13) {
- conf_idx = hdmi_v13_conf_index(mode);
- if (conf_idx >= 0)
- hdata->cur_conf = conf_idx;
- else
- DRM_DEBUG_KMS("not supported mode\n");
- } else {
- hdmi_v14_mode_set(hdata, mode);
- }
-}
-
-static void hdmi_get_max_resol(void *ctx, unsigned int *width,
- unsigned int *height)
-{
- DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
- *width = MAX_WIDTH;
- *height = MAX_HEIGHT;
-}
-
-static void hdmi_commit(void *ctx)
-{
- struct hdmi_context *hdata = ctx;
-
- DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
- hdmi_conf_apply(hdata);
-}
-
static void hdmi_poweron(struct hdmi_context *hdata)
{
struct hdmi_resources *res = &hdata->res;
@@ -1953,62 +1821,215 @@ out:
mutex_unlock(&hdata->hdmi_mutex);
}
-static void hdmi_dpms(void *ctx, int mode)
+int hdmi_get_size(struct display_entity *ent,
+ unsigned int *width, unsigned int *height)
{
- struct hdmi_context *hdata = ctx;
+ DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
- DRM_DEBUG_KMS("[%d] %s mode %d\n", __LINE__, __func__, mode);
+ *width = MAX_WIDTH;
+ *height = MAX_HEIGHT;
- switch (mode) {
- case DRM_MODE_DPMS_ON:
- if (pm_runtime_suspended(hdata->dev))
- pm_runtime_get_sync(hdata->dev);
- break;
- case DRM_MODE_DPMS_STANDBY:
- case DRM_MODE_DPMS_SUSPEND:
- case DRM_MODE_DPMS_OFF:
+ return 0;
+}
+
+void hdmi_send_hpdevent(struct display_entity *entity, int hpd)
+{
+ DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+
+ display_entity_notify_event_subscriber(entity,
+ DISPLAY_ENTITY_HDMI_HOTPLUG, hpd);
+}
+
+int hdmi_get_hpdstate(struct display_entity *entity, unsigned int *hpd_state)
+{
+ struct hdmi_context *hdata + container_of(entity, struct hdmi_context, entity);
+
+ DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+
+ if (hpd_state) {
+ *hpd_state = hdata->hpd;
+ return 0;
+ }
+ return -1;
+}
+
+int hdmi_get_edid(struct display_entity *entity,
+ struct display_entity_edid *edid)
+{
+ struct hdmi_context *hdata + container_of(entity, struct hdmi_context, entity);
+ struct edid *raw_edid;
+ int ret;
+
+ DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+
+ if (!hdata->ddc_port)
+ return -ENODEV;
+
+ ret = generic_drm_get_edid(hdata->ddc_port->adapter, edid);
+ if (ret) {
+ DRM_ERROR("[%d]%s, Edid Read Fail!!! ret = %d\n",
+ __LINE__, __func__, ret);
+ return -EINVAL;
+ }
+
+ raw_edid = (struct edid *)edid->edid;
+
+ if (raw_edid)
+ hdata->dvi_mode = !drm_detect_hdmi_monitor(raw_edid);
+ else
+ return -ENODEV;
+
+ return 0;
+}
+
+int hdmi_check_mode(struct display_entity *entity,
+ const struct videomode *mode)
+{
+ struct hdmi_context *hdata + container_of(entity, struct hdmi_context, entity);
+ struct fb_videomode *timing = (struct fb_videomode *)mode;
+
+ DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+
+ DRM_DEBUG_KMS("[%d]x[%d] [%d]Hz [%x]\n", timing->xres,
+ timing->yres, timing->refresh,
+ timing->vmode);
+
+ if (hdata->type = HDMI_TYPE13)
+ return hdmi_v13_check_timing(timing);
+ else
+ return hdmi_v14_check_timing(timing);
+}
+
+int hdmi_set_mode(struct display_entity *entity,
+ const struct videomode *mode)
+{
+ struct hdmi_context *hdata + container_of(entity, struct hdmi_context, entity);
+ struct drm_display_mode *m = (struct drm_display_mode *)mode;
+ int conf_idx;
+
+ DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+
+ if (hdata->type = HDMI_TYPE13) {
+ conf_idx = hdmi_v13_conf_index(m);
+ if (conf_idx >= 0)
+ hdata->cur_conf = conf_idx;
+ else
+ DRM_DEBUG_KMS("not supported mode\n");
+ } else {
+ hdmi_v14_mode_set(hdata, m);
+ }
+
+ return 0;
+}
+
+int hdmi_update(struct display_entity *entity)
+{
+ struct hdmi_context *hdata + container_of(entity, struct hdmi_context, entity);
+ DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+
+ hdmi_conf_apply(hdata);
+ return 0;
+}
+
+int hdmi_set_state(struct display_entity *entity,
+ enum display_entity_state state)
+{
+ struct hdmi_context *hdata + container_of(entity, struct hdmi_context, entity);
+
+ DRM_DEBUG_KMS("[%d] %s %d\n", __LINE__, __func__, state);
+
+ switch (state) {
+ case DISPLAY_ENTITY_STATE_OFF:
+ case DISPLAY_ENTITY_STATE_STANDBY:
if (!pm_runtime_suspended(hdata->dev))
pm_runtime_put_sync(hdata->dev);
break;
- default:
- DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
+
+ case DISPLAY_ENTITY_STATE_ON:
+ if (pm_runtime_suspended(hdata->dev))
+ pm_runtime_get_sync(hdata->dev);
break;
+ default:
+ return -EINVAL;
}
+ return 0;
+}
+
+int hdmi_init_audio(struct display_entity *entity,
+ const struct display_entity_audio_params *params)
+{
+ struct hdmi_context *hdata + container_of(entity, struct hdmi_context, entity);
+
+ DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+
+ if (params->type = DISPLAY_ENTITY_AUDIO_I2S)
+ hdmi_i2s_audio_init(hdata, params);
+ else if (params->type = DISPLAY_ENTITY_AUDIO_SPDIF)
+ hdmi_spdif_audio_init(hdata, params);
+ else
+ return -EINVAL;
+
+ return 0;
+}
+
+
+int hdmi_set_audiostate(struct display_entity *entity,
+ enum display_entity_audiostate state)
+{
+ struct hdmi_context *hdata + container_of(entity, struct hdmi_context, entity);
+
+ DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+
+ if (state = DISPLAY_ENTITY_AUDIOSTATE_ON)
+ hdmi_audio_control(hdata, true);
+ else
+ hdmi_audio_control(hdata, false);
+
+ return 0;
}
-static struct exynos_hdmi_ops hdmi_ops = {
- /* display */
- .is_connected = hdmi_is_connected,
- .get_edid = hdmi_get_edid,
- .check_timing = hdmi_check_timing,
-
- /* manager */
- .mode_fixup = hdmi_mode_fixup,
- .mode_set = hdmi_mode_set,
- .get_max_resol = hdmi_get_max_resol,
- .commit = hdmi_commit,
- .dpms = hdmi_dpms,
+struct display_entity_control_ops entity_ctrl_ops = {
+ .get_size = hdmi_get_size,
+ .update = hdmi_update,
+ .set_state = hdmi_set_state,
+ .set_mode = hdmi_set_mode,
+};
+
+struct display_entity_hdmi_control_ops hdmi_ctrl_ops = {
+ .get_edid = hdmi_get_edid,
+ .check_mode = hdmi_check_mode,
+ .init_audio = hdmi_init_audio,
+ .set_audiostate = hdmi_set_audiostate,
+};
+
+struct exynos_hdmi_control_ops exynos_hdmi_ctrl_ops = {
+ .get_hpdstate = hdmi_get_hpdstate,
};
static irqreturn_t hdmi_external_irq_thread(int irq, void *arg)
{
- struct exynos_drm_hdmi_context *ctx = arg;
- struct hdmi_context *hdata = ctx->ctx;
+ struct hdmi_context *hdata = arg;
mutex_lock(&hdata->hdmi_mutex);
hdata->hpd = gpio_get_value(hdata->hpd_gpio);
mutex_unlock(&hdata->hdmi_mutex);
- if (ctx->drm_dev)
- drm_helper_hpd_irq_event(ctx->drm_dev);
+ hdmi_send_hpdevent(&hdata->entity, hdata->hpd);
return IRQ_HANDLED;
}
static irqreturn_t hdmi_internal_irq_thread(int irq, void *arg)
{
- struct exynos_drm_hdmi_context *ctx = arg;
- struct hdmi_context *hdata = ctx->ctx;
+ struct hdmi_context *hdata = arg;
u32 intc_flag;
intc_flag = hdmi_reg_read(hdata, HDMI_INTC_FLAG);
@@ -2017,16 +2038,17 @@ static irqreturn_t hdmi_internal_irq_thread(int irq, void *arg)
DRM_DEBUG_KMS("unplugged\n");
hdmi_reg_writemask(hdata, HDMI_INTC_FLAG, ~0,
HDMI_INTC_FLAG_HPD_UNPLUG);
+ hdata->hpd = 0;
+ hdmi_send_hpdevent(&hdata->entity, hdata->hpd);
}
if (intc_flag & HDMI_INTC_FLAG_HPD_PLUG) {
DRM_DEBUG_KMS("plugged\n");
hdmi_reg_writemask(hdata, HDMI_INTC_FLAG, ~0,
HDMI_INTC_FLAG_HPD_PLUG);
+ hdata->hpd = 1;
+ hdmi_send_hpdevent(&hdata->entity, hdata->hpd);
}
- if (ctx->drm_dev)
- drm_helper_hpd_irq_event(ctx->drm_dev);
-
return IRQ_HANDLED;
}
@@ -2176,16 +2198,20 @@ static struct of_device_id hdmi_match_types[] = {
};
#endif
+static void hdmi_release(struct display_entity *entity)
+{
+ DRM_DEBUG_KMS("[%d][%s]\n", __LINE__, __func__);
+}
+
static int hdmi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct exynos_drm_hdmi_context *drm_hdmi_ctx;
struct hdmi_context *hdata;
struct s5p_hdmi_platform_data *pdata;
struct resource *res;
int ret;
- DRM_DEBUG_KMS("[%d]\n", __LINE__);
+ DRM_DEBUG_KMS("[%d][%s]\n", __LINE__, __func__);
if (pdev->dev.of_node) {
pdata = drm_hdmi_dt_parse_pdata(dev);
@@ -2202,13 +2228,6 @@ static int hdmi_probe(struct platform_device *pdev)
return -EINVAL;
}
- drm_hdmi_ctx = devm_kzalloc(&pdev->dev, sizeof(*drm_hdmi_ctx),
- GFP_KERNEL);
- if (!drm_hdmi_ctx) {
- DRM_ERROR("failed to allocate common hdmi context.\n");
- return -ENOMEM;
- }
-
hdata = devm_kzalloc(&pdev->dev, sizeof(struct hdmi_context),
GFP_KERNEL);
if (!hdata) {
@@ -2218,10 +2237,7 @@ static int hdmi_probe(struct platform_device *pdev)
mutex_init(&hdata->hdmi_mutex);
- drm_hdmi_ctx->ctx = (void *)hdata;
- hdata->parent_ctx = (void *)drm_hdmi_ctx;
-
- platform_set_drvdata(pdev, drm_hdmi_ctx);
+ platform_set_drvdata(pdev, hdata);
if (dev->of_node) {
const struct of_device_id *match;
@@ -2299,7 +2315,7 @@ static int hdmi_probe(struct platform_device *pdev)
ret = request_threaded_irq(hdata->external_irq, NULL,
hdmi_external_irq_thread, IRQF_TRIGGER_RISING |
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
- "hdmi_external", drm_hdmi_ctx);
+ "hdmi_external", hdata);
if (ret) {
DRM_ERROR("failed to register hdmi external interrupt\n");
goto err_hdmiphy;
@@ -2307,24 +2323,31 @@ static int hdmi_probe(struct platform_device *pdev)
ret = request_threaded_irq(hdata->internal_irq, NULL,
hdmi_internal_irq_thread, IRQF_ONESHOT,
- "hdmi_internal", drm_hdmi_ctx);
+ "hdmi_internal", hdata);
if (ret) {
DRM_ERROR("failed to register hdmi internal interrupt\n");
goto err_free_irq;
}
- /* Attach HDMI Driver to common hdmi. */
- exynos_hdmi_drv_attach(drm_hdmi_ctx);
+ pm_runtime_enable(dev);
- /* register specific callbacks to common hdmi. */
- exynos_hdmi_ops_register(&hdmi_ops);
+ hdata->entity.dev = &pdev->dev;
+ hdata->entity.release = hdmi_release;
+ hdata->entity.ops.ctrl = &entity_ctrl_ops;
+ hdata->entity.opt_ctrl.hdmi = &hdmi_ctrl_ops;
- pm_runtime_enable(dev);
+ hdata->entity.private = &exynos_hdmi_ctrl_ops;
+
+ ret = display_entity_register(&hdata->entity);
+ if (ret < 0) {
+ DRM_ERROR("[%d][%s]\n", __LINE__, __func__);
+ return ret;
+ }
return 0;
err_free_irq:
- free_irq(hdata->external_irq, drm_hdmi_ctx);
+ free_irq(hdata->external_irq, hdata);
err_hdmiphy:
i2c_del_driver(&hdmiphy_driver);
err_ddc:
@@ -2335,8 +2358,7 @@ err_ddc:
static int hdmi_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct exynos_drm_hdmi_context *ctx = platform_get_drvdata(pdev);
- struct hdmi_context *hdata = ctx->ctx;
+ struct hdmi_context *hdata = platform_get_drvdata(pdev);
DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
@@ -2357,8 +2379,7 @@ static int hdmi_remove(struct platform_device *pdev)
#ifdef CONFIG_PM_SLEEP
static int hdmi_suspend(struct device *dev)
{
- struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
- struct hdmi_context *hdata = ctx->ctx;
+ struct hdmi_context *hdata = get_hdmi_context(dev);
DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
@@ -2366,8 +2387,7 @@ static int hdmi_suspend(struct device *dev)
disable_irq(hdata->external_irq);
hdata->hpd = false;
- if (ctx->drm_dev)
- drm_helper_hpd_irq_event(ctx->drm_dev);
+ hdmi_send_hpdevent(&hdata->entity, hdata->hpd);
if (pm_runtime_suspended(dev)) {
DRM_DEBUG_KMS("%s : Already suspended\n", __func__);
@@ -2381,8 +2401,7 @@ static int hdmi_suspend(struct device *dev)
static int hdmi_resume(struct device *dev)
{
- struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
- struct hdmi_context *hdata = ctx->ctx;
+ struct hdmi_context *hdata = get_hdmi_context(dev);
DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
@@ -2405,8 +2424,7 @@ static int hdmi_resume(struct device *dev)
#ifdef CONFIG_PM_RUNTIME
static int hdmi_runtime_suspend(struct device *dev)
{
- struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
- struct hdmi_context *hdata = ctx->ctx;
+ struct hdmi_context *hdata = get_hdmi_context(dev);
DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
hdmi_poweroff(hdata);
@@ -2416,8 +2434,7 @@ static int hdmi_runtime_suspend(struct device *dev)
static int hdmi_runtime_resume(struct device *dev)
{
- struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
- struct hdmi_context *hdata = ctx->ctx;
+ struct hdmi_context *hdata = get_hdmi_context(dev);
DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
hdmi_poweron(hdata);
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi_cdf.c b/drivers/gpu/drm/exynos/exynos_hdmi_cdf.c
new file mode 100644
index 0000000..e1c862f
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_hdmi_cdf.c
@@ -0,0 +1,370 @@
+/*
+ * Copyright (C) 2011 Samsung Electronics Co.Ltd
+ * Authors:
+ * Seung-Woo Kim <sw0312.kim@samsung.com>
+ * Inki Dae <inki.dae@samsung.com>
+ * Joonyoung Shim <jy0922.shim@samsung.com>
+ *
+ * Based on drivers/media/video/s5p-tv/hdmi_drv.c
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_crtc_helper.h>
+
+#include "regs-hdmi.h"
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <video/display.h>
+#include "video/exynos_hdmi.h"
+
+#include <drm/exynos_drm.h>
+#include "exynos_drm_drv.h"
+#include "exynos_drm_hdmi.h"
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+
+#include "exynos_hdmi.h"
+
+#define get_hdmi_context(dev) platform_get_drvdata(to_platform_device(dev))
+
+struct hdmi_cdf_context {
+ struct device *dev;
+ struct drm_device *drm_dev;
+ unsigned int hpd;
+ struct display_entity *entity;
+ struct display_entity_notifier notf;
+ struct display_event_subscriber subscriber;
+ void *parent_ctx;
+};
+
+extern bool hdmi_cdf_is_connected(void *ctx)
+{
+ struct hdmi_cdf_context *hdata = (struct hdmi_cdf_context *)ctx;
+
+ DRM_DEBUG_KMS("[%d] %s hpd %d\n", __LINE__, __func__, hdata->hpd);
+ return (bool)hdata->hpd;
+}
+
+extern int hdmi_cdf_get_edid(void *ctx, struct drm_connector *connector,
+ u8 *edid, int len)
+{
+ struct hdmi_cdf_context *hdata = (struct hdmi_cdf_context *)ctx;
+ struct display_entity_edid edid_st;
+ struct edid *raw_edid;
+ int ret;
+
+ DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+
+ ret = display_entity_hdmi_get_edid(hdata->entity, &edid_st);
+ if (ret) {
+ DRM_ERROR("[%d]%s, Edid Read Fail!!! ret = %d\n",
+ __LINE__, __func__, ret);
+ return -EINVAL;
+ }
+
+ raw_edid = (struct edid *)edid_st.edid;
+
+ if (raw_edid) {
+ memcpy(edid, raw_edid, min(edid_st.len, len));
+ kfree(raw_edid);
+ } else {
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+extern int hdmi_cdf_check_timing(void *ctx, struct fb_videomode *timing)
+{
+ struct hdmi_cdf_context *hdata = (struct hdmi_cdf_context *)ctx;
+ int ret;
+
+ ret = display_entity_hdmi_check_mode(hdata->entity,
+ (struct videomode *)timing);
+ if (ret) {
+ DRM_DEBUG_KMS("[%d]%s, Mode NOT Supported! %dx%d@%d%s\n",
+ __LINE__, __func__, timing->xres, timing->yres,
+ timing->refresh, timing->flag
+ & FB_VMODE_INTERLACED ? "I" : "P");
+ return -EINVAL;
+ }
+
+ DRM_DEBUG_KMS("[%d]%s, Mode Supported! %dx%d@%d%s\n", __LINE__,
+ __func__, timing->xres, timing->yres, timing->refresh,
+ timing->flag & FB_VMODE_INTERLACED ? "I" : "P");
+
+ return 0;
+}
+
+extern int hdmi_cdf_power_on(void *ctx, int mode)
+{
+ return 0;
+}
+
+extern void hdmi_cdf_mode_fixup(void *ctx, struct drm_connector *connector,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ struct hdmi_cdf_context *hdata = (struct hdmi_cdf_context *)ctx;
+ struct drm_display_mode *m;
+ struct fb_videomode timing;
+ int index;
+
+ DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+
+ drm_mode_set_crtcinfo(adjusted_mode, 0);
+
+ timing.xres = adjusted_mode->hdisplay;
+ timing.yres = adjusted_mode->vdisplay;
+ timing.refresh = adjusted_mode->vrefresh;
+ timing.pixclock = adjusted_mode->clock * 1000;
+ timing.flag = ((adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) ?
+ FB_VMODE_INTERLACED : 0);
+
+ index = display_entity_hdmi_check_mode(hdata->entity,
+ (struct videomode *)&timing);
+
+ /* just return if user desired mode exists. */
+ if (index = 0)
+ return;
+
+ /*
+ * otherwise, find the most suitable mode among modes and change it
+ * to adjusted_mode.
+ */
+ list_for_each_entry(m, &connector->modes, head) {
+
+ timing.xres = m->hdisplay;
+ timing.yres = m->vdisplay;
+ timing.refresh = m->vrefresh;
+ timing.pixclock = m->clock * 1000;
+ timing.flag = ((m->flags & DRM_MODE_FLAG_INTERLACE) ?
+ FB_VMODE_INTERLACED : 0);
+
+ index = display_entity_hdmi_check_mode(hdata->entity,
+ (struct videomode *)&timing);
+
+ if (index = 0) {
+ struct drm_mode_object base;
+ struct list_head head;
+
+ DRM_INFO("desired mode doesn't exist so\n");
+ DRM_INFO("use most suitable mode.\n");
+
+ DRM_DEBUG_KMS("Adjusted Mode: [%d]x[%d][%d]Hz\n",
+ m->hdisplay, m->vdisplay, m->vrefresh);
+
+ /* preserve display mode header while copying. */
+ head = adjusted_mode->head;
+ base = adjusted_mode->base;
+ memcpy(adjusted_mode, m, sizeof(*m));
+ adjusted_mode->head = head;
+ adjusted_mode->base = base;
+ break;
+ }
+ }
+}
+
+extern void hdmi_cdf_mode_set(void *ctx, void *mode)
+{
+ struct hdmi_cdf_context *hdata = (struct hdmi_cdf_context *)ctx;
+ struct drm_display_mode *m = mode;
+ int ret;
+
+ DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+
+ ret = display_entity_set_mode(hdata->entity, (struct videomode *)m);
+ if (ret) {
+ DRM_DEBUG_KMS("[%d]%s, Mode NOT Set! %dx%d@%d%s\n",
+ __LINE__, __func__, m->hdisplay, m->vdisplay,
+ m->vrefresh, (m->flags & DRM_MODE_FLAG_INTERLACE)
+ ? "I" : "P");
+ }
+}
+
+extern void hdmi_cdf_get_max_resol(void *ctx, unsigned int *width,
+ unsigned int *height)
+{
+ struct hdmi_cdf_context *hdata = (struct hdmi_cdf_context *)ctx;
+
+ DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+
+ display_entity_get_size(hdata->entity, width, height);
+}
+
+extern void hdmi_cdf_commit(void *ctx)
+{
+ struct hdmi_cdf_context *hdata = (struct hdmi_cdf_context *)ctx;
+
+ DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+
+ display_entity_update(hdata->entity);
+}
+
+extern void hdmi_cdf_dpms(void *ctx, int mode)
+{
+ struct hdmi_cdf_context *hdata = (struct hdmi_cdf_context *)ctx;
+ enum display_entity_state state;
+
+ DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+
+ switch (mode) {
+ case DRM_MODE_DPMS_ON:
+ state = DISPLAY_ENTITY_STATE_ON;
+ break;
+ case DRM_MODE_DPMS_STANDBY:
+ state = DISPLAY_ENTITY_STATE_STANDBY;
+ break;
+ case DRM_MODE_DPMS_SUSPEND:
+ case DRM_MODE_DPMS_OFF:
+ state = DISPLAY_ENTITY_STATE_STANDBY;
+ break;
+ default:
+ DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
+ return;
+ }
+
+ display_entity_set_state(hdata->entity, state);
+}
+
+void event_notify(struct display_entity *entity,
+ enum display_entity_event_type type, unsigned int value,
+ void *context)
+{
+ struct hdmi_cdf_context *hdata = (struct hdmi_cdf_context *)context;
+ struct exynos_drm_hdmi_context *ctx = get_hdmi_context(hdata->dev);
+
+ if (type = DISPLAY_ENTITY_HDMI_HOTPLUG) {
+ DRM_DEBUG_KMS("[%d][%s] hpd(%d)\n",
+ __LINE__, __func__, value);
+ hdata->hpd = value;
+
+ if (ctx->drm_dev)
+ drm_helper_hpd_irq_event(ctx->drm_dev);
+ }
+}
+
+int display_entity_notification(struct display_entity_notifier *notf,
+ struct display_entity *entity, int status)
+{
+ struct hdmi_cdf_context *hdata = container_of(notf,
+ struct hdmi_cdf_context, notf);
+ struct exynos_hdmi_control_ops *exynos_ops + (struct exynos_hdmi_control_ops *)entity->private;
+
+ if (status != DISPLAY_ENTITY_NOTIFIER_CONNECT && entity)
+ return -EINVAL;
+
+ DRM_DEBUG_KMS("[%d][%s] NOTIFIER_CONNECT\n", __LINE__, __func__);
+
+ hdata->entity = entity;
+
+ hdata->subscriber.context = hdata;
+ hdata->subscriber.notify = event_notify;
+ display_entity_subscribe_event(entity, &hdata->subscriber);
+
+ exynos_ops->get_hpdstate(entity, &hdata->hpd);
+ return 0;
+}
+
+static struct exynos_hdmi_ops hdmi_ops = {
+ /* display */
+ .is_connected = hdmi_cdf_is_connected,
+ .get_edid = hdmi_cdf_get_edid,
+ .check_timing = hdmi_cdf_check_timing,
+
+ /* manager */
+ .mode_fixup = hdmi_cdf_mode_fixup,
+ .mode_set = hdmi_cdf_mode_set,
+ .get_max_resol = hdmi_cdf_get_max_resol,
+ .commit = hdmi_cdf_commit,
+ .dpms = hdmi_cdf_dpms,
+};
+
+static int hdmi_cdf_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *dev_node;
+ struct platform_device *disp_pdev;
+ struct exynos_drm_hdmi_context *drm_hdmi_ctx;
+ struct hdmi_cdf_context *hdata;
+ int ret;
+
+ DRM_DEBUG_KMS("[%d][%s]\n", __LINE__, __func__);
+
+ dev_node = of_find_compatible_node(NULL, NULL,
+ "samsung,exynos5-hdmi");
+ if (!dev_node) {
+ DRM_DEBUG_KMS("[ERROR][%d][%s] dt node not found.\n",
+ __LINE__, __func__);
+ return -EINVAL;
+ }
+
+ disp_pdev = of_find_device_by_node(dev_node);
+ if (!disp_pdev) {
+ DRM_DEBUG_KMS("[ERROR][%d][%s] No pdev\n",
+ __LINE__, __func__);
+ return -EINVAL;
+ }
+
+ drm_hdmi_ctx = devm_kzalloc(&pdev->dev, sizeof(*drm_hdmi_ctx),
+ GFP_KERNEL);
+ if (!drm_hdmi_ctx) {
+ DRM_ERROR("failed to allocate common hdmi context.\n");
+ return -ENOMEM;
+ }
+
+ hdata = devm_kzalloc(&pdev->dev, sizeof(struct hdmi_cdf_context),
+ GFP_KERNEL);
+ if (!hdata) {
+ DRM_ERROR("out of memory\n");
+ return -ENOMEM;
+ }
+
+ drm_hdmi_ctx->ctx = (void *)hdata;
+ hdata->parent_ctx = (void *)drm_hdmi_ctx;
+
+ platform_set_drvdata(pdev, drm_hdmi_ctx);
+
+ /* Attach HDMI Driver to common hdmi. */
+ exynos_hdmi_drv_attach(drm_hdmi_ctx);
+
+ /* register specific callbacks to common hdmi. */
+ exynos_hdmi_ops_register(&hdmi_ops);
+
+ hdata->dev = dev;
+ hdata->notf.dev = &disp_pdev->dev;
+ hdata->notf.notify = display_entity_notification;
+
+ ret = display_entity_register_notifier(&hdata->notf);
+ if (ret) {
+ DRM_DEBUG_KMS("[ERROR][%d][%s] entity registe failed.\n",
+ __LINE__, __func__);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int hdmi_cdf_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+struct platform_driver hdmi_cdf_driver = {
+ .probe = hdmi_cdf_probe,
+ .remove = hdmi_cdf_remove,
+ .driver = {
+ .name = "exynos-hdmi-cdf",
+ .owner = THIS_MODULE,
+ },
+};
+
diff --git a/include/video/exynos_hdmi.h b/include/video/exynos_hdmi.h
new file mode 100644
index 0000000..cc8d613
--- /dev/null
+++ b/include/video/exynos_hdmi.h
@@ -0,0 +1,25 @@
+/*
+ * Display Core
+ *
+ * Copyright (C) 2012 Renesas Solutions Corp.
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __EXYNOS_HDMI_H__
+#define __EXYNOS_HDMI_H__
+
+#include <linux/kref.h>
+#include <linux/list.h>
+#include <linux/module.h>
+
+struct exynos_hdmi_control_ops {
+ int (*get_hpdstate)(struct display_entity *entity,
+ unsigned int *hpd_state);
+};
+
+#endif /* __EXYNOS_HDMI_H__ */
--
1.8.0
^ permalink raw reply related
* [RFC PATCH v2 2/5] drm/edid: temporarily exposing generic edid-read interface from drm
From: Rahul Sharma @ 2013-02-07 11:49 UTC (permalink / raw)
To: linux-media, dri-devel, alsa-devel, linux-fbdev
Cc: tomi.valkeinen, laurent.pinchart, broonie, inki.dae,
kyungmin.park, r.sh.open, joshi
It exposes generic interface from drm_edid.c to get the edid data and length
by any display entity. Once I get clear idea about edid handling in CDF, I need
to revert these temporary changes.
Signed-off-by: Rahul Sharma <rahul.sharma@samsung.com>
---
drivers/gpu/drm/drm_edid.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 88 insertions(+)
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 5a3770f..567a565 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -31,6 +31,7 @@
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/module.h>
+#include <video/display.h>
#include <drm/drmP.h>
#include <drm/drm_edid.h>
#include "drm_edid_modes.h"
@@ -386,6 +387,93 @@ out:
return NULL;
}
+int generic_drm_do_get_edid(struct i2c_adapter *adapter,
+ struct display_entity_edid *edid)
+{
+ int i, j = 0, valid_extensions = 0;
+ u8 *block, *new;
+ bool print_bad_edid = 0;
+
+ block = kmalloc(EDID_LENGTH, GFP_KERNEL);
+ if (!block)
+ return -ENOMEM;
+
+ /* base block fetch */
+ for (i = 0; i < 4; i++) {
+ if (drm_do_probe_ddc_edid(adapter, block, 0, EDID_LENGTH))
+ goto out;
+ if (drm_edid_block_valid(block, 0, print_bad_edid))
+ break;
+ if (i = 0 && drm_edid_is_zero(block, EDID_LENGTH))
+ goto carp;
+ }
+ if (i = 4)
+ goto carp;
+
+ /* if there's no extensions, we're done */
+ if (block[0x7e] = 0) {
+ edid->edid = block;
+ edid->len = EDID_LENGTH;
+ return 0;
+ }
+
+ new = krealloc(block, (block[0x7e] + 1) * EDID_LENGTH, GFP_KERNEL);
+ if (!new)
+ goto out;
+ block = new;
+ edid->len = (block[0x7e] + 1) * EDID_LENGTH;
+
+ for (j = 1; j <= block[0x7e]; j++) {
+ for (i = 0; i < 4; i++) {
+ if (drm_do_probe_ddc_edid(adapter,
+ block + (valid_extensions + 1) * EDID_LENGTH,
+ j, EDID_LENGTH))
+ goto out;
+ if (drm_edid_block_valid(block + (valid_extensions + 1)*
+ EDID_LENGTH, j, print_bad_edid)) {
+ valid_extensions++;
+ break;
+ }
+ }
+ if (i = 4)
+ DRM_DEBUG_KMS("Ignoring inv lock %d.\n", j);
+ }
+
+ if (valid_extensions != block[0x7e]) {
+ block[EDID_LENGTH-1] += block[0x7e] - valid_extensions;
+ block[0x7e] = valid_extensions;
+ new = krealloc(block, (valid_extensions + 1)*
+ EDID_LENGTH, GFP_KERNEL);
+ if (!new)
+ goto out;
+ block = new;
+ edid->len = (valid_extensions + 1) * EDID_LENGTH;
+ }
+
+ edid->edid = block;
+ return 0;
+
+carp:
+ if (print_bad_edid)
+ DRM_DEBUG_KMS("[ERROR]: EDID block %d invalid.\n", j);
+
+out:
+ kfree(block);
+ return -ENOMEM;
+}
+
+
+int generic_drm_get_edid(struct i2c_adapter *adapter,
+ struct display_entity_edid *edid)
+{
+ int ret = -EINVAL;
+ if (drm_probe_ddc(adapter))
+ ret = generic_drm_do_get_edid(adapter, edid);
+
+ return ret;
+}
+EXPORT_SYMBOL(generic_drm_get_edid);
+
/**
* Probe DDC presence.
*
--
1.8.0
^ permalink raw reply related
* Re: [RFC PATCH 4/4] video: display: Add Samsung s6e8ax0 display panel driver
From: Tomasz Figa @ 2013-02-07 10:18 UTC (permalink / raw)
To: Vikas Sajjan
Cc: dri-devel, linux-fbdev, linux-samsung-soc, kyungmin.park,
m.szyprowski, tomasz.figa, Daniel Vetter, Marcus Lorentzon,
Laurent Pinchart, rob, tomi.valkeinen, inki.dae, dh09.lee,
ville.syrjala, s.nawrocki, aditya.ps, sunil joshi
In-Reply-To: <CAGm_ybj-oN6OtVr5EAcH5w=cRfkVphfrwHTer40wgas1venbBQ@mail.gmail.com>
On Thursday 07 of February 2013 15:04:30 Vikas Sajjan wrote:
> Hi Figa,
>
> On Wed, Jan 30, 2013 at 9:09 PM, Tomasz Figa <t.figa@samsung.com> wrote:
> > This patch adds Common Display Framework driver for Samsung s6e8ax0
> > MIPI DSI display panel.
> >
> > Signed-off-by: Tomasz Figa <t.figa@samsung.com>
> > Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> > ---
> >
> > drivers/video/display/Kconfig | 3 +
> > drivers/video/display/Makefile | 1 +
> > drivers/video/display/panel-s6e8ax0.c | 1027
> > +++++++++++++++++++++++++++++++++ include/video/panel-s6e8ax0.h
> > | 41 ++
> > 4 files changed, 1072 insertions(+)
> > create mode 100644 drivers/video/display/panel-s6e8ax0.c
> > create mode 100644 include/video/panel-s6e8ax0.h
> >
[snip]
> > + lcd->ld = lcd_device_register("s6e8ax0", &pdev->dev, lcd,
> > + &s6e8ax0_lcd_ops);
> > + if (IS_ERR(lcd->ld)) {
> > + dev_err(&pdev->dev, "failed to register lcd ops.\n");
> > + ret = PTR_ERR(lcd->ld);
> > + goto err_lcd_register;
> > + }
> > +
> > + lcd->bd = backlight_device_register("s6e8ax0-bl", &pdev->dev,
> > lcd, + &s6e8ax0_backlight_ops, NULL);
> > + if (IS_ERR(lcd->bd)) {
> > + dev_err(&pdev->dev, "failed to register backlight
> > ops.\n"); + ret = PTR_ERR(lcd->bd);
> > + goto err_backlight_register;
> > + }
> > +
>
> I think we should try to remove the dependency with LCD framework and
> Backlight framework, and incorporate those functionality as par of
> CDF.
> you can refer to my similar patch "Make s6e8ax0 panel driver compliant
> with CDF" (
> http://comments.gmane.org/gmane.linux.drivers.video-input-infrastructur
> e/59187 ) which i had posted couple of weeks back, where I made an
> attempt to remove "lcd_ops" dependency.
Yes, I have written in the cover letter that those interfaces is just a
hack to be able to control the display from userspace in current state of
CDF.
I agree that CDF will have to be extended with backlight/brightness
control. However currently CDF does not expose any interface to userspace.
Laurent, what's your opinion on this?
P.S. Tomasz is my first name.
Best regards,
--
Tomasz Figa
Samsung Poland R&D Center
SW Solution Development, Linux Platform
^ permalink raw reply
* Re: [RFC PATCH 4/4] video: display: Add Samsung s6e8ax0 display panel driver
From: Vikas Sajjan @ 2013-02-07 9:46 UTC (permalink / raw)
To: Tomasz Figa
Cc: dri-devel, linux-fbdev, linux-samsung-soc, kyungmin.park,
m.szyprowski, tomasz.figa, Daniel Vetter, Marcus Lorentzon,
Laurent Pinchart, rob, tomi.valkeinen, inki.dae, dh09.lee,
ville.syrjala, s.nawrocki, aditya.ps, sunil joshi
In-Reply-To: <1359560343-31636-5-git-send-email-t.figa@samsung.com>
Hi Figa,
On Wed, Jan 30, 2013 at 9:09 PM, Tomasz Figa <t.figa@samsung.com> wrote:
> This patch adds Common Display Framework driver for Samsung s6e8ax0
> MIPI DSI display panel.
>
> Signed-off-by: Tomasz Figa <t.figa@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> ---
> drivers/video/display/Kconfig | 3 +
> drivers/video/display/Makefile | 1 +
> drivers/video/display/panel-s6e8ax0.c | 1027 +++++++++++++++++++++++++++++++++
> include/video/panel-s6e8ax0.h | 41 ++
> 4 files changed, 1072 insertions(+)
> create mode 100644 drivers/video/display/panel-s6e8ax0.c
> create mode 100644 include/video/panel-s6e8ax0.h
>
> diff --git a/drivers/video/display/Kconfig b/drivers/video/display/Kconfig
> index b14527a..f19ec04 100644
> --- a/drivers/video/display/Kconfig
> +++ b/drivers/video/display/Kconfig
> @@ -5,6 +5,9 @@ menuconfig DISPLAY_CORE
>
> if DISPLAY_CORE
>
> +config DISPLAY_PANEL_S6E8AX0
> + tristate "S6E8AX0 DSI video mode panel"
> + select OF_VIDEOMODE
>
> config DISPLAY_SOURCE_EXYNOS_DSI
> tristate "Samsung SoC MIPI DSI Master"
> diff --git a/drivers/video/display/Makefile b/drivers/video/display/Makefile
> index 40a283a..0f7fdc2 100644
> --- a/drivers/video/display/Makefile
> +++ b/drivers/video/display/Makefile
> @@ -1,2 +1,3 @@
> obj-$(CONFIG_DISPLAY_CORE) += display-core.o
> +obj-$(CONFIG_DISPLAY_PANEL_S6E8AX0) += panel-s6e8ax0.o
> obj-$(CONFIG_DISPLAY_SOURCE_EXYNOS_DSI) += source-exynos_dsi.o
> diff --git a/drivers/video/display/panel-s6e8ax0.c b/drivers/video/display/panel-s6e8ax0.c
> new file mode 100644
> index 0000000..4c09fe2
> --- /dev/null
> +++ b/drivers/video/display/panel-s6e8ax0.c
> @@ -0,0 +1,1027 @@
> +/* linux/drivers/video/exynos/s6e8ax0.c
> + *
> + * MIPI-DSI based s6e8ax0 AMOLED lcd 4.65 inch panel driver.
> + *
> + * Inki Dae, <inki.dae@samsung.com>
> + * Donghwa Lee, <dh09.lee@samsung.com>
> + * Tomasz Figa, <t.figa@samsung.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/errno.h>
> +#include <linux/mutex.h>
> +#include <linux/wait.h>
> +#include <linux/ctype.h>
> +#include <linux/io.h>
> +#include <linux/delay.h>
> +#include <linux/irq.h>
> +#include <linux/interrupt.h>
> +
> +#include <linux/fb.h>
> +#include <linux/gpio.h>
> +#include <linux/lcd.h>
> +#include <linux/of.h>
> +#include <linux/of_gpio.h>
> +#include <linux/of_videomode.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/backlight.h>
> +#include <linux/regulator/consumer.h>
> +
> +#include <video/display.h>
> +#include <video/mipi_display.h>
> +#include <video/panel-s6e8ax0.h>
> +
> +#define LDI_MTP_LENGTH 24
> +#define DSIM_PM_STABLE_TIME 10
> +#define MIN_BRIGHTNESS 0
> +#define MAX_BRIGHTNESS 24
> +#define GAMMA_TABLE_COUNT 26
> +
> +struct s6e8ax0 {
> + struct display_entity entity;
> + struct device *dev;
> +
> + struct s6e8ax0_platform_data *pdata;
> + struct backlight_device *bd;
> + struct lcd_device *ld;
> + struct regulator_bulk_data supplies[2];
> +
> + bool enabled;
> + unsigned int id;
> + unsigned int gamma;
> + unsigned int acl_enable;
> + unsigned int cur_acl;
> + int power;
> +
> + unsigned int reset_gpio;
> +};
> +
> +#define to_panel(p) container_of(p, struct s6e8ax0, entity)
> +
> +static const unsigned char s6e8ax0_22_gamma_30[] = {
> + 0xfa, 0x01, 0x60, 0x10, 0x60, 0xf5, 0x00, 0xff, 0xad, 0xaf,
> + 0xbA, 0xc3, 0xd8, 0xc5, 0x9f, 0xc6, 0x9e, 0xc1, 0xdc, 0xc0,
> + 0x00, 0x61, 0x00, 0x5a, 0x00, 0x74,
> +};
> +
> +static const unsigned char s6e8ax0_22_gamma_50[] = {
> + 0xfa, 0x01, 0x60, 0x10, 0x60, 0xe8, 0x1f, 0xf7, 0xad, 0xc0,
> + 0xb5, 0xc4, 0xdc, 0xc4, 0x9e, 0xc6, 0x9c, 0xbb, 0xd8, 0xbb,
> + 0x00, 0x70, 0x00, 0x68, 0x00, 0x86,
> +};
> +
> +static const unsigned char s6e8ax0_22_gamma_60[] = {
> + 0xfa, 0x01, 0x60, 0x10, 0x60, 0xde, 0x1f, 0xef, 0xad, 0xc4,
> + 0xb3, 0xc3, 0xdd, 0xc4, 0x9e, 0xc6, 0x9c, 0xbc, 0xd6, 0xba,
> + 0x00, 0x75, 0x00, 0x6e, 0x00, 0x8d,
> +};
> +
> +static const unsigned char s6e8ax0_22_gamma_70[] = {
> + 0xfa, 0x01, 0x60, 0x10, 0x60, 0xd8, 0x1f, 0xe7, 0xaf, 0xc8,
> + 0xb4, 0xc4, 0xdd, 0xc3, 0x9d, 0xc6, 0x9c, 0xbb, 0xd6, 0xb9,
> + 0x00, 0x7a, 0x00, 0x72, 0x00, 0x93,
> +};
> +
> +static const unsigned char s6e8ax0_22_gamma_80[] = {
> + 0xfa, 0x01, 0x60, 0x10, 0x60, 0xc9, 0x1f, 0xde, 0xae, 0xc9,
> + 0xb1, 0xc3, 0xdd, 0xc2, 0x9d, 0xc5, 0x9b, 0xbc, 0xd6, 0xbb,
> + 0x00, 0x7f, 0x00, 0x77, 0x00, 0x99,
> +};
> +
> +static const unsigned char s6e8ax0_22_gamma_90[] = {
> + 0xfa, 0x01, 0x60, 0x10, 0x60, 0xc7, 0x1f, 0xd9, 0xb0, 0xcc,
> + 0xb2, 0xc3, 0xdc, 0xc1, 0x9c, 0xc6, 0x9c, 0xbc, 0xd4, 0xb9,
> + 0x00, 0x83, 0x00, 0x7b, 0x00, 0x9e,
> +};
> +
> +static const unsigned char s6e8ax0_22_gamma_100[] = {
> + 0xfa, 0x01, 0x60, 0x10, 0x60, 0xbd, 0x80, 0xcd, 0xba, 0xce,
> + 0xb3, 0xc4, 0xde, 0xc3, 0x9c, 0xc4, 0x9, 0xb8, 0xd3, 0xb6,
> + 0x00, 0x88, 0x00, 0x80, 0x00, 0xa5,
> +};
> +
> +static const unsigned char s6e8ax0_22_gamma_120[] = {
> + 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb9, 0x95, 0xc8, 0xb1, 0xcf,
> + 0xb2, 0xc6, 0xdf, 0xc5, 0x9b, 0xc3, 0x99, 0xb6, 0xd2, 0xb6,
> + 0x00, 0x8f, 0x00, 0x86, 0x00, 0xac,
> +};
> +
> +static const unsigned char s6e8ax0_22_gamma_130[] = {
> + 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb7, 0xa0, 0xc7, 0xb1, 0xd0,
> + 0xb2, 0xc4, 0xdd, 0xc3, 0x9a, 0xc3, 0x98, 0xb6, 0xd0, 0xb4,
> + 0x00, 0x92, 0x00, 0x8a, 0x00, 0xb1,
> +};
> +
> +static const unsigned char s6e8ax0_22_gamma_140[] = {
> + 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb7, 0xa0, 0xc5, 0xb2, 0xd0,
> + 0xb3, 0xc3, 0xde, 0xc3, 0x9b, 0xc2, 0x98, 0xb6, 0xd0, 0xb4,
> + 0x00, 0x95, 0x00, 0x8d, 0x00, 0xb5,
> +};
> +
> +static const unsigned char s6e8ax0_22_gamma_150[] = {
> + 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb3, 0xa0, 0xc2, 0xb2, 0xd0,
> + 0xb2, 0xc1, 0xdd, 0xc2, 0x9b, 0xc2, 0x98, 0xb4, 0xcf, 0xb1,
> + 0x00, 0x99, 0x00, 0x90, 0x00, 0xba,
> +};
> +
> +static const unsigned char s6e8ax0_22_gamma_160[] = {
> + 0xfa, 0x01, 0x60, 0x10, 0x60, 0xaf, 0xa5, 0xbf, 0xb0, 0xd0,
> + 0xb1, 0xc3, 0xde, 0xc2, 0x99, 0xc1, 0x97, 0xb4, 0xce, 0xb1,
> + 0x00, 0x9c, 0x00, 0x93, 0x00, 0xbe,
> +};
> +
> +static const unsigned char s6e8ax0_22_gamma_170[] = {
> + 0xfa, 0x01, 0x60, 0x10, 0x60, 0xaf, 0xb5, 0xbf, 0xb1, 0xd1,
> + 0xb1, 0xc3, 0xde, 0xc3, 0x99, 0xc0, 0x96, 0xb4, 0xce, 0xb1,
> + 0x00, 0x9f, 0x00, 0x96, 0x00, 0xc2,
> +};
> +
> +static const unsigned char s6e8ax0_22_gamma_180[] = {
> + 0xfa, 0x01, 0x60, 0x10, 0x60, 0xaf, 0xb7, 0xbe, 0xb3, 0xd2,
> + 0xb3, 0xc3, 0xde, 0xc2, 0x97, 0xbf, 0x95, 0xb4, 0xcd, 0xb1,
> + 0x00, 0xa2, 0x00, 0x99, 0x00, 0xc5,
> +};
> +
> +static const unsigned char s6e8ax0_22_gamma_190[] = {
> + 0xfa, 0x01, 0x60, 0x10, 0x60, 0xaf, 0xb9, 0xbe, 0xb2, 0xd2,
> + 0xb2, 0xc3, 0xdd, 0xc3, 0x98, 0xbf, 0x95, 0xb2, 0xcc, 0xaf,
> + 0x00, 0xa5, 0x00, 0x9c, 0x00, 0xc9,
> +};
> +
> +static const unsigned char s6e8ax0_22_gamma_200[] = {
> + 0xfa, 0x01, 0x60, 0x10, 0x60, 0xaf, 0xb9, 0xbc, 0xb2, 0xd2,
> + 0xb1, 0xc4, 0xdd, 0xc3, 0x97, 0xbe, 0x95, 0xb1, 0xcb, 0xae,
> + 0x00, 0xa8, 0x00, 0x9f, 0x00, 0xcd,
> +};
> +
> +static const unsigned char s6e8ax0_22_gamma_210[] = {
> + 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb1, 0xc1, 0xbd, 0xb1, 0xd1,
> + 0xb1, 0xc2, 0xde, 0xc2, 0x97, 0xbe, 0x94, 0xB0, 0xc9, 0xad,
> + 0x00, 0xae, 0x00, 0xa4, 0x00, 0xd4,
> +};
> +
> +static const unsigned char s6e8ax0_22_gamma_220[] = {
> + 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb1, 0xc7, 0xbd, 0xb1, 0xd1,
> + 0xb1, 0xc2, 0xdd, 0xc2, 0x97, 0xbd, 0x94, 0xb0, 0xc9, 0xad,
> + 0x00, 0xad, 0x00, 0xa2, 0x00, 0xd3,
> +};
> +
> +static const unsigned char s6e8ax0_22_gamma_230[] = {
> + 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb1, 0xc3, 0xbd, 0xb2, 0xd1,
> + 0xb1, 0xc3, 0xdd, 0xc1, 0x96, 0xbd, 0x94, 0xb0, 0xc9, 0xad,
> + 0x00, 0xb0, 0x00, 0xa7, 0x00, 0xd7,
> +};
> +
> +static const unsigned char s6e8ax0_22_gamma_240[] = {
> + 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb1, 0xcb, 0xbd, 0xb1, 0xd2,
> + 0xb1, 0xc3, 0xdD, 0xc2, 0x95, 0xbd, 0x93, 0xaf, 0xc8, 0xab,
> + 0x00, 0xb3, 0x00, 0xa9, 0x00, 0xdb,
> +};
> +
> +static const unsigned char s6e8ax0_22_gamma_250[] = {
> + 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb3, 0xcc, 0xbe, 0xb0, 0xd2,
> + 0xb0, 0xc3, 0xdD, 0xc2, 0x94, 0xbc, 0x92, 0xae, 0xc8, 0xab,
> + 0x00, 0xb6, 0x00, 0xab, 0x00, 0xde,
> +};
> +
> +static const unsigned char s6e8ax0_22_gamma_260[] = {
> + 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb3, 0xd0, 0xbe, 0xaf, 0xd1,
> + 0xaf, 0xc2, 0xdd, 0xc1, 0x96, 0xbc, 0x93, 0xaf, 0xc8, 0xac,
> + 0x00, 0xb7, 0x00, 0xad, 0x00, 0xe0,
> +};
> +
> +static const unsigned char s6e8ax0_22_gamma_270[] = {
> + 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb2, 0xcF, 0xbd, 0xb0, 0xd2,
> + 0xaf, 0xc2, 0xdc, 0xc1, 0x95, 0xbd, 0x93, 0xae, 0xc6, 0xaa,
> + 0x00, 0xba, 0x00, 0xb0, 0x00, 0xe4,
> +};
> +
> +static const unsigned char s6e8ax0_22_gamma_280[] = {
> + 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb2, 0xd0, 0xbd, 0xaf, 0xd0,
> + 0xad, 0xc4, 0xdd, 0xc3, 0x95, 0xbd, 0x93, 0xac, 0xc5, 0xa9,
> + 0x00, 0xbd, 0x00, 0xb2, 0x00, 0xe7,
> +};
> +
> +static const unsigned char s6e8ax0_22_gamma_300[] = {
> + 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb5, 0xd3, 0xbd, 0xb1, 0xd2,
> + 0xb0, 0xc0, 0xdc, 0xc0, 0x94, 0xba, 0x91, 0xac, 0xc5, 0xa9,
> + 0x00, 0xc2, 0x00, 0xb7, 0x00, 0xed,
> +};
> +
> +static const unsigned char *s6e8ax0_22_gamma_table[] = {
> + s6e8ax0_22_gamma_30,
> + s6e8ax0_22_gamma_50,
> + s6e8ax0_22_gamma_60,
> + s6e8ax0_22_gamma_70,
> + s6e8ax0_22_gamma_80,
> + s6e8ax0_22_gamma_90,
> + s6e8ax0_22_gamma_100,
> + s6e8ax0_22_gamma_120,
> + s6e8ax0_22_gamma_130,
> + s6e8ax0_22_gamma_140,
> + s6e8ax0_22_gamma_150,
> + s6e8ax0_22_gamma_160,
> + s6e8ax0_22_gamma_170,
> + s6e8ax0_22_gamma_180,
> + s6e8ax0_22_gamma_190,
> + s6e8ax0_22_gamma_200,
> + s6e8ax0_22_gamma_210,
> + s6e8ax0_22_gamma_220,
> + s6e8ax0_22_gamma_230,
> + s6e8ax0_22_gamma_240,
> + s6e8ax0_22_gamma_250,
> + s6e8ax0_22_gamma_260,
> + s6e8ax0_22_gamma_270,
> + s6e8ax0_22_gamma_280,
> + s6e8ax0_22_gamma_300,
> +};
> +
> +static void s6e8ax0_panel_cond(struct s6e8ax0 *lcd)
> +{
> + static const unsigned char data_to_send[] = {
> + 0xf8, 0x3d, 0x35, 0x00, 0x00, 0x00, 0x93, 0x00, 0x3c, 0x7d,
> + 0x08, 0x27, 0x7d, 0x3f, 0x00, 0x00, 0x00, 0x20, 0x04, 0x08,
> + 0x6e, 0x00, 0x00, 0x00, 0x02, 0x08, 0x08, 0x23, 0x23, 0xc0,
> + 0xc8, 0x08, 0x48, 0xc1, 0x00, 0xc1, 0xff, 0xff, 0xc8
> + };
> + static const unsigned char data_to_send_panel_reverse[] = {
> + 0xf8, 0x19, 0x35, 0x00, 0x00, 0x00, 0x93, 0x00, 0x3c, 0x7d,
> + 0x08, 0x27, 0x7d, 0x3f, 0x00, 0x00, 0x00, 0x20, 0x04, 0x08,
> + 0x6e, 0x00, 0x00, 0x00, 0x02, 0x08, 0x08, 0x23, 0x23, 0xc0,
> + 0xc1, 0x01, 0x41, 0xc1, 0x00, 0xc1, 0xf6, 0xf6, 0xc1
> + };
> +
> + if (lcd->pdata->panel_reverse)
> + dsi_dcs_write(lcd->entity.source, 0,
> + data_to_send_panel_reverse,
> + ARRAY_SIZE(data_to_send_panel_reverse));
> + else
> + dsi_dcs_write(lcd->entity.source, 0,
> + data_to_send, ARRAY_SIZE(data_to_send));
> +}
> +
> +static void s6e8ax0_display_cond(struct s6e8ax0 *lcd)
> +{
> + static const unsigned char data_to_send[] = {
> + 0xf2, 0x80, 0x03, 0x0d
> + };
> +
> + dsi_dcs_write(lcd->entity.source, 0,
> + data_to_send, ARRAY_SIZE(data_to_send));
> +}
> +
> +/* Gamma 2.2 Setting (200cd, 7500K, 10MPCD) */
> +static void s6e8ax0_gamma_cond(struct s6e8ax0 *lcd)
> +{
> + unsigned int gamma = lcd->bd->props.brightness;
> +
> + dsi_dcs_write(lcd->entity.source, 0,
> + s6e8ax0_22_gamma_table[gamma],
> + GAMMA_TABLE_COUNT);
> +}
> +
> +static void s6e8ax0_gamma_update(struct s6e8ax0 *lcd)
> +{
> + static const unsigned char data_to_send[] = {
> + 0xf7, 0x03
> + };
> +
> + dsi_dcs_write(lcd->entity.source, 0, data_to_send,
> + ARRAY_SIZE(data_to_send));
> +}
> +
> +static void s6e8ax0_etc_cond1(struct s6e8ax0 *lcd)
> +{
> + static const unsigned char data_to_send[] = {
> + 0xd1, 0xfe, 0x80, 0x00, 0x01, 0x0b, 0x00, 0x00, 0x40,
> + 0x0d, 0x00, 0x00
> + };
> +
> + dsi_dcs_write(lcd->entity.source, 0,
> + data_to_send, ARRAY_SIZE(data_to_send));
> +}
> +
> +static void s6e8ax0_etc_cond2(struct s6e8ax0 *lcd)
> +{
> + static const unsigned char data_to_send[] = {
> + 0xb6, 0x0c, 0x02, 0x03, 0x32, 0xff, 0x44, 0x44, 0xc0,
> + 0x00
> + };
> +
> + dsi_dcs_write(lcd->entity.source, 0,
> + data_to_send, ARRAY_SIZE(data_to_send));
> +}
> +
> +static void s6e8ax0_etc_cond3(struct s6e8ax0 *lcd)
> +{
> + static const unsigned char data_to_send[] = {
> + 0xe1, 0x10, 0x1c, 0x17, 0x08, 0x1d
> + };
> +
> + dsi_dcs_write(lcd->entity.source, 0,
> + data_to_send, ARRAY_SIZE(data_to_send));
> +}
> +
> +static void s6e8ax0_etc_cond4(struct s6e8ax0 *lcd)
> +{
> + static const unsigned char data_to_send[] = {
> + 0xe2, 0xed, 0x07, 0xc3, 0x13, 0x0d, 0x03
> + };
> +
> + dsi_dcs_write(lcd->entity.source, 0,
> + data_to_send, ARRAY_SIZE(data_to_send));
> +}
> +
> +static void s6e8ax0_etc_cond5(struct s6e8ax0 *lcd)
> +{
> + static const unsigned char data_to_send[] = {
> + 0xf4, 0xcf, 0x0a, 0x12, 0x10, 0x19, 0x33, 0x02
> + };
> +
> + dsi_dcs_write(lcd->entity.source, 0,
> + data_to_send, ARRAY_SIZE(data_to_send));
> +}
> +static void s6e8ax0_etc_cond6(struct s6e8ax0 *lcd)
> +{
> + static const unsigned char data_to_send[] = {
> + 0xe3, 0x40
> + };
> +
> + dsi_dcs_write(lcd->entity.source, 0,
> + data_to_send, ARRAY_SIZE(data_to_send));
> +}
> +
> +static void s6e8ax0_etc_cond7(struct s6e8ax0 *lcd)
> +{
> + static const unsigned char data_to_send[] = {
> + 0xe4, 0x00, 0x00, 0x14, 0x80, 0x00, 0x00, 0x00
> + };
> +
> + dsi_dcs_write(lcd->entity.source, 0,
> + data_to_send, ARRAY_SIZE(data_to_send));
> +}
> +
> +static void s6e8ax0_elvss_set(struct s6e8ax0 *lcd)
> +{
> + static const unsigned char data_to_send[] = {
> + 0xb1, 0x04, 0x00
> + };
> +
> + dsi_dcs_write(lcd->entity.source, 0,
> + data_to_send, ARRAY_SIZE(data_to_send));
> +}
> +
> +static void s6e8ax0_elvss_nvm_set(struct s6e8ax0 *lcd)
> +{
> + static const unsigned char data_to_send[] = {
> + 0xd9, 0x5c, 0x20, 0x0c, 0x0f, 0x41, 0x00, 0x10, 0x11,
> + 0x12, 0xd1, 0x00, 0x00, 0x00, 0x00, 0x80, 0xcb, 0xed,
> + 0x64, 0xaf
> + };
> +
> + dsi_dcs_write(lcd->entity.source, 0,
> + data_to_send, ARRAY_SIZE(data_to_send));
> +}
> +
> +static void s6e8ax0_sleep_in(struct s6e8ax0 *lcd)
> +{
> + static const unsigned char data_to_send[] = {
> + 0x10
> + };
> +
> + dsi_dcs_write(lcd->entity.source, 0,
> + data_to_send, ARRAY_SIZE(data_to_send));
> +}
> +
> +static void s6e8ax0_sleep_out(struct s6e8ax0 *lcd)
> +{
> + static const unsigned char data_to_send[] = {
> + 0x11
> + };
> +
> + dsi_dcs_write(lcd->entity.source, 0,
> + data_to_send, ARRAY_SIZE(data_to_send));
> +}
> +
> +static void s6e8ax0_display_on(struct s6e8ax0 *lcd)
> +{
> + static const unsigned char data_to_send[] = {
> + 0x29
> + };
> +
> + dsi_dcs_write(lcd->entity.source, 0,
> + data_to_send, ARRAY_SIZE(data_to_send));
> +}
> +
> +static void s6e8ax0_display_off(struct s6e8ax0 *lcd)
> +{
> + static const unsigned char data_to_send[] = {
> + 0x28
> + };
> +
> + dsi_dcs_write(lcd->entity.source, 0,
> + data_to_send, ARRAY_SIZE(data_to_send));
> +}
> +
> +static void s6e8ax0_apply_level2_key(struct s6e8ax0 *lcd)
> +{
> + static const unsigned char data_to_send[] = {
> + 0xf0, 0x5a, 0x5a
> + };
> +
> + dsi_dcs_write(lcd->entity.source, 0,
> + data_to_send, ARRAY_SIZE(data_to_send));
> +}
> +
> +static void s6e8ax0_acl_on(struct s6e8ax0 *lcd)
> +{
> + static const unsigned char data_to_send[] = {
> + 0xc0, 0x01
> + };
> +
> + dsi_dcs_write(lcd->entity.source, 0,
> + data_to_send, ARRAY_SIZE(data_to_send));
> +}
> +
> +static void s6e8ax0_acl_off(struct s6e8ax0 *lcd)
> +{
> + static const unsigned char data_to_send[] = {
> + 0xc0, 0x00
> + };
> +
> + dsi_dcs_write(lcd->entity.source, 0,
> + data_to_send, ARRAY_SIZE(data_to_send));
> +}
> +
> +/* Full white 50% reducing setting */
> +static void s6e8ax0_acl_ctrl_set(struct s6e8ax0 *lcd)
> +{
> + /* Full white 50% reducing setting */
> + static const unsigned char cutoff_50[] = {
> + 0xc1, 0x47, 0x53, 0x13, 0x53, 0x00, 0x00, 0x02, 0xcf,
> + 0x00, 0x00, 0x04, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x01, 0x08, 0x0f, 0x16, 0x1d, 0x24, 0x2a, 0x31, 0x38,
> + 0x3f, 0x46
> + };
> + /* Full white 45% reducing setting */
> + static const unsigned char cutoff_45[] = {
> + 0xc1, 0x47, 0x53, 0x13, 0x53, 0x00, 0x00, 0x02, 0xcf,
> + 0x00, 0x00, 0x04, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x01, 0x07, 0x0d, 0x13, 0x19, 0x1f, 0x25, 0x2b, 0x31,
> + 0x37, 0x3d
> + };
> + /* Full white 40% reducing setting */
> + static const unsigned char cutoff_40[] = {
> + 0xc1, 0x47, 0x53, 0x13, 0x53, 0x00, 0x00, 0x02, 0xcf,
> + 0x00, 0x00, 0x04, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x01, 0x06, 0x0c, 0x11, 0x16, 0x1c, 0x21, 0x26, 0x2b,
> + 0x31, 0x36
> + };
> +
> + if (lcd->acl_enable) {
> + if (lcd->cur_acl = 0) {
> + if (lcd->gamma = 0 || lcd->gamma = 1) {
> + s6e8ax0_acl_off(lcd);
> + dev_dbg(lcd->dev,
> + "cur_acl=%d\n", lcd->cur_acl);
> + } else
> + s6e8ax0_acl_on(lcd);
> + }
> + switch (lcd->gamma) {
> + case 0: /* 30cd */
> + s6e8ax0_acl_off(lcd);
> + lcd->cur_acl = 0;
> + break;
> + case 1 ... 3: /* 50cd ~ 90cd */
> + dsi_dcs_write(lcd->entity.source, 0,
> + cutoff_40,
> + ARRAY_SIZE(cutoff_40));
> + lcd->cur_acl = 40;
> + break;
> + case 4 ... 7: /* 120cd ~ 210cd */
> + dsi_dcs_write(lcd->entity.source, 0,
> + cutoff_45,
> + ARRAY_SIZE(cutoff_45));
> + lcd->cur_acl = 45;
> + break;
> + case 8 ... 10: /* 220cd ~ 300cd */
> + dsi_dcs_write(lcd->entity.source, 0,
> + cutoff_50,
> + ARRAY_SIZE(cutoff_50));
> + lcd->cur_acl = 50;
> + break;
> + default:
> + break;
> + }
> + } else {
> + s6e8ax0_acl_off(lcd);
> + lcd->cur_acl = 0;
> + dev_dbg(lcd->dev, "cur_acl = %d\n", lcd->cur_acl);
> + }
> +}
> +
> +static void s6e8ax0_read_id(struct s6e8ax0 *lcd, u8 *mtp_id)
> +{
> + unsigned int ret;
> + u8 addr = 0xd1; /* MTP ID */
> +
> + ret = dsi_dcs_read(lcd->entity.source, 0, addr, mtp_id, 3);
> +}
> +
> +static int s6e8ax0_panel_init(struct s6e8ax0 *lcd)
> +{
> + s6e8ax0_apply_level2_key(lcd);
> + s6e8ax0_sleep_out(lcd);
> + msleep(1);
> + s6e8ax0_panel_cond(lcd);
> + s6e8ax0_display_cond(lcd);
> + s6e8ax0_gamma_cond(lcd);
> + s6e8ax0_gamma_update(lcd);
> +
> + s6e8ax0_etc_cond1(lcd);
> + s6e8ax0_etc_cond2(lcd);
> + s6e8ax0_etc_cond3(lcd);
> + s6e8ax0_etc_cond4(lcd);
> + s6e8ax0_etc_cond5(lcd);
> + s6e8ax0_etc_cond6(lcd);
> + s6e8ax0_etc_cond7(lcd);
> +
> + s6e8ax0_elvss_nvm_set(lcd);
> + s6e8ax0_elvss_set(lcd);
> +
> + s6e8ax0_acl_ctrl_set(lcd);
> + s6e8ax0_acl_on(lcd);
> +
> + /* if ID3 value is not 33h, branch private elvss mode */
> + msleep(lcd->pdata->power_on_delay);
> +
> + return 0;
> +}
> +
> +static int s6e8ax0_update_gamma_ctrl(struct s6e8ax0 *lcd, int brightness)
> +{
> + dsi_dcs_write(lcd->entity.source, 0,
> + s6e8ax0_22_gamma_table[brightness],
> + ARRAY_SIZE(s6e8ax0_22_gamma_table));
> +
> + /* update gamma table. */
> + s6e8ax0_gamma_update(lcd);
> + lcd->gamma = brightness;
> +
> + return 0;
> +}
> +
> +static int s6e8ax0_gamma_ctrl(struct s6e8ax0 *lcd, int gamma)
> +{
> + s6e8ax0_update_gamma_ctrl(lcd, gamma);
> +
> + return 0;
> +}
> +
> +static int s6e8ax0_get_brightness(struct backlight_device *bd)
> +{
> + return bd->props.brightness;
> +}
> +
> +static int s6e8ax0_set_brightness(struct backlight_device *bd)
> +{
> + int ret = 0, brightness = bd->props.brightness;
> + struct s6e8ax0 *lcd = bl_get_data(bd);
> +
> + if (brightness < MIN_BRIGHTNESS ||
> + brightness > bd->props.max_brightness) {
> + dev_err(lcd->dev,
> + "lcd brightness should be %d to %d.\n",
> + MIN_BRIGHTNESS, MAX_BRIGHTNESS);
> + return -EINVAL;
> + }
> +
> + ret = s6e8ax0_gamma_ctrl(lcd, brightness);
> + if (ret) {
> + dev_err(lcd->dev,
> + "lcd brightness setting failed.\n");
> + return -EIO;
> + }
> +
> + return ret;
> +}
> +
> +static const struct backlight_ops s6e8ax0_backlight_ops = {
> + .get_brightness = s6e8ax0_get_brightness,
> + .update_status = s6e8ax0_set_brightness,
> +};
> +
> +static int s6e8ax0_set_power(struct lcd_device *ld, int power)
> +{
> + struct s6e8ax0 *lcd = lcd_get_data(ld);
> + enum display_entity_state state;
> + int ret;
> +
> + if (power = FB_BLANK_POWERDOWN)
> + state = DISPLAY_ENTITY_STATE_OFF;
> + else if (power != FB_BLANK_UNBLANK)
> + state = DISPLAY_ENTITY_STATE_STANDBY;
> + else
> + state = DISPLAY_ENTITY_STATE_ON;
> +
> + ret = display_entity_set_state(&lcd->entity, state);
> + if (ret)
> + return ret;
> +
> + lcd->power = power;
> + return 0;
> +}
> +
> +static int s6e8ax0_get_power(struct lcd_device *ld)
> +{
> + struct s6e8ax0 *lcd = lcd_get_data(ld);
> +
> + return lcd->power;
> +}
> +
> +static struct lcd_ops s6e8ax0_lcd_ops = {
> + .set_power = s6e8ax0_set_power,
> + .get_power = s6e8ax0_get_power,
> +};
> +
> +static void s6e8ax0_set_sequence(struct s6e8ax0 *lcd)
> +{
> + u8 mtp_id[3] = {0, };
> +
> + msleep(100);
> +
> + s6e8ax0_read_id(lcd, mtp_id);
> + if (mtp_id[0] = 0x00)
> + dev_err(lcd->dev, "read id failed\n");
> +
> + dev_info(lcd->dev, "Read ID : %x, %x, %x\n",
> + mtp_id[0], mtp_id[1], mtp_id[2]);
> +
> + if (mtp_id[2] = 0x33)
> + dev_info(lcd->dev,
> + "ID-3 is 0xff does not support dynamic elvss\n");
> + else
> + dev_info(lcd->dev,
> + "ID-3 is 0x%x support dynamic elvss\n", mtp_id[2]);
> +
> + s6e8ax0_panel_init(lcd);
> + s6e8ax0_display_on(lcd);
> +}
> +
> +#ifdef CONFIG_OF
> +static int s6e8ax0_generic_reset(struct device *dev)
> +{
> + struct s6e8ax0 *lcd = dev_get_drvdata(dev);
> +
> + mdelay(10);
> + gpio_set_value(lcd->reset_gpio, 0);
> + mdelay(10);
> + gpio_set_value(lcd->reset_gpio, 1);
> +
> + return 0;
> +}
> +
> +static struct s6e8ax0_platform_data *s6e8ax0_parse_dt(struct s6e8ax0 *lcd)
> +{
> + struct device_node *node = lcd->dev->of_node;
> + struct s6e8ax0_platform_data *data;
> + const __be32 *prop_data;
> + int ret;
> +
> + data = devm_kzalloc(lcd->dev, sizeof(*data), GFP_KERNEL);
> + if (!data) {
> + dev_err(lcd->dev, "failed to allocate platform data.\n");
> + return NULL;
> + }
> +
> + ret = of_get_videomode(node, &data->mode, 0);
> + if (ret) {
> + dev_err(lcd->dev, "failed to read video mode from DT\n");
> + return NULL;
> + }
> +
> + lcd->reset_gpio = of_get_named_gpio(node, "reset-gpio", 0);
> + if (lcd->reset_gpio < 0)
> + return NULL;
> +
> + prop_data = of_get_property(node, "reset-delay", NULL);
> + if (!prop_data)
> + return NULL;
> + data->reset_delay = be32_to_cpu(*prop_data);
> +
> + prop_data = of_get_property(node, "power-off-delay", NULL);
> + if (!prop_data)
> + return NULL;
> + data->power_off_delay = be32_to_cpu(*prop_data);
> +
> + prop_data = of_get_property(node, "power-on-delay", NULL);
> + if (!prop_data)
> + return NULL;
> + data->power_on_delay = be32_to_cpu(*prop_data);
> +
> + data->reset = s6e8ax0_generic_reset;
> +
> + return data;
> +}
> +
> +static struct of_device_id s6e8ax0_of_match[] = {
> + { .compatible = "samsung,s6e8ax0" },
> + { }
> +};
> +
> +MODULE_DEVICE_TABLE(of, s6e8ax0_of_match);
> +#else
> +static struct s6e8ax0_platform_data *s6e8ax0_parse_dt(struct s6e8ax0 *lcd)
> +{
> + return NULL;
> +}
> +#endif
> +
> +static const struct display_entity_interface_params s6e8ax0_params = {
> + .type = DISPLAY_ENTITY_INTERFACE_DSI,
> + .p.dsi = {
> + .format = DSI_FMT_RGB888,
> + .mode = DSI_MODE_VIDEO | DSI_MODE_VIDEO_BURST
> + | DSI_MODE_VIDEO_HFP | DSI_MODE_VIDEO_HBP
> + | DSI_MODE_VIDEO_HSA | DSI_MODE_EOT_PACKET
> + | DSI_MODE_VSYNC_FLUSH,
> + .data_lanes = 0xf,
> + .hs_clk_freq = 500000000,
> + .esc_clk_freq = 10000000,
> + },
> +};
> +
> +static int s6e8ax0_set_state(struct display_entity *entity,
> + enum display_entity_state state)
> +{
> + struct s6e8ax0 *panel = to_panel(entity);
> +
> + switch (state) {
> + case DISPLAY_ENTITY_STATE_OFF:
> + if (entity->state = DISPLAY_ENTITY_STATE_ON) {
> + s6e8ax0_sleep_in(panel);
> + panel->entity.source->common_ops->set_stream(entity->source,
> + DISPLAY_ENTITY_STREAM_STOPPED);
> +
> + msleep(panel->pdata->power_off_delay);
> + s6e8ax0_display_off(panel);
> +
> + panel->entity.source->ops.dsi->disable(entity->source);
> +
> + regulator_bulk_disable(ARRAY_SIZE(panel->supplies),
> + panel->supplies);
> + } else if (entity->state = DISPLAY_ENTITY_STATE_STANDBY) {
> + msleep(panel->pdata->power_off_delay);
> + s6e8ax0_display_off(panel);
> +
> + panel->entity.source->ops.dsi->disable(entity->source);
> +
> + regulator_bulk_disable(ARRAY_SIZE(panel->supplies),
> + panel->supplies);
> + }
> + break;
> +
> + case DISPLAY_ENTITY_STATE_STANDBY:
> + if (entity->state = DISPLAY_ENTITY_STATE_ON) {
> + s6e8ax0_sleep_in(panel);
> + panel->entity.source->common_ops->set_stream(entity->source,
> + DISPLAY_ENTITY_STREAM_STOPPED);
> + } else if (entity->state = DISPLAY_ENTITY_STATE_OFF) {
> + msleep(panel->pdata->power_on_delay);
> +
> + regulator_bulk_enable(ARRAY_SIZE(panel->supplies),
> + panel->supplies);
> +
> + msleep(panel->pdata->reset_delay);
> +
> + /* lcd reset */
> + if (panel->pdata->reset)
> + panel->pdata->reset(panel->dev);
> + msleep(5);
> +
> + panel->entity.source->ops.dsi->enable(entity->source);
> +
> + s6e8ax0_set_sequence(panel);
> + s6e8ax0_sleep_in(panel);
> + }
> + break;
> +
> + case DISPLAY_ENTITY_STATE_ON:
> + if (entity->state = DISPLAY_ENTITY_STATE_OFF) {
> + msleep(panel->pdata->power_on_delay);
> +
> + regulator_bulk_enable(ARRAY_SIZE(panel->supplies),
> + panel->supplies);
> +
> + msleep(panel->pdata->reset_delay);
> +
> + /* lcd reset */
> + if (panel->pdata->reset)
> + panel->pdata->reset(panel->dev);
> + msleep(5);
> +
> + panel->entity.source->ops.dsi->enable(entity->source);
> +
> + s6e8ax0_set_sequence(panel);
> +
> + panel->entity.source->common_ops->set_stream(entity->source,
> + DISPLAY_ENTITY_STREAM_CONTINUOUS);
> + } else {
> + panel->entity.source->common_ops->set_stream(entity->source,
> + DISPLAY_ENTITY_STREAM_CONTINUOUS);
> + s6e8ax0_sleep_out(panel);
> + }
> + break;
> +
> + default:
> + break;
> + }
> +
> + return 0;
> +}
> +
> +static int s6e8ax0_get_modes(struct display_entity *entity,
> + const struct videomode **modes)
> +{
> + struct s6e8ax0 *panel = to_panel(entity);
> +
> + *modes = &panel->pdata->mode;
> + return 1;
> +}
> +
> +static int s6e8ax0_get_size(struct display_entity *entity,
> + unsigned int *width, unsigned int *height)
> +{
> + struct s6e8ax0 *panel = to_panel(entity);
> +
> + *width = panel->pdata->width;
> + *height = panel->pdata->height;
> + return 0;
> +}
> +
> +static int s6e8ax0_get_params(struct display_entity *entity,
> + struct display_entity_interface_params *params)
> +{
> + *params = s6e8ax0_params;
> + return 0;
> +}
> +
> +static const struct display_entity_control_ops s6e8ax0_control_ops = {
> + .set_state = s6e8ax0_set_state,
> + .get_modes = s6e8ax0_get_modes,
> + .get_size = s6e8ax0_get_size,
> + .get_params = s6e8ax0_get_params,
> +};
> +
> +static void s6e8ax0_release(struct display_entity *entity)
> +{
> + struct s6e8ax0 *panel = to_panel(entity);
> +
> + backlight_device_unregister(panel->bd);
> + lcd_device_unregister(panel->ld);
> + regulator_bulk_free(ARRAY_SIZE(panel->supplies), panel->supplies);
> + kfree(panel);
> +}
> +
> +static int s6e8ax0_probe(struct platform_device *pdev)
> +{
> + struct s6e8ax0 *lcd;
> + int ret;
> +
> + lcd = kzalloc(sizeof(struct s6e8ax0), GFP_KERNEL);
> + if (!lcd) {
> + dev_err(&pdev->dev, "failed to allocate s6e8ax0 structure.\n");
> + return -ENOMEM;
> + }
> +
> + lcd->dev = &pdev->dev;
> + lcd->pdata = (struct s6e8ax0_platform_data *)pdev->dev.platform_data;
> +
> + if (!lcd->pdata) {
> + lcd->pdata = s6e8ax0_parse_dt(lcd);
> + if (!lcd->pdata) {
> + dev_err(&pdev->dev, "failed to find platform data\n");
> + return -ENODEV;
> + }
> + }
> +
> + lcd->supplies[0].supply = "vdd3";
> + lcd->supplies[1].supply = "vci";
> + ret = regulator_bulk_get(&pdev->dev,
> + ARRAY_SIZE(lcd->supplies), lcd->supplies);
> + if (ret) {
> + dev_err(&pdev->dev, "Failed to get regulators: %d\n", ret);
> + goto err_regulator_bulk_get;
> + }
> +
> + lcd->ld = lcd_device_register("s6e8ax0", &pdev->dev, lcd,
> + &s6e8ax0_lcd_ops);
> + if (IS_ERR(lcd->ld)) {
> + dev_err(&pdev->dev, "failed to register lcd ops.\n");
> + ret = PTR_ERR(lcd->ld);
> + goto err_lcd_register;
> + }
> +
> + lcd->bd = backlight_device_register("s6e8ax0-bl", &pdev->dev, lcd,
> + &s6e8ax0_backlight_ops, NULL);
> + if (IS_ERR(lcd->bd)) {
> + dev_err(&pdev->dev, "failed to register backlight ops.\n");
> + ret = PTR_ERR(lcd->bd);
> + goto err_backlight_register;
> + }
> +
I think we should try to remove the dependency with LCD framework and
Backlight framework, and incorporate those functionality as par of
CDF.
you can refer to my similar patch "Make s6e8ax0 panel driver compliant
with CDF" ( http://comments.gmane.org/gmane.linux.drivers.video-input-infrastructure/59187
) which i had posted couple of weeks back, where I made an attempt to
remove "lcd_ops" dependency.
> + lcd->acl_enable = 1;
> + lcd->cur_acl = 0;
> + lcd->power = FB_BLANK_UNBLANK;
> +
> + lcd->bd->props.max_brightness = MAX_BRIGHTNESS;
> + lcd->bd->props.brightness = MAX_BRIGHTNESS;
> +
> + lcd->entity.of_node = pdev->dev.of_node;
> + lcd->entity.dev = &pdev->dev;
> + lcd->entity.release = s6e8ax0_release;
> + lcd->entity.ops = &s6e8ax0_control_ops;
> +
> + platform_set_drvdata(pdev, lcd);
> +
> + ret = display_entity_register(&lcd->entity);
> + if (ret < 0)
> + goto err_display_register;
> +
> + display_entity_set_state(&lcd->entity, DISPLAY_ENTITY_STATE_ON);
> +
> + dev_dbg(&pdev->dev, "probed s6e8ax0 panel driver.\n");
> +
> + return 0;
> +
> +err_display_register:
> + backlight_device_unregister(lcd->bd);
> +err_backlight_register:
> + lcd_device_unregister(lcd->ld);
> +err_lcd_register:
> + regulator_bulk_free(ARRAY_SIZE(lcd->supplies), lcd->supplies);
> +err_regulator_bulk_get:
> + kfree(lcd);
> +
> + return ret;
> +}
> +
> +static int s6e8ax0_remove(struct platform_device *dev)
> +{
> + struct s6e8ax0 *lcd = platform_get_drvdata(dev);
> +
> + platform_set_drvdata(dev, NULL);
> + display_entity_unregister(&lcd->entity);
> +
> + return 0;
> +}
> +
> +static int s6e8ax0_suspend(struct device *dev)
> +{
> + struct s6e8ax0 *lcd = dev_get_drvdata(dev);
> +
> + if (lcd->power = FB_BLANK_UNBLANK)
> + display_entity_set_state(&lcd->entity,
> + DISPLAY_ENTITY_STATE_OFF);
> +
> + return 0;
> +}
> +
> +static int s6e8ax0_resume(struct device *dev)
> +{
> + struct s6e8ax0 *lcd = dev_get_drvdata(dev);
> +
> + if (lcd->power = FB_BLANK_UNBLANK)
> + display_entity_set_state(&lcd->entity,
> + DISPLAY_ENTITY_STATE_ON);
> +
> + return 0;
> +}
> +
> +static struct dev_pm_ops s6e8ax0_pm_ops = {
> + SET_SYSTEM_SLEEP_PM_OPS(s6e8ax0_suspend, s6e8ax0_resume)
> +};
> +
> +static struct platform_driver s6e8ax0_driver = {
> + .probe = s6e8ax0_probe,
> + .remove = s6e8ax0_remove,
> + .driver = {
> + .name = "panel_s6e8ax0",
> + .owner = THIS_MODULE,
> + .of_match_table = of_match_ptr(s6e8ax0_of_match),
> + .pm = &s6e8ax0_pm_ops,
> + },
> +};
> +module_platform_driver(s6e8ax0_driver);
> +
> +MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>");
> +MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
> +MODULE_AUTHOR("Tomasz Figa <t.figa@samsung.com>");
> +MODULE_DESCRIPTION("MIPI-DSI based s6e8ax0 AMOLED LCD Panel Driver");
> +MODULE_LICENSE("GPL");
> diff --git a/include/video/panel-s6e8ax0.h b/include/video/panel-s6e8ax0.h
> new file mode 100644
> index 0000000..e522bfb
> --- /dev/null
> +++ b/include/video/panel-s6e8ax0.h
> @@ -0,0 +1,41 @@
> +/*
> + * Renesas R61505-based Display Panels
> + *
> + * Copyright (C) 2012 Renesas Solutions Corp.
> + *
> + * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#ifndef __PANEL_S6E8AX0_H__
> +#define __PANEL_S6E8AX0_H__
> +
> +#include <linux/videomode.h>
> +
> +struct s6e8ax0_platform_data {
> + unsigned long width; /* Panel width in mm */
> + unsigned long height; /* Panel height in mm */
> + struct videomode mode;
> +
> + /* reset lcd panel device. */
> + int (*reset)(struct device *dev);
> +
> + /* it indicates whether lcd panel was enabled
> + from bootloader or not. */
> + int lcd_enabled;
> + /* it means delay for stable time when it becomes low to high
> + or high to low that is dependent on whether reset gpio is
> + low active or high active. */
> + unsigned int reset_delay;
> + /* stable time needing to become lcd power on. */
> + unsigned int power_on_delay;
> + /* stable time needing to become lcd power off. */
> + unsigned int power_off_delay;
> + /* panel is reversed */
> + bool panel_reverse;
> +};
> +
> +#endif /* __PANEL_S6E8AX0_H__ */
> --
> 1.8.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v2,RESEND] video console: add a driver for lcd2s character display
From: Lars Poeschel @ 2013-02-07 9:26 UTC (permalink / raw)
To: Arnd Bergmann
Cc: FlorianSchandinat, mathieu.poirier, linux-fbdev, linux-kernel
In-Reply-To: <201212170934.15312.poeschel@lemonage.de>
As it seems there are no further comments, could this please be included ?
Thanks,
Lars
On Monday 17 December 2012 at 09:34:15, Lars Poeschel wrote:
> From: Lars Poeschel <poeschel@lemonage.de>
>
> This driver allows to use a lcd2s 20x4 character display as
> a linux console output device.
>
> Signed-off-by: Lars Poeschel <poeschel@lemonage.de>
>
> ---
> drivers/video/console/Kconfig | 10 ++
> drivers/video/console/Makefile | 1 +
> drivers/video/console/lcd2scon.c | 360
> ++++++++++++++++++++++++++++++++++++++ 3 files changed, 371 insertions(+)
> create mode 100644 drivers/video/console/lcd2scon.c
>
> diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
> index e2c96d0..44fc3bf 100644
> --- a/drivers/video/console/Kconfig
> +++ b/drivers/video/console/Kconfig
> @@ -129,6 +129,16 @@ config STI_CONSOLE
> machines. Say Y here to build support for it into your kernel.
> The alternative is to use your primary serial port as a
> console.
>
> +config LCD2S_CONSOLE
> + tristate "lcd2s 20x4 character display over I2C console"
> + depends on I2C
> + default n
> + help
> + This is a driver that lets you use the lcd2s 20x4 character
> display + from modtronix engineering as a console output device.
> The display + is a simple single color character display. You
> have to connect it + to an I2C bus.
> +
> config FONTS
> bool "Select compiled-in fonts"
> depends on FRAMEBUFFER_CONSOLE || STI_CONSOLE
> diff --git a/drivers/video/console/Makefile
> b/drivers/video/console/Makefile index a862e91..74d5993 100644
> --- a/drivers/video/console/Makefile
> +++ b/drivers/video/console/Makefile
> @@ -23,6 +23,7 @@ font-objs += $(font-objs-y)
> obj-$(CONFIG_DUMMY_CONSOLE) += dummycon.o
> obj-$(CONFIG_SGI_NEWPORT_CONSOLE) += newport_con.o font.o
> obj-$(CONFIG_STI_CONSOLE) += sticon.o sticore.o font.o
> +obj-$(CONFIG_LCD2S_CONSOLE) += lcd2scon.o
> obj-$(CONFIG_VGA_CONSOLE) += vgacon.o
> obj-$(CONFIG_MDA_CONSOLE) += mdacon.o
> obj-$(CONFIG_FRAMEBUFFER_CONSOLE) += fbcon.o bitblit.o font.o
> softcursor.o diff --git a/drivers/video/console/lcd2scon.c
> b/drivers/video/console/lcd2scon.c new file mode 100644
> index 0000000..c139811
> --- /dev/null
> +++ b/drivers/video/console/lcd2scon.c
> @@ -0,0 +1,360 @@
> +/*
> + * console driver for LCD2S 4x20 character displays connected through
> i2c. + *
> + * This is a driver allowing you to use a LCD2S 4x20 from modtronix
> + * engineering as console output device.
> + *
> + * (C) 2012 by Lemonage Software GmbH
> + * Author: Lars Poeschel <poeschel@lemonage.de>
> + * All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify
> it + * under the terms of the GNU General Public License as published
> by the + * Free Software Foundation; either version 2 of the License,
> or (at your + * option) any later version.
> + *
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/kd.h>
> +#include <linux/tty.h>
> +#include <linux/console_struct.h>
> +#include <linux/console.h>
> +#include <linux/vt_kern.h>
> +#include <linux/i2c.h>
> +
> +#define LCD2S_CMD_CUR_BLINK_OFF 0x10
> +#define LCD2S_CMD_CUR_UL_OFF 0x11
> +#define LCD2S_CMD_DISPLAY_OFF 0x12
> +#define LCD2S_CMD_CUR_BLINK_ON 0x18
> +#define LCD2S_CMD_CUR_UL_ON 0x19
> +#define LCD2S_CMD_DISPLAY_ON 0x1a
> +#define LCD2S_CMD_BACKLIGHT_OFF 0x20
> +#define LCD2S_CMD_BACKLIGHT_ON 0x28
> +#define LCD2S_CMD_WRITE 0x80
> +#define LCD2S_CMD_SHIFT_UP 0x87
> +#define LCD2S_CMD_SHIFT_DOWN 0x88
> +#define LCD2S_CMD_CUR_ADDR 0x89
> +#define LCD2S_CMD_CUR_POS 0x8a
> +#define LCD2S_CMD_CUR_RESET 0x8b
> +#define LCD2S_CMD_CLEAR 0x8c
> +
> +#define LCD2S_FIRST 8
> +#define LCD2S_LAST 9
> +
> +#define LCD2S_ROWS 4
> +#define LCD2S_COLS 20
> +
> +struct lcd2s_data {
> + struct i2c_client *i2c;
> + int row;
> + int col;
> + unsigned int cur_blink:1;
> + unsigned int cur_ul:1;
> +};
> +
> +static struct lcd2s_data lcd2s;
> +
> +static void lcd2s_set_cursor(int row, int col)
> +{
> + u8 buf[] = { LCD2S_CMD_CUR_POS, row + 1, col + 1};
> +
> + if (row = lcd2s.row && col = lcd2s.col)
> + return;
> +
> + i2c_master_send(lcd2s.i2c, buf, sizeof(buf));
> + lcd2s.row = row;
> + lcd2s.col = col;
> +}
> +
> +static void lcd2s_reset_cursor(void)
> +{
> + i2c_smbus_write_byte(lcd2s.i2c, LCD2S_CMD_CUR_RESET);
> + lcd2s.row = 0;
> + lcd2s.col = 0;
> +}
> +
> +static void lcd2s_increase_cursor(struct vc_data *con, int inc)
> +{
> + lcd2s.col += inc;
> + if ((lcd2s.col / con->vc_cols) >= 1) {
> + lcd2s.row += (lcd2s.col / con->vc_cols);
> + lcd2s.col %= con->vc_cols;
> + }
> +}
> +
> +static void lcd2s_cursor_ul_on(void)
> +{
> + if (!lcd2s.cur_ul) {
> + i2c_smbus_write_byte(lcd2s.i2c, LCD2S_CMD_CUR_UL_ON);
> + lcd2s.cur_ul = 1;
> + }
> +}
> +
> +static void lcd2s_cursor_ul_off(void)
> +{
> + if (lcd2s.cur_ul) {
> + i2c_smbus_write_byte(lcd2s.i2c, LCD2S_CMD_CUR_UL_OFF);
> + lcd2s.cur_ul = 0;
> + }
> +}
> +
> +static void lcd2s_cursor_blink_on(void)
> +{
> + if (!lcd2s.cur_blink) {
> + i2c_smbus_write_byte(lcd2s.i2c, LCD2S_CMD_CUR_BLINK_ON);
> + lcd2s.cur_blink = 1;
> + }
> +}
> +
> +static void lcd2s_cursor_blink_off(void)
> +{
> + if (lcd2s.cur_blink) {
> + i2c_smbus_write_byte(lcd2s.i2c, LCD2S_CMD_CUR_BLINK_OFF);
> + lcd2s.cur_blink = 0;
> + }
> +}
> +
> +static const char *lcd2s_startup(void)
> +{
> + return "lcd2s console";
> +}
> +
> +
> +/*
> + * init is set if console is currently allocated during init
> + */
> +static void lcd2s_init(struct vc_data *con, int init)
> +{
> + lcd2s.cur_blink = 0;
> + lcd2s.cur_ul = 0;
> +
> + /* turn display on */
> + i2c_smbus_write_byte(lcd2s.i2c, LCD2S_CMD_DISPLAY_ON);
> + i2c_smbus_write_byte(lcd2s.i2c, LCD2S_CMD_BACKLIGHT_ON);
> + i2c_smbus_write_byte(lcd2s.i2c, LCD2S_CMD_CLEAR);
> + lcd2s_cursor_ul_on();
> + lcd2s_reset_cursor();
> +
> + con->vc_can_do_color = 0;
> + con->vc_hi_font_mask = 0;
> +
> + if (init) {
> + con->vc_rows = LCD2S_ROWS;
> + con->vc_cols = LCD2S_COLS;
> + } else
> + vc_resize(con, LCD2S_COLS, LCD2S_ROWS);
> +}
> +
> +static void lcd2s_deinit(struct vc_data *con)
> +{
> + i2c_smbus_write_byte(lcd2s.i2c, LCD2S_CMD_DISPLAY_OFF);
> + i2c_smbus_write_byte(lcd2s.i2c, LCD2S_CMD_BACKLIGHT_OFF);
> + lcd2s_cursor_blink_off();
> + lcd2s_cursor_ul_off();
> +}
> +
> +static void lcd2s_clear(struct vc_data *con, int s_row, int s_col,
> + int height, int width)
> +{
> + u8 buf[width];
> + int i;
> +
> + if (width <= 0 || height <= 0)
> + return;
> +
> + /* if the whole display is to clear, we have a single command */
> + if (s_col = 0 && s_row = 0 &&
> + height >= con->vc_rows - 1 && width >= con->vc_cols - 1) {
> + i2c_smbus_write_byte(lcd2s.i2c, LCD2S_CMD_CLEAR);
> + return;
> + }
> +
> + for (i = 0; i <= width; i++)
> + buf[i] = ' ';
> +
> + for (i = s_col; i <= height; i++) {
> + lcd2s_set_cursor(s_row, i);
> + i2c_master_send(lcd2s.i2c, buf, width);
> + }
> +}
> +
> +static void lcd2s_putc(struct vc_data *con, int data, int row, int col)
> +{
> + u8 buf[] = {LCD2S_CMD_WRITE, data};
> +
> + lcd2s_set_cursor(row, col);
> +
> + i2c_master_send(lcd2s.i2c, buf, sizeof(buf));
> + lcd2s_increase_cursor(con, 1);
> +}
> +
> +static void lcd2s_putcs(struct vc_data *con, const unsigned short *buf,
> + int len, int row, int col)
> +{
> + u8 *i2c_buf;
> + int i;
> +
> + i2c_buf = kzalloc(len + 1, GFP_KERNEL);
> + if (!i2c_buf)
> + return;
> +
> + lcd2s_set_cursor(row, col);
> +
> + i2c_buf[0] = LCD2S_CMD_WRITE;
> + for (i = 0; i < len ; i++)
> + i2c_buf[i + 1] = buf[i];
> +
> + i2c_master_send(lcd2s.i2c, i2c_buf, len + 1);
> + kfree(i2c_buf);
> + lcd2s_increase_cursor(con, len);
> +}
> +
> +static void lcd2s_cursor(struct vc_data *con, int mode)
> +{
> + switch (mode) {
> + case CM_ERASE:
> + lcd2s_cursor_blink_off();
> + lcd2s_cursor_ul_off();
> + break;
> + case CM_MOVE:
> + case CM_DRAW:
> + lcd2s_set_cursor(con->vc_y, con->vc_x);
> +
> + switch (con->vc_cursor_type & CUR_HWMASK) {
> + case CUR_UNDERLINE:
> + lcd2s_cursor_ul_on();
> + lcd2s_cursor_blink_off();
> + break;
> + case CUR_NONE:
> + lcd2s_cursor_blink_off();
> + lcd2s_cursor_ul_off();
> + break;
> + default:
> + lcd2s_cursor_blink_on();
> + lcd2s_cursor_ul_off();
> + break;
> + }
> + break;
> + }
> +}
> +
> +static int lcd2s_scroll(struct vc_data *con, int top, int bot,
> + int dir, int lines)
> +{
> + /* we can only scroll the whole display */
> + if (top = 0 && bot = con->vc_rows) {
> + while (lines--) {
> + switch (dir) {
> + case SM_UP:
> + i2c_smbus_write_byte(lcd2s.i2c,
> + LCD2S_CMD_SHIFT_UP);
> + break;
> + case SM_DOWN:
> + i2c_smbus_write_byte(lcd2s.i2c,
> + LCD2S_CMD_SHIFT_DOWN);
> + break;
> + }
> + }
> + return 0;
> + }
> + return 1;
> +}
> +
> +static void lcd2s_bmove(struct vc_data *conp, int s_row, int s_col,
> + int d_row, int d_col, int height, int width)
> +{
> +}
> +
> +static int lcd2s_switch(struct vc_data *con)
> +{
> + return 1;
> +}
> +
> +static int lcd2s_blank(struct vc_data *con, int blank, int mode_switch)
> +{
> + switch (blank) {
> + case 0: /* unblank */
> + i2c_smbus_write_byte(lcd2s.i2c, LCD2S_CMD_DISPLAY_ON);
> + i2c_smbus_write_byte(lcd2s.i2c, LCD2S_CMD_BACKLIGHT_ON);
> + break;
> + case 1: /* normal blanking */
> + i2c_smbus_write_byte(lcd2s.i2c, LCD2S_CMD_DISPLAY_OFF);
> + i2c_smbus_write_byte(lcd2s.i2c, LCD2S_CMD_BACKLIGHT_OFF);
> + break;
> + }
> + return 0;
> +}
> +
> +static int lcd2s_set_palette(struct vc_data *con, unsigned char *table)
> +{
> + return -EINVAL;
> +}
> +
> +static int lcd2s_scrolldelta(struct vc_data *con, int lines)
> +{
> + return 0;
> +}
> +
> +static struct consw lcd2s_con = {
> + .owner = THIS_MODULE,
> + .con_startup = lcd2s_startup,
> + .con_init = lcd2s_init,
> + .con_deinit = lcd2s_deinit,
> + .con_clear = lcd2s_clear,
> + .con_putc = lcd2s_putc,
> + .con_putcs = lcd2s_putcs,
> + .con_cursor = lcd2s_cursor,
> + .con_scroll = lcd2s_scroll,
> + .con_bmove = lcd2s_bmove,
> + .con_switch = lcd2s_switch,
> + .con_blank = lcd2s_blank,
> + .con_set_palette = lcd2s_set_palette,
> + .con_scrolldelta = lcd2s_scrolldelta,
> +};
> +
> +static int __devinit lcd2s_i2c_probe(struct i2c_client *i2c,
> + const struct i2c_device_id *id)
> +{
> + if (!i2c_check_functionality(i2c->adapter,
> + I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
> + I2C_FUNC_SMBUS_WRITE_BLOCK_DATA))
> + return -EIO;
> +
> + lcd2s.i2c = i2c;
> +
> + take_over_console(&lcd2s_con, LCD2S_FIRST, LCD2S_LAST, 1);
> +
> + return 0;
> +}
> +
> +static __devexit int lcd2s_i2c_remove(struct i2c_client *i2c)
> +{
> + /* unregister from console subsystem */
> + unregister_con_driver(&lcd2s_con);
> + return 0;
> +}
> +
> +static const struct i2c_device_id lcd2s_i2c_id[] = {
> + { "lcd2s", 0 },
> + { }
> +};
> +MODULE_DEVICE_TABLE(i2c, lcd2s_i2c_id);
> +
> +static struct i2c_driver lcd2s_i2c_driver = {
> + .driver = {
> + .name = "lcd2s",
> + .owner = THIS_MODULE,
> + },
> + .probe = lcd2s_i2c_probe,
> + .remove = __devexit_p(lcd2s_i2c_remove),
> + .id_table = lcd2s_i2c_id,
> +};
> +
> +module_i2c_driver(lcd2s_i2c_driver)
> +
> +MODULE_DESCRIPTION("LCD2S character display console driver");
> +MODULE_AUTHOR("Lars Poeschel");
> +MODULE_LICENSE("GPL");
^ permalink raw reply
* Re: [PATCH v3 00/10] video: da8xx-fb: runtime timing configuration
From: Tomi Valkeinen @ 2013-02-07 9:13 UTC (permalink / raw)
To: Mohammed, Afzal
Cc: Florian Tobias Schandinat, Nori, Sekhar,
linux-omap@vger.kernel.org, linux-fbdev@vger.kernel.org,
linux-kernel@vger.kernel.org
In-Reply-To: <C8443D0743D26F4388EA172BF4E2A7A93EAA2846@DBDE01.ent.ti.com>
[-- Attachment #1: Type: text/plain, Size: 1200 bytes --]
Hi,
On 2013-02-07 11:05, Mohammed, Afzal wrote:
> Hi Tomi, Florian,
>
> On Tue, Jan 15, 2013 at 19:00:50, Mohammed, Afzal wrote:
>
>> This series makes da8xx-fb driver (device found on DaVinci and AM335x)
>> capable of handling runtime timing configuration by adding fb_set_par.
>>
>> The last change adds actual fb_set_par support. Other preceeding
>> changes makes the way clear for it as well as does certain cleanup's
>> on the way.
>>
>> This has been tested on da850 evm as is. This was also tested on
>> am335x-evm & am335x-evmsk with a series that adds DT support.
>>
>> This is based on v3.8-rc3, this is the only change in this revision.
>> The new version of this series is being posted so that this series can
>> be applied easily (as __dev* are removed, there would be merge
>> conflicts with v2, which was based on -rc2).
>> series
>
> Can you please consider this series for inclusion. There are no
> pending comments or dependency for this series. If you need a
> pull request, let me know, I will sent it.
I handled only the pull request for 3.8 merge window to help Florian
with it. I didn't mean to become a co-maintainer or such =).
Tomi
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 899 bytes --]
^ permalink raw reply
* RE: [PATCH v3 00/10] video: da8xx-fb: runtime timing configuration
From: Mohammed, Afzal @ 2013-02-07 9:05 UTC (permalink / raw)
To: Florian Tobias Schandinat, Valkeinen, Tomi, Nori, Sekhar,
linux-omap@vger.kernel.org, linux-fbdev@vger.kernel.org,
linux-kernel@vger.kernel.org
In-Reply-To: <cover.1358250489.git.afzal@ti.com>
SGkgVG9taSwgRmxvcmlhbiwNCg0KT24gVHVlLCBKYW4gMTUsIDIwMTMgYXQgMTk6MDA6NTAsIE1v
aGFtbWVkLCBBZnphbCB3cm90ZToNCg0KPiBUaGlzIHNlcmllcyBtYWtlcyBkYTh4eC1mYiBkcml2
ZXIgKGRldmljZSBmb3VuZCBvbiBEYVZpbmNpIGFuZCBBTTMzNXgpDQo+IGNhcGFibGUgb2YgaGFu
ZGxpbmcgcnVudGltZSB0aW1pbmcgY29uZmlndXJhdGlvbiBieSBhZGRpbmcgZmJfc2V0X3Bhci4N
Cj4gDQo+IFRoZSBsYXN0IGNoYW5nZSBhZGRzIGFjdHVhbCBmYl9zZXRfcGFyIHN1cHBvcnQuIE90
aGVyIHByZWNlZWRpbmcNCj4gY2hhbmdlcyBtYWtlcyB0aGUgd2F5IGNsZWFyIGZvciBpdCBhcyB3
ZWxsIGFzIGRvZXMgY2VydGFpbiBjbGVhbnVwJ3MNCj4gb24gdGhlIHdheS4NCj4gDQo+IFRoaXMg
aGFzIGJlZW4gdGVzdGVkIG9uIGRhODUwIGV2bSBhcyBpcy4gVGhpcyB3YXMgYWxzbyB0ZXN0ZWQg
b24NCj4gYW0zMzV4LWV2bSAmIGFtMzM1eC1ldm1zayB3aXRoIGEgc2VyaWVzIHRoYXQgYWRkcyBE
VCBzdXBwb3J0Lg0KPiANCj4gVGhpcyBpcyBiYXNlZCBvbiB2My44LXJjMywgdGhpcyBpcyB0aGUg
b25seSBjaGFuZ2UgaW4gdGhpcyByZXZpc2lvbi4NCj4gVGhlIG5ldyB2ZXJzaW9uIG9mIHRoaXMg
c2VyaWVzIGlzIGJlaW5nIHBvc3RlZCBzbyB0aGF0IHRoaXMgc2VyaWVzIGNhbg0KPiBiZSBhcHBs
aWVkIGVhc2lseSAoYXMgX19kZXYqIGFyZSByZW1vdmVkLCB0aGVyZSB3b3VsZCBiZSBtZXJnZQ0K
PiBjb25mbGljdHMgd2l0aCB2Miwgd2hpY2ggd2FzIGJhc2VkIG9uIC1yYzIpLg0KPiBzZXJpZXMN
Cg0KQ2FuIHlvdSBwbGVhc2UgY29uc2lkZXIgdGhpcyBzZXJpZXMgZm9yIGluY2x1c2lvbi4gVGhl
cmUgYXJlIG5vDQpwZW5kaW5nIGNvbW1lbnRzIG9yIGRlcGVuZGVuY3kgZm9yIHRoaXMgc2VyaWVz
LiBJZiB5b3UgbmVlZCBhDQpwdWxsIHJlcXVlc3QsIGxldCBtZSBrbm93LCBJIHdpbGwgc2VudCBp
dC4NCg0KUmVnYXJkcw0KQWZ6YWwNCg0K
^ permalink raw reply
* Re: Unmerged patches for 3.9
From: Sachin Kamat @ 2013-02-07 7:19 UTC (permalink / raw)
To: linux-fbdev
Resending due to wrong fbdev mailing address. Sorry.
On 7 February 2013 12:34, Sachin Kamat <sachin.kamat@linaro.org> wrote:
> Hi Florian,
>
> I have the following 'Acked' patches missing in your tree.
>
> https://patchwork.kernel.org/patch/1864681/
> https://patchwork.kernel.org/patch/1923041/
> https://patchwork.kernel.org/patch/1926501/
>
> Could you please pick them up in your tree as they have been pending
> almost since a couple of months now.
>
> --
> With warm regards,
> Sachin
--
With warm regards,
Sachin
^ permalink raw reply
* Re: [Linaro-mm-sig] CDF meeting @FOSDEM report
From: Daniel Vetter @ 2013-02-06 16:14 UTC (permalink / raw)
To: Tomi Valkeinen
Cc: Alex Deucher, Thomas Petazzoni, linux-fbdev, Stephen Warren,
Thierry Reding, Mark Zhang, dri-devel, Sunil Joshi, linaro-mm-sig,
Stéphane Marchesin, Kyungmin Park, Jesse Barnes,
Laurent Pinchart, Sebastien Guiriec, Alexandre Courbot,
Maxime Ripard, Vikas Sajjan, Ragesh Radhakrishnan, linux-media
In-Reply-To: <51127008.7050808@ti.com>
On Wed, Feb 6, 2013 at 4:00 PM, Tomi Valkeinen <tomi.valkeinen@ti.com> wrote:
>> not always a perfect match to the hardware. For example a lot of GPUs
>> have a DVO encoder which feeds a secondary encoder like an sil164 DVO
>> to TMDS encoder.
>
> Right. I think mapping the DRM entities to CDF ones is one of the bigger
> question marks we have with CDF. While I'm no expert on DRM, I think we
> have the following options:
>
> 1. Force DRM's model to CDF, meaning one encoder.
>
> 2. Extend DRM to support multiple encoders in a chain.
>
> 3. Support multiple encoders in a chain in CDF, but somehow map them to
> a single encoder in DRM side.
4. Ignore drm kms encoders.
They are only exposed to userspace as a means for userspace to
discover very simple constraints, e.g. 1 encoder connected to 2
outputs means you can only use one of the outputs at the same time.
They are completely irrelevant for the actual modeset interface
exposed to drivers, so you could create a fake kms encoder for each
connector you expose through kms.
The crtc helpers use the encoders as a real entity, and if you opt to
use the crtc helpers to implement the modeset sequence in your driver
it makes sense to map them to some real piece of hw. But you can
essentially pick any transcoder in your crtc -> final output chain for
this. Generic userspace needs to be able to cope with a failed modeset
due to arbitrary reasons anyway, so can't presume that simply because
the currently exposed constraints are fulfilled it'll work.
> I really dislike the first option, as it would severely limit where CDF
> can be used, or would force you to write some kind of combined drivers,
> so that you can have one encoder driver running multiple encoder devices.
Imo CDF and drm encoders don't really have that much to do with each
another, it should just be a driver implementation detail. Of course,
if common patterns emerge we could extract them somehow. E.g. if many
drivers end up exposing the CDF transcoder chain as a drm encoder
using the crtc helpers, we could add some library functions to make
that simpler.
Another conclusion (at least from my pov) from the fosdem discussion
is that we should separate the panel interface from the actual
control/pixel data buses. That should give us more flexibility for
insane hw and also directly exposing properties and knobs to the
userspace interface from e.g. dsi transcoders. So I don't think we'll
end up with _the_ canonical CDF sink interface anyway.
-Daniel
--
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
^ permalink raw reply
* Re: CDF meeting @FOSDEM report
From: Tomi Valkeinen @ 2013-02-06 15:00 UTC (permalink / raw)
To: Alex Deucher
Cc: Laurent Pinchart, linux-fbdev, Sebastien Guiriec, dri-devel,
Jesse Barnes, Benjamin Gaignard, Sumit Semwal, Tom Gall,
Kyungmin Park, linux-media, Stephen Warren, Thierry Reding,
Mark Zhang, linaro-mm-sig, Stéphane Marchesin,
Alexandre Courbot, Ragesh Radhakrishnan, Thomas Petazzoni,
Sunil Joshi, Maxime Ripard, Vikas Sajjan
In-Reply-To: <CADnq5_P1GFbAwoe9kTeARq8ZLP1tOBc9Rn1h2KrRYxkoLxLXfw@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 1840 bytes --]
On 2013-02-06 16:44, Alex Deucher wrote:
> On Wed, Feb 6, 2013 at 6:11 AM, Tomi Valkeinen <tomi.valkeinen@ti.com> wrote:
>> What is an encoder? Something that takes a video signal in, and lets the
>> CPU store the received data to memory? Isn't that a decoder?
>>
>> Or do you mean something that takes a video signal in, and outputs a
>> video signal in another format? (transcoder?)
>
> In KMS parlance, we have two objects a crtc and an encoder. A crtc
> reads data from memory and produces a data stream with display timing.
> The encoder then takes that datastream and timing from the crtc and
> converts it some sort of physical signal (LVDS, TMDS, DP, etc.). It's
Isn't the video stream between CRTC and encoder just as physical, it
just happens to be inside the GPU?
This is the case for OMAP, at least, where DISPC could be considered
CRTC, and DSI/HDMI/etc could be considered encoder. The stream between
DISPC and DSI/HDMI is plain parallel RGB signal. The video stream could
as well be outside OMAP.
> not always a perfect match to the hardware. For example a lot of GPUs
> have a DVO encoder which feeds a secondary encoder like an sil164 DVO
> to TMDS encoder.
Right. I think mapping the DRM entities to CDF ones is one of the bigger
question marks we have with CDF. While I'm no expert on DRM, I think we
have the following options:
1. Force DRM's model to CDF, meaning one encoder.
2. Extend DRM to support multiple encoders in a chain.
3. Support multiple encoders in a chain in CDF, but somehow map them to
a single encoder in DRM side.
I really dislike the first option, as it would severely limit where CDF
can be used, or would force you to write some kind of combined drivers,
so that you can have one encoder driver running multiple encoder devices.
Tomi
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 899 bytes --]
^ permalink raw reply
* Re: CDF meeting @FOSDEM report
From: Alex Deucher @ 2013-02-06 14:44 UTC (permalink / raw)
To: Tomi Valkeinen
Cc: Thomas Petazzoni, linux-fbdev, Tom Gall, Stephen Warren,
Thierry Reding, Mark Zhang, dri-devel, Sunil Joshi, linaro-mm-sig,
Stéphane Marchesin, Kyungmin Park, Jesse Barnes,
Laurent Pinchart, Sebastien Guiriec, Alexandre Courbot,
Maxime Ripard, Vikas Sajjan, Sumit Semwal, Ragesh Radhakrishnan,
linux-media
In-Reply-To: <51123A5F.9050604@ti.com>
On Wed, Feb 6, 2013 at 6:11 AM, Tomi Valkeinen <tomi.valkeinen@ti.com> wrote:
> Hi,
>
> On 2013-02-06 00:27, Laurent Pinchart wrote:
>> Hello,
>>
>> We've hosted a CDF meeting at the FOSDEM on Sunday morning. Here's a summary
>> of the discussions.
>
> Thanks for the summary. I've been on a longish leave, and just got back,
> so I haven't read the recent CDF discussions on lists yet. I thought
> I'll start by replying to this summary first =).
>
>> 0. Abbreviations
>> ----------------
>>
>> DBI - Display Bus Interface, a parallel video control and data bus that
>> transmits data using parallel data, read/write, chip select and address
>> signals, similarly to 8051-style microcontroller parallel busses. This is a
>> mixed video control and data bus.
>>
>> DPI - Display Pixel Interface, a parallel video data bus that transmits data
>> using parallel data, h/v sync and clock signals. This is a video data bus
>> only.
>>
>> DSI - Display Serial Interface, a serial video control and data bus that
>> transmits data using one or more differential serial lines. This is a mixed
>> video control and data bus.
>
> In case you'll re-use these abbrevs in later posts, I think it would be
> good to mention that DPI is a one-way bus, whereas DBI and DSI are
> two-way (perhaps that's implicit with control bus, though).
>
>> 1. Goals
>> --------
>>
>> The meeting started with a brief discussion about the CDF goals.
>>
>> Tomi Valkeinin and Tomasz Figa have sent RFC patches to show their views of
>> what CDF could/should be. Many others have provided very valuable feedback.
>> Given the early development stage propositions were sometimes contradictory,
>> and focused on different areas of interest. We have thus started the meeting
>> with a discussion about what CDF should try to achieve, and what it shouldn't.
>>
>> CDF has two main purposes. The original goal was to support display panels in
>> a platform- and subsystem-independent way. While mostly useful for embedded
>> systems, the emergence of platforms such as Intel Medfield and ARM-based PCs
>> that blends the embedded and PC worlds makes panel support useful for the PC
>> world as well.
>>
>> The second purpose is to provide a cross-subsystem interface to support video
>> encoders. The idea originally came from a generalisation of the original RFC
>> that supported panels only. While encoder support is considered as lower
>> priority than display panel support by developers focussed on display
>> controller driver (Intel, Renesas, ST Ericsson, TI), companies that produce
>> video encoders (Analog Devices, and likely others) don't share that point of
>> view and would like to provide a single encoder driver that can be used in
>> both KMS and V4L2 drivers.
>
> What is an encoder? Something that takes a video signal in, and lets the
> CPU store the received data to memory? Isn't that a decoder?
>
> Or do you mean something that takes a video signal in, and outputs a
> video signal in another format? (transcoder?)
In KMS parlance, we have two objects a crtc and an encoder. A crtc
reads data from memory and produces a data stream with display timing.
The encoder then takes that datastream and timing from the crtc and
converts it some sort of physical signal (LVDS, TMDS, DP, etc.). It's
not always a perfect match to the hardware. For example a lot of GPUs
have a DVO encoder which feeds a secondary encoder like an sil164 DVO
to TMDS encoder.
Alex
^ permalink raw reply
* Re: [RFC v2 0/5] Common Display Framework
From: Archit Taneja @ 2013-02-06 9:52 UTC (permalink / raw)
To: Marcus Lorentzon
Cc: Laurent Pinchart, Thomas Petazzoni, linux-fbdev@vger.kernel.org,
Vikas Sajjan, Benjamin Gaignard, Tom Gall, Kyungmin Park,
dri-devel@lists.freedesktop.org, Rob Clark, Ragesh Radhakrishnan,
Tomi Valkeinen, Bryan Wu, Maxime Ripard, sunil joshi,
Sumit Semwal, Sebastien Guiriec, linux-media@vger.kernel.org
In-Reply-To: <510F8807.2020406@stericsson.com>
On Monday 04 February 2013 03:35 PM, Marcus Lorentzon wrote:
> On 02/02/2013 12:35 AM, Laurent Pinchart wrote:
>> Hi Marcus,
>>
>> On Tuesday 08 January 2013 18:08:19 Marcus Lorentzon wrote:
>>> On 01/08/2013 05:36 PM, Tomasz Figa wrote:
>>>> On Tuesday 08 of January 2013 11:12:26 Marcus Lorentzon wrote:
> [...]
>>>>> But it is not perfect. After a couple of products we realized that
>>>>> most
>>>>> panel drivers want an easy way to send a bunch of init commands in one
>>>>> go. So I think it should be an op for sending an array of commands at
>>>>> once. Something like
>>>>>
>>>>> struct dsi_cmd {
>>>>> enum mipi_pkt_type type; /* MIPI DSI, DCS, SetPacketLen, ... */
>>>>> u8 cmd;
>>>>> int dataLen;
>>>>> u8 *data;
>>>>> }
>>>>>
>>>>> struct dsi_ops {
>>>>> int dsi_write(source, int num_cmds, struct dsi_cmd *cmds);
>>>>> ...
>>>>> }
>> Do you have DSI IP(s) that can handle a list of commands ? Or would
>> all DSI
>> transmitter drivers need to iterate over the commands manually ? In
>> the later
>> case a lower-level API might be easier to implement in DSI transmitter
>> drivers. Helper functions could provide the higher-level API you
>> proposed.
>
> The HW has a FIFO, so it can handle a few. Currently we use the low
> level type of call with one call per command. But we have found DSI
> command mode panels that don't accept any commands during the "update"
> (write start+continues). And so we must use a mutex/state machine to
> exclude any async calls to send DSI commands during update. But if you
> need to send more than one command per frame this will be hard (like
> CABC and backlight commands). It will be a ping pong between update and
> command calls. One option is to expose the mutex to the caller so it can
> make many calls before the next update grabs the mutex again.
> So maybe we could create a helper that handle the op for list of
> commands and another op for single command that you actually have to
> implement.
fyi, the DSI IP on OMAP3+ SoCs also has a FIFO. It can provide
interrupts after each command is pushed out, and also when the FIFO gets
empty(all commands are pushed). The only thing to take care is to not
overflow FIFO.
DSI video mode panels generally have a few dozen internal registers
which need to be configured via DSI commands. It's more fast(and
convenient) to configure a handful of internal registers in one shot,
and then perform a single BTA to know from the panel whether the
commands were received correctly.
Regards,
Archit
^ permalink raw reply
* Re: 答复: [PATCH]Siliconmotion initial patch
From: Greg KH @ 2013-02-05 21:19 UTC (permalink / raw)
To: Daniel Vetter
Cc: Linux Fbdev development list, caesar.qiu 裘赛海,
dri-devel, Aaron.Chen 陈俊杰
In-Reply-To: <20130205210427.GF5813@phenom.ffwll.local>
On Tue, Feb 05, 2013 at 10:04:27PM +0100, Daniel Vetter wrote:
> On Tue, Feb 05, 2013 at 03:51:55PM +0800, Aaron.Chen 陈俊杰 wrote:
> > This is an initial patch for Siliconmotion Graphics chips. It add SM750
> > chip support with 2d accelerate and hw curser support. It is a complete
> > new driver. So the patch is a little bit big. Is it OK for review?
>
> Adding a new fbdev driver while established consensus pretty much boils
> down to fbdev being a dead subsystem which should only be used for legacy
> applications and drivers: Not good. You should implement this as a drm
> modesetting driver, and if required base your 2d acceleration on top of
> the drm fb helpers. Or just implement a drm/gem driver to expose this.
>
> Additionally you should include the appropriate mailing lists, which is
> linux-fbdev for fbdev drivers.
>
> On a very quick read the patch has serious issues:
>
> - checkpatch.pl:
>
> total: 2 errors, 779 warnings, 7961 lines checked
>
> NOTE: whitespace errors detected, you may wish to use scripts/cleanpatch or
> scripts/cleanfile
>
> - Remants of hungarian notation (dunno whether checkpatch checks for
> those, too much other stuff flying by, but it really stuck out).
>
> - Not using the linux i2c layer in the ddk750_hwi2c.c file.
>
> - Reimplementing i2c bit-banging code in the ddk750_swi2c.c
>
> - Adding a new implementation of a sil 164 dvi driver, we already have at
> least two in drivers/gpu/drm/i2c/sil164_drv.c and
> drivers/gpu/drm/i915/dvo_sil164.c. This should be unified and probably
> use the drm encoder slave framework.
>
> At that point I've given up on further review, since there's clearly a lot
> of work left to do. Please review SubmittingPatches from the kernel
> documentation carefully. Also cc'ing our dear staging maintainer, he
> should be able to point you at further useful resources for getting this
> going.
If you wish to put this in the drivers/staging/ directory and do the
cleanup there before it moves to the "real" part of the kernel, I have
no objection to that.
thanks,
greg k-h
^ permalink raw reply
* Re: 答复: [PATCH]Siliconmotion initial patch
From: Daniel Vetter @ 2013-02-05 21:04 UTC (permalink / raw)
To: Aaron.Chen 陈俊杰
Cc: Greg KH, Linux Fbdev development list,
caesar.qiu 裘赛海, dri-devel
In-Reply-To: <4CE6A5494DEECD498EBCD4C5488B1AFCEAC6F7@CNDC08.cn.smi.ad>
On Tue, Feb 05, 2013 at 03:51:55PM +0800, Aaron.Chen 陈俊杰 wrote:
> This is an initial patch for Siliconmotion Graphics chips. It add SM750
> chip support with 2d accelerate and hw curser support. It is a complete
> new driver. So the patch is a little bit big. Is it OK for review?
Adding a new fbdev driver while established consensus pretty much boils
down to fbdev being a dead subsystem which should only be used for legacy
applications and drivers: Not good. You should implement this as a drm
modesetting driver, and if required base your 2d acceleration on top of
the drm fb helpers. Or just implement a drm/gem driver to expose this.
Additionally you should include the appropriate mailing lists, which is
linux-fbdev for fbdev drivers.
On a very quick read the patch has serious issues:
- checkpatch.pl:
total: 2 errors, 779 warnings, 7961 lines checked
NOTE: whitespace errors detected, you may wish to use scripts/cleanpatch or
scripts/cleanfile
- Remants of hungarian notation (dunno whether checkpatch checks for
those, too much other stuff flying by, but it really stuck out).
- Not using the linux i2c layer in the ddk750_hwi2c.c file.
- Reimplementing i2c bit-banging code in the ddk750_swi2c.c
- Adding a new implementation of a sil 164 dvi driver, we already have at
least two in drivers/gpu/drm/i2c/sil164_drv.c and
drivers/gpu/drm/i915/dvo_sil164.c. This should be unified and probably
use the drm encoder slave framework.
At that point I've given up on further review, since there's clearly a lot
of work left to do. Please review SubmittingPatches from the kernel
documentation carefully. Also cc'ing our dear staging maintainer, he
should be able to point you at further useful resources for getting this
going.
Cheers, Daniel
--
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
^ permalink raw reply
* Re: [PATCH 5/5] ARM: at91/avr32/atmel_lcdfb: replace cpu_is macros with device-id table
From: Jean-Christophe PLAGNIOL-VILLARD @ 2013-02-05 20:11 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1360071315-4032-6-git-send-email-jhovold@gmail.com>
On 14:35 Tue 05 Feb , Johan Hovold wrote:
> Remove cpu_is macros from atmel lcdfb driver and use platform-device-id
> table to determine platform configuration parameters.
>
> The currently used configuration parameters are:
>
> have_alt_pixclock
> - SOC uses an alternate pixel-clock calculation formula (at91sam9g45
> non-ES)
>
> have_bus_clk
> - SOC has bus clock hck1 (at91sam9261, at921sam9g10 and at32ap)
no provide a clkdev a we do for macb
>
> have_hozval
> - SOC has a HOZVAL field in LCDFRMCFG which is used to determine the
> linesize for STN displays (at91sam9261, at921sam9g10 and at32ap)
>
> have_intensity_bit
> - SOC uses IBGR:555 rather than BGR:565 16-bit pixel layout
> (at91sam9261, at91sam9263 and at91sam9rl)
>
> Tested on at91sam9g45, compile-tested for other AT91 SOCs, and untested
> for AVR32.
>
> Signed-off-by: Johan Hovold <jhovold@gmail.com>
> ---
> arch/arm/mach-at91/at91sam9261_devices.c | 6 +-
> arch/arm/mach-at91/at91sam9263_devices.c | 2 +-
> arch/arm/mach-at91/at91sam9g45_devices.c | 6 +-
> arch/arm/mach-at91/at91sam9rl_devices.c | 2 +-
> arch/avr32/mach-at32ap/at32ap700x.c | 2 +
> drivers/video/atmel_lcdfb.c | 96 ++++++++++++++++++++++++++++----
> include/video/atmel_lcdc.h | 4 +-
> 7 files changed, 101 insertions(+), 17 deletions(-)
>
> diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c
> index 92e0f86..01647cb 100644
> --- a/arch/arm/mach-at91/at91sam9261_devices.c
> +++ b/arch/arm/mach-at91/at91sam9261_devices.c
> @@ -488,7 +488,6 @@ static struct resource lcdc_resources[] = {
> };
>
> static struct platform_device at91_lcdc_device = {
> - .name = "atmel_lcdfb",
> .id = 0,
> .dev = {
> .dma_mask = &lcdc_dmamask,
> @@ -505,6 +504,11 @@ void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data)
> return;
> }
>
> + if (cpu_is_at91sam9g10())
> + at91_lcdc_device.name = "fb-at91sam9g10";
use this
at91sam9g10-lcdfb
as we will use for dt
> + else
> + at91_lcdc_device.name = "fb-at91sam9261";
> +
> #if defined(CONFIG_FB_ATMEL_STN)
> at91_set_A_periph(AT91_PIN_PB0, 0); /* LCDVSYNC */
> at91_set_A_periph(AT91_PIN_PB1, 0); /* LCDHSYNC */
> diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c
> index ed666f5..a34f39a 100644
> --- a/arch/arm/mach-at91/at91sam9263_devices.c
> +++ b/arch/arm/mach-at91/at91sam9263_devices.c
> @@ -848,7 +848,7 @@ static struct resource lcdc_resources[] = {
> };
>
> static struct platform_device at91_lcdc_device = {
> - .name = "atmel_lcdfb",
> + .name = "fb-at91sam9263",
> .id = 0,
> .dev = {
> .dma_mask = &lcdc_dmamask,
> diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c
> index 827c9f2..1d5cc51 100644
> --- a/arch/arm/mach-at91/at91sam9g45_devices.c
> +++ b/arch/arm/mach-at91/at91sam9g45_devices.c
> @@ -981,7 +981,6 @@ static struct resource lcdc_resources[] = {
> };
>
> static struct platform_device at91_lcdc_device = {
> - .name = "atmel_lcdfb",
> .id = 0,
> .dev = {
> .dma_mask = &lcdc_dmamask,
> @@ -997,6 +996,11 @@ void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data)
> if (!data)
> return;
>
> + if (cpu_is_at91sam9g45es())
> + at91_lcdc_device.name = "fb-at91sam9g45es";
> + else
> + at91_lcdc_device.name = "fb-at91sam9g45";
> +
> at91_set_A_periph(AT91_PIN_PE0, 0); /* LCDDPWR */
>
> at91_set_A_periph(AT91_PIN_PE2, 0); /* LCDCC */
> diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c
> index ddf223f..13cac0a 100644
> --- a/arch/arm/mach-at91/at91sam9rl_devices.c
> +++ b/arch/arm/mach-at91/at91sam9rl_devices.c
> @@ -514,7 +514,7 @@ static struct resource lcdc_resources[] = {
> };
>
> static struct platform_device at91_lcdc_device = {
> - .name = "atmel_lcdfb",
> + .name = "fb-at91sam9rl",
> .id = 0,
> .dev = {
> .dma_mask = &lcdc_dmamask,
> diff --git a/arch/avr32/mach-at32ap/at32ap700x.c b/arch/avr32/mach-at32ap/at32ap700x.c
> index b323d8d..5cdaa07 100644
> --- a/arch/avr32/mach-at32ap/at32ap700x.c
> +++ b/arch/avr32/mach-at32ap/at32ap700x.c
> @@ -1530,6 +1530,8 @@ at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
> memcpy(info, data, sizeof(struct atmel_lcdfb_info));
> info->default_monspecs = monspecs;
>
> + pdev->name = "fb-at32ap";
> +
> platform_device_register(pdev);
> return pdev;
>
> diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
> index 347bab2..5ad49ed 100644
> --- a/drivers/video/atmel_lcdfb.c
> +++ b/drivers/video/atmel_lcdfb.c
> @@ -34,6 +34,81 @@
> #define ATMEL_LCDC_DMA_BURST_LEN 8 /* words */
> #define ATMEL_LCDC_FIFO_SIZE 512 /* words */
>
> +struct atmel_lcdfb_config {
> + bool have_alt_pixclock;
> + bool have_bus_clk;
> + bool have_hozval;
> + bool have_intensity_bit;
> +};
> +
> +static struct atmel_lcdfb_config at91sam9261_config = {
> + .have_bus_clk = true,
> + .have_intensity_bit = true,
> + .have_hozval = true,
> +};
> +
> +static struct atmel_lcdfb_config at91sam9263_config = {
> + .have_intensity_bit = true,
> +};
> +
> +static struct atmel_lcdfb_config at91sam9g10_config = {
> + .have_bus_clk = true,
> + .have_hozval = true,
> +};
> +
> +static struct atmel_lcdfb_config at91sam9g45_config = {
> + .have_alt_pixclock = true,
> +};
> +
> +static struct atmel_lcdfb_config at91sam9g45es_config = {
> +};
> +
> +static struct atmel_lcdfb_config at91sam9rl_config = {
> + .have_intensity_bit = true,
> +};
> +
> +static struct atmel_lcdfb_config at32ap_config = {
> + .have_bus_clk = true,
> + .have_hozval = true,
> +};
> +
> +static const struct platform_device_id atmel_lcdfb_devtypes[] = {
> + {
> + .name = "fb-at91sam9261",
> + .driver_data = (unsigned long)&at91sam9261_config,
> + }, {
> + .name = "fb-at91sam9263",
> + .driver_data = (unsigned long)&at91sam9263_config,
> + }, {
> + .name = "fb-at91sam9g10",
> + .driver_data = (unsigned long)&at91sam9g10_config,
> + }, {
> + .name = "fb-at91sam9g45",
> + .driver_data = (unsigned long)&at91sam9g45_config,
> + }, {
> + .name = "fb-at91sam9g45es",
> + .driver_data = (unsigned long)&at91sam9g45es_config,
> + }, {
> + .name = "fb-at91sam9rl",
> + .driver_data = (unsigned long)&at91sam9rl_config,
> + }, {
> + .name = "fb-at32ap",
> + .driver_data = (unsigned long)&at32ap_config,
> + }, {
> + /* terminator */
> + }
> +};
> +
> +static struct atmel_lcdfb_config *
> +atmel_lcdfb_get_config(struct platform_device *pdev)
> +{
> + unsigned long data;
> +
> + data = platform_get_device_id(pdev)->driver_data;
> +
> + return (struct atmel_lcdfb_config *)data;
> +}
> +
> #if defined(CONFIG_ARCH_AT91)
> #define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \
> | FBINFO_PARTIAL_PAN_OK \
> @@ -199,8 +274,7 @@ static unsigned long compute_hozval(struct atmel_lcdfb_info *sinfo,
> unsigned long lcdcon2;
> unsigned long value;
>
> - if (!(cpu_is_at91sam9261() || cpu_is_at91sam9g10()
> - || cpu_is_at32ap7000()))
> + if (!sinfo->config->have_hozval)
> return xres;
>
> lcdcon2 = lcdc_readl(sinfo, ATMEL_LCDC_LCDCON2);
> @@ -426,7 +500,7 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
> break;
> case 16:
> /* Older SOCs use IBGR:555 rather than BGR:565. */
> - if (sinfo->have_intensity_bit)
> + if (sinfo->config->have_intensity_bit)
> var->green.length = 5;
> else
> var->green.length = 6;
> @@ -534,7 +608,7 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
> /* Now, the LCDC core... */
>
> /* Set pixel clock */
> - if (cpu_is_at91sam9g45() && !cpu_is_at91sam9g45es())
> + if (sinfo->config->have_alt_pixclock)
> pix_factor = 1;
>
> clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
> @@ -685,7 +759,7 @@ static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red,
>
> case FB_VISUAL_PSEUDOCOLOR:
> if (regno < 256) {
> - if (sinfo->have_intensity_bit) {
> + if (sinfo->config->have_intensity_bit) {
> /* old style I+BGR:555 */
> val = ((red >> 11) & 0x001f);
> val |= ((green >> 6) & 0x03e0);
> @@ -875,10 +949,9 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
> }
> sinfo->info = info;
> sinfo->pdev = pdev;
> - if (cpu_is_at91sam9261() || cpu_is_at91sam9263() ||
> - cpu_is_at91sam9rl()) {
> - sinfo->have_intensity_bit = true;
> - }
> + sinfo->config = atmel_lcdfb_get_config(pdev);
> + if (!sinfo->config)
> + goto free_info;
>
> strcpy(info->fix.id, sinfo->pdev->name);
> info->flags = ATMEL_LCDFB_FBINFO_DEFAULT;
> @@ -889,8 +962,7 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
> info->fix = atmel_lcdfb_fix;
>
> /* Enable LCDC Clocks */
> - if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()
> - || cpu_is_at32ap7000()) {
> + if (sinfo->config->have_bus_clk) {
> sinfo->bus_clk = clk_get(dev, "hck1");
> if (IS_ERR(sinfo->bus_clk)) {
> ret = PTR_ERR(sinfo->bus_clk);
> @@ -1152,7 +1224,7 @@ static struct platform_driver atmel_lcdfb_driver = {
> .remove = __exit_p(atmel_lcdfb_remove),
> .suspend = atmel_lcdfb_suspend,
> .resume = atmel_lcdfb_resume,
> -
> + .id_table = atmel_lcdfb_devtypes,
> .driver = {
> .name = "atmel_lcdfb",
> .owner = THIS_MODULE,
> diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h
> index 8deb226..0f5a2fc 100644
> --- a/include/video/atmel_lcdc.h
> +++ b/include/video/atmel_lcdc.h
> @@ -31,6 +31,7 @@
> #define ATMEL_LCDC_WIRING_BGR 0
> #define ATMEL_LCDC_WIRING_RGB 1
>
> +struct atmel_lcdfb_config;
>
> /* LCD Controller info data structure, stored in device platform_data */
> struct atmel_lcdfb_info {
> @@ -61,7 +62,8 @@ struct atmel_lcdfb_info {
> void (*atmel_lcdfb_power_control)(int on);
> struct fb_monspecs *default_monspecs;
> u32 pseudo_palette[16];
> - bool have_intensity_bit;
> +
> + struct atmel_lcdfb_config *config;
> };
>
> #define ATMEL_LCDC_DMABADDR1 0x00
> --
> 1.8.1.1
>
^ permalink raw reply
* Re: [PATCH v17 4/7] fbmon: add videomode helpers
From: Steffen Trumtrar @ 2013-02-05 18:29 UTC (permalink / raw)
To: Jingoo Han
Cc: 'Mohammed, Afzal', 'Florian Tobias Schandinat',
'Dave Airlie', devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
linux-fbdev-u79uwXL29TY76Z2rM5mHXA,
dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
'Tomi Valkeinen', 'Laurent Pinchart',
kernel-bIcnvbaLZ9MEGnE8C9+IrQ, 'Guennady Liakhovetski',
linux-media-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <003401ce005e$af665c50$0e3314f0$%han-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
Hi!
On Fri, Feb 01, 2013 at 06:29:50PM +0900, Jingoo Han wrote:
> On Friday, January 25, 2013 6:02 PM, Steffen Trumtrar wrote
> >
> > + fbmode->sync = 0;
> > + fbmode->vmode = 0;
> > + if (vm->dmt_flags & VESA_DMT_HSYNC_HIGH)
> > + fbmode->sync |= FB_SYNC_HOR_HIGH_ACT;
> > + if (vm->dmt_flags & VESA_DMT_HSYNC_HIGH)
>
> Um, it seems to be a type. 'H'SYNC -> 'V'SYNC
> Thus, it would be changed as below:
>
> VESA_DMT_HSYNC_HIGH -> VESA_DMT_VSYNC_HIGH
Damn. You are right, that is a typo. But I guess some maintainer (Dave) really,
really wants to take the series now and this can wait for an -rc. No?! ;-)
Thanks,
Steffen
>
> > + fbmode->sync |= FB_SYNC_VERT_HIGH_ACT;
> > + if (vm->data_flags & DISPLAY_FLAGS_INTERLACED)
> > + fbmode->vmode |= FB_VMODE_INTERLACED;
> > + if (vm->data_flags & DISPLAY_FLAGS_DOUBLESCAN)
> > + fbmode->vmode |= FB_VMODE_DOUBLE;
> > + fbmode->flag = 0;
> > +
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
^ permalink raw reply
* Re: [PATCH 2/3 v2] fb: udlfb: fix hang at disconnect
From: Alexander Holler @ 2013-02-05 17:36 UTC (permalink / raw)
To: Greg KH
Cc: Andrew Morton, linux-kernel, linux-fbdev,
Florian Tobias Schandinat, Bernie Thompson, Steve Glendinning,
stable
In-Reply-To: <20130205172245.GA1426@kroah.com>
Am 05.02.2013 18:22, schrieb Greg KH:
> On Tue, Feb 05, 2013 at 08:08:28AM +0100, Alexander Holler wrote:
>> Am 04.02.2013 20:25, schrieb Greg KH:
>>> Where was that urb when the disconnect happened? The USB core should
>>> call your urb callback for any outstanding urbs at that point in time,
>>> with the proper error flag being set, are you handling that properly?
>>
>> I don't know where that urb is as I don't handle it.
>
> What do you mean by that? The urb is being sent back to your driver,
> right? If not, that's a bug, but please be sure that your urb callback
> isn't really being called.
I meant it isn't _my_ driver. ;)
I'm just trying to add some würgarounds without having the need to
rewrite the whole driver.
In regard to that "urb missing problem", I think I've just named it
wrong and the actual problem is a race-condition between the semaphore
handling (which is used to keep track of the urbs) and the urb handling
inside the driver.
But I've just switched to udl (instead of udlfb) and will see if I can
fix the bugs there to make it usable as a console. udl is a rewrite of
udlfb with some additional features (e.g. drm), so hopefully fixing the
remaining problems there will require less work.
Regards,
Alexander
^ permalink raw reply
* Re: [PATCH 2/3 v2] fb: udlfb: fix hang at disconnect
From: Greg KH @ 2013-02-05 17:22 UTC (permalink / raw)
To: Alexander Holler
Cc: Andrew Morton, linux-kernel, linux-fbdev,
Florian Tobias Schandinat, Bernie Thompson, Steve Glendinning,
stable
In-Reply-To: <5110AFEC.8020406@ahsoftware.de>
On Tue, Feb 05, 2013 at 08:08:28AM +0100, Alexander Holler wrote:
> Am 04.02.2013 20:25, schrieb Greg KH:
> > On Mon, Feb 04, 2013 at 08:17:04PM +0100, Alexander Holler wrote:
> >> Am 04.02.2013 13:05, schrieb Alexander Holler:
> >>> Am 04.02.2013 02:14, schrieb Greg KH:
> >>>
> >>>> So you are right in that your driver will wait for forever for a
> >>>> disconnect() to happen, as it will never be called. I don't understand
> >>>> the problem that this is causing when it happens. What's wrong with
> >>>> udlfb that having the cpu suddently reset as the powerdown happened
> >>>> without it knowing about it?
> >>>
> >>> There is nothing wrong with that. I've just explained why a problem
> >>> doesn't occur on shutdown but on disconnect (of the device).
> >>
> >> Maybe my explanation before was just to long and I try to explain it
> >> a bit shorter:
> >>
> >> If a device gets disconnected, the disconnect in udlfb might wait
> >> forever in down_interruptible() (because it waits for an urb it
> >> never receives). This even prevents a shutdown afterwards, because
> >> that down_interruptible() never receives a signal (at shutdown,
> >> because kernel threads don't get such).
> >
> > Where was that urb when the disconnect happened? The USB core should
> > call your urb callback for any outstanding urbs at that point in time,
> > with the proper error flag being set, are you handling that properly?
>
> I don't know where that urb is as I don't handle it.
What do you mean by that? The urb is being sent back to your driver,
right? If not, that's a bug, but please be sure that your urb callback
isn't really being called.
thanks,
greg k-h
^ permalink raw reply
* [PATCH 5/5] ARM: at91/avr32/atmel_lcdfb: replace cpu_is macros with device-id table
From: Johan Hovold @ 2013-02-05 13:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1360071315-4032-1-git-send-email-jhovold@gmail.com>
Remove cpu_is macros from atmel lcdfb driver and use platform-device-id
table to determine platform configuration parameters.
The currently used configuration parameters are:
have_alt_pixclock
- SOC uses an alternate pixel-clock calculation formula (at91sam9g45
non-ES)
have_bus_clk
- SOC has bus clock hck1 (at91sam9261, at921sam9g10 and at32ap)
have_hozval
- SOC has a HOZVAL field in LCDFRMCFG which is used to determine the
linesize for STN displays (at91sam9261, at921sam9g10 and at32ap)
have_intensity_bit
- SOC uses IBGR:555 rather than BGR:565 16-bit pixel layout
(at91sam9261, at91sam9263 and at91sam9rl)
Tested on at91sam9g45, compile-tested for other AT91 SOCs, and untested
for AVR32.
Signed-off-by: Johan Hovold <jhovold@gmail.com>
---
arch/arm/mach-at91/at91sam9261_devices.c | 6 +-
arch/arm/mach-at91/at91sam9263_devices.c | 2 +-
arch/arm/mach-at91/at91sam9g45_devices.c | 6 +-
arch/arm/mach-at91/at91sam9rl_devices.c | 2 +-
arch/avr32/mach-at32ap/at32ap700x.c | 2 +
drivers/video/atmel_lcdfb.c | 96 ++++++++++++++++++++++++++++----
include/video/atmel_lcdc.h | 4 +-
7 files changed, 101 insertions(+), 17 deletions(-)
diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c
index 92e0f86..01647cb 100644
--- a/arch/arm/mach-at91/at91sam9261_devices.c
+++ b/arch/arm/mach-at91/at91sam9261_devices.c
@@ -488,7 +488,6 @@ static struct resource lcdc_resources[] = {
};
static struct platform_device at91_lcdc_device = {
- .name = "atmel_lcdfb",
.id = 0,
.dev = {
.dma_mask = &lcdc_dmamask,
@@ -505,6 +504,11 @@ void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data)
return;
}
+ if (cpu_is_at91sam9g10())
+ at91_lcdc_device.name = "fb-at91sam9g10";
+ else
+ at91_lcdc_device.name = "fb-at91sam9261";
+
#if defined(CONFIG_FB_ATMEL_STN)
at91_set_A_periph(AT91_PIN_PB0, 0); /* LCDVSYNC */
at91_set_A_periph(AT91_PIN_PB1, 0); /* LCDHSYNC */
diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c
index ed666f5..a34f39a 100644
--- a/arch/arm/mach-at91/at91sam9263_devices.c
+++ b/arch/arm/mach-at91/at91sam9263_devices.c
@@ -848,7 +848,7 @@ static struct resource lcdc_resources[] = {
};
static struct platform_device at91_lcdc_device = {
- .name = "atmel_lcdfb",
+ .name = "fb-at91sam9263",
.id = 0,
.dev = {
.dma_mask = &lcdc_dmamask,
diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c
index 827c9f2..1d5cc51 100644
--- a/arch/arm/mach-at91/at91sam9g45_devices.c
+++ b/arch/arm/mach-at91/at91sam9g45_devices.c
@@ -981,7 +981,6 @@ static struct resource lcdc_resources[] = {
};
static struct platform_device at91_lcdc_device = {
- .name = "atmel_lcdfb",
.id = 0,
.dev = {
.dma_mask = &lcdc_dmamask,
@@ -997,6 +996,11 @@ void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data)
if (!data)
return;
+ if (cpu_is_at91sam9g45es())
+ at91_lcdc_device.name = "fb-at91sam9g45es";
+ else
+ at91_lcdc_device.name = "fb-at91sam9g45";
+
at91_set_A_periph(AT91_PIN_PE0, 0); /* LCDDPWR */
at91_set_A_periph(AT91_PIN_PE2, 0); /* LCDCC */
diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c
index ddf223f..13cac0a 100644
--- a/arch/arm/mach-at91/at91sam9rl_devices.c
+++ b/arch/arm/mach-at91/at91sam9rl_devices.c
@@ -514,7 +514,7 @@ static struct resource lcdc_resources[] = {
};
static struct platform_device at91_lcdc_device = {
- .name = "atmel_lcdfb",
+ .name = "fb-at91sam9rl",
.id = 0,
.dev = {
.dma_mask = &lcdc_dmamask,
diff --git a/arch/avr32/mach-at32ap/at32ap700x.c b/arch/avr32/mach-at32ap/at32ap700x.c
index b323d8d..5cdaa07 100644
--- a/arch/avr32/mach-at32ap/at32ap700x.c
+++ b/arch/avr32/mach-at32ap/at32ap700x.c
@@ -1530,6 +1530,8 @@ at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
memcpy(info, data, sizeof(struct atmel_lcdfb_info));
info->default_monspecs = monspecs;
+ pdev->name = "fb-at32ap";
+
platform_device_register(pdev);
return pdev;
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
index 347bab2..5ad49ed 100644
--- a/drivers/video/atmel_lcdfb.c
+++ b/drivers/video/atmel_lcdfb.c
@@ -34,6 +34,81 @@
#define ATMEL_LCDC_DMA_BURST_LEN 8 /* words */
#define ATMEL_LCDC_FIFO_SIZE 512 /* words */
+struct atmel_lcdfb_config {
+ bool have_alt_pixclock;
+ bool have_bus_clk;
+ bool have_hozval;
+ bool have_intensity_bit;
+};
+
+static struct atmel_lcdfb_config at91sam9261_config = {
+ .have_bus_clk = true,
+ .have_intensity_bit = true,
+ .have_hozval = true,
+};
+
+static struct atmel_lcdfb_config at91sam9263_config = {
+ .have_intensity_bit = true,
+};
+
+static struct atmel_lcdfb_config at91sam9g10_config = {
+ .have_bus_clk = true,
+ .have_hozval = true,
+};
+
+static struct atmel_lcdfb_config at91sam9g45_config = {
+ .have_alt_pixclock = true,
+};
+
+static struct atmel_lcdfb_config at91sam9g45es_config = {
+};
+
+static struct atmel_lcdfb_config at91sam9rl_config = {
+ .have_intensity_bit = true,
+};
+
+static struct atmel_lcdfb_config at32ap_config = {
+ .have_bus_clk = true,
+ .have_hozval = true,
+};
+
+static const struct platform_device_id atmel_lcdfb_devtypes[] = {
+ {
+ .name = "fb-at91sam9261",
+ .driver_data = (unsigned long)&at91sam9261_config,
+ }, {
+ .name = "fb-at91sam9263",
+ .driver_data = (unsigned long)&at91sam9263_config,
+ }, {
+ .name = "fb-at91sam9g10",
+ .driver_data = (unsigned long)&at91sam9g10_config,
+ }, {
+ .name = "fb-at91sam9g45",
+ .driver_data = (unsigned long)&at91sam9g45_config,
+ }, {
+ .name = "fb-at91sam9g45es",
+ .driver_data = (unsigned long)&at91sam9g45es_config,
+ }, {
+ .name = "fb-at91sam9rl",
+ .driver_data = (unsigned long)&at91sam9rl_config,
+ }, {
+ .name = "fb-at32ap",
+ .driver_data = (unsigned long)&at32ap_config,
+ }, {
+ /* terminator */
+ }
+};
+
+static struct atmel_lcdfb_config *
+atmel_lcdfb_get_config(struct platform_device *pdev)
+{
+ unsigned long data;
+
+ data = platform_get_device_id(pdev)->driver_data;
+
+ return (struct atmel_lcdfb_config *)data;
+}
+
#if defined(CONFIG_ARCH_AT91)
#define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \
| FBINFO_PARTIAL_PAN_OK \
@@ -199,8 +274,7 @@ static unsigned long compute_hozval(struct atmel_lcdfb_info *sinfo,
unsigned long lcdcon2;
unsigned long value;
- if (!(cpu_is_at91sam9261() || cpu_is_at91sam9g10()
- || cpu_is_at32ap7000()))
+ if (!sinfo->config->have_hozval)
return xres;
lcdcon2 = lcdc_readl(sinfo, ATMEL_LCDC_LCDCON2);
@@ -426,7 +500,7 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
break;
case 16:
/* Older SOCs use IBGR:555 rather than BGR:565. */
- if (sinfo->have_intensity_bit)
+ if (sinfo->config->have_intensity_bit)
var->green.length = 5;
else
var->green.length = 6;
@@ -534,7 +608,7 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
/* Now, the LCDC core... */
/* Set pixel clock */
- if (cpu_is_at91sam9g45() && !cpu_is_at91sam9g45es())
+ if (sinfo->config->have_alt_pixclock)
pix_factor = 1;
clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
@@ -685,7 +759,7 @@ static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red,
case FB_VISUAL_PSEUDOCOLOR:
if (regno < 256) {
- if (sinfo->have_intensity_bit) {
+ if (sinfo->config->have_intensity_bit) {
/* old style I+BGR:555 */
val = ((red >> 11) & 0x001f);
val |= ((green >> 6) & 0x03e0);
@@ -875,10 +949,9 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
}
sinfo->info = info;
sinfo->pdev = pdev;
- if (cpu_is_at91sam9261() || cpu_is_at91sam9263() ||
- cpu_is_at91sam9rl()) {
- sinfo->have_intensity_bit = true;
- }
+ sinfo->config = atmel_lcdfb_get_config(pdev);
+ if (!sinfo->config)
+ goto free_info;
strcpy(info->fix.id, sinfo->pdev->name);
info->flags = ATMEL_LCDFB_FBINFO_DEFAULT;
@@ -889,8 +962,7 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
info->fix = atmel_lcdfb_fix;
/* Enable LCDC Clocks */
- if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()
- || cpu_is_at32ap7000()) {
+ if (sinfo->config->have_bus_clk) {
sinfo->bus_clk = clk_get(dev, "hck1");
if (IS_ERR(sinfo->bus_clk)) {
ret = PTR_ERR(sinfo->bus_clk);
@@ -1152,7 +1224,7 @@ static struct platform_driver atmel_lcdfb_driver = {
.remove = __exit_p(atmel_lcdfb_remove),
.suspend = atmel_lcdfb_suspend,
.resume = atmel_lcdfb_resume,
-
+ .id_table = atmel_lcdfb_devtypes,
.driver = {
.name = "atmel_lcdfb",
.owner = THIS_MODULE,
diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h
index 8deb226..0f5a2fc 100644
--- a/include/video/atmel_lcdc.h
+++ b/include/video/atmel_lcdc.h
@@ -31,6 +31,7 @@
#define ATMEL_LCDC_WIRING_BGR 0
#define ATMEL_LCDC_WIRING_RGB 1
+struct atmel_lcdfb_config;
/* LCD Controller info data structure, stored in device platform_data */
struct atmel_lcdfb_info {
@@ -61,7 +62,8 @@ struct atmel_lcdfb_info {
void (*atmel_lcdfb_power_control)(int on);
struct fb_monspecs *default_monspecs;
u32 pseudo_palette[16];
- bool have_intensity_bit;
+
+ struct atmel_lcdfb_config *config;
};
#define ATMEL_LCDC_DMABADDR1 0x00
--
1.8.1.1
^ permalink raw reply related
* [PATCH 4/5] atmel_lcdfb: move lcdcon2 register access to compute_hozval
From: Johan Hovold @ 2013-02-05 13:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1360071315-4032-1-git-send-email-jhovold@gmail.com>
Pass atmel_lcd_info structure to compute_hozval and only do the register
access on SOCs that actually use it.
This will also simplify the removal of the cpu_is macros.
Signed-off-by: Johan Hovold <jhovold@gmail.com>
---
drivers/video/atmel_lcdfb.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
index 93910e3..347bab2 100644
--- a/drivers/video/atmel_lcdfb.c
+++ b/drivers/video/atmel_lcdfb.c
@@ -193,14 +193,17 @@ static struct fb_fix_screeninfo atmel_lcdfb_fix __initdata = {
.accel = FB_ACCEL_NONE,
};
-static unsigned long compute_hozval(unsigned long xres, unsigned long lcdcon2)
+static unsigned long compute_hozval(struct atmel_lcdfb_info *sinfo,
+ unsigned long xres)
{
+ unsigned long lcdcon2;
unsigned long value;
if (!(cpu_is_at91sam9261() || cpu_is_at91sam9g10()
|| cpu_is_at32ap7000()))
return xres;
+ lcdcon2 = lcdc_readl(sinfo, ATMEL_LCDC_LCDCON2);
value = xres;
if ((lcdcon2 & ATMEL_LCDC_DISTYPE) != ATMEL_LCDC_DISTYPE_TFT) {
/* STN display */
@@ -590,8 +593,7 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value);
/* Horizontal value (aka line size) */
- hozval_linesz = compute_hozval(info->var.xres,
- lcdc_readl(sinfo, ATMEL_LCDC_LCDCON2));
+ hozval_linesz = compute_hozval(sinfo, info->var.xres);
/* Display size */
value = (hozval_linesz - 1) << ATMEL_LCDC_HOZVAL_OFFSET;
--
1.8.1.1
^ permalink raw reply related
* [PATCH 3/5] atmel_lcdfb: remove unsupported 15-bpp mode
From: Johan Hovold @ 2013-02-05 13:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1360071315-4032-1-git-send-email-jhovold@gmail.com>
Since commit 787f9fd23283 ("atmel_lcdfb: support 16bit BGR:565 mode,
remove unsupported 15bit modes") atmel_lcdfb_check_var does not accept
15-bpp mode so remove it from atmel_lcdfb_set_par as well.
Acked-by: Peter Korsgaard <jacmet@sunsite.dk>
Signed-off-by: Johan Hovold <jhovold@gmail.com>
---
drivers/video/atmel_lcdfb.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
index 025428e..93910e3 100644
--- a/drivers/video/atmel_lcdfb.c
+++ b/drivers/video/atmel_lcdfb.c
@@ -567,7 +567,6 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
case 2: value |= ATMEL_LCDC_PIXELSIZE_2; break;
case 4: value |= ATMEL_LCDC_PIXELSIZE_4; break;
case 8: value |= ATMEL_LCDC_PIXELSIZE_8; break;
- case 15: /* fall through */
case 16: value |= ATMEL_LCDC_PIXELSIZE_16; break;
case 24: value |= ATMEL_LCDC_PIXELSIZE_24; break;
case 32: value |= ATMEL_LCDC_PIXELSIZE_32; break;
--
1.8.1.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox