* [PATCH v2] video, udlfb: Fix two build warnings about 'ignoring return value'
From: Liu Yuan @ 2011-04-18 10:44 UTC (permalink / raw)
To: Paul Mundt; +Cc: open list:FRAMEBUFFER LAYER, open list
From: Liu Yuan <tailai.ly@taobao.com>
build warning:
...
drivers/video/udlfb.c:1590: warning: ignoring return value of ‘device_create_file’, declared with attribute warn_unused_result
drivers/video/udlfb.c:1592: warning: ignoring return value of ‘device_create_bin_file’, declared with attribute warn_unused_result
...
So add two checks to get rid of 'em.
Signed-off-by: Liu Yuan <tailai.ly@taobao.com>
---
drivers/video/udlfb.c | 19 ++++++++++++++++---
1 files changed, 16 insertions(+), 3 deletions(-)
diff --git a/drivers/video/udlfb.c b/drivers/video/udlfb.c
index 68041d9..1baa802 100644
--- a/drivers/video/udlfb.c
+++ b/drivers/video/udlfb.c
@@ -1586,10 +1586,19 @@ static int dlfb_usb_probe(struct usb_interface *interface,
goto error;
}
- for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++)
- device_create_file(info->dev, &fb_device_attrs[i]);
+ for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++) {
+ retval = device_create_file(info->dev, &fb_device_attrs[i]);
+ if (retval) {
+ pr_err("device_create_file failed %d\n", retval);
+ goto err_del_attrs;
+ }
+ }
- device_create_bin_file(info->dev, &edid_attr);
+ retval = device_create_bin_file(info->dev, &edid_attr);
+ if (retval) {
+ pr_err("device_create_bin_file failed %d\n", retval);
+ goto err_del_attrs;
+ }
pr_info("DisplayLink USB device /dev/fb%d attached. %dx%d resolution."
" Using %dK framebuffer memory\n", info->node,
@@ -1598,6 +1607,10 @@ static int dlfb_usb_probe(struct usb_interface *interface,
info->fix.smem_len * 2 : info->fix.smem_len) >> 10);
return 0;
+err_del_attrs:
+ for (i -= 1; i >= 0; i--)
+ device_remove_file(info->dev, &fb_device_attrs[i]);
+
error:
if (dev) {
--
1.7.1
^ permalink raw reply related
* Re: [PATCH] video, udlfb: Fix two build warning about 'ignoring
From: Liu Yuan @ 2011-04-18 10:42 UTC (permalink / raw)
To: Paul Mundt; +Cc: linux-fbdev, linux-kernel
In-Reply-To: <20110418084634.GC32457@linux-sh.org>
Ah, thanks for pointing it out. I'll prepare v2 patch for it.
Thanks,
Yuan
On Mon, Apr 18, 2011 at 4:46 PM, Paul Mundt <lethal@linux-sh.org> wrote:
> On Thu, Apr 14, 2011 at 04:17:50PM +0800, Liu Yuan wrote:
>> Build warning:
>> ...
>> drivers/video/udlfb.c:1590: warning: ignoring return value of ???device_create_file???, declared with attribute warn_unused_result
>> drivers/video/udlfb.c:1592: warning: ignoring return value of ???device_create_bin_file???, declared with attribute warn_unused_result
>>
>> So add two checks to get rid of 'em.
>>
>> Signed-off-by: Liu Yuan <tailai.ly@taobao.com>
>> ---
>> drivers/video/udlfb.c | 15 ++++++++++++---
>> 1 files changed, 12 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/video/udlfb.c b/drivers/video/udlfb.c
>> index 68041d9..55d6de6 100644
>> --- a/drivers/video/udlfb.c
>> +++ b/drivers/video/udlfb.c
>> @@ -1586,10 +1586,19 @@ static int dlfb_usb_probe(struct usb_interface *interface,
>> goto error;
>> }
>>
>> - for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++)
>> - device_create_file(info->dev, &fb_device_attrs[i]);
>> + for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++) {
>> + retval = device_create_file(info->dev, &fb_device_attrs[i]);
>> + if (retval) {
>> + pr_err("device_create_file failed %d\n", retval);
>> + goto error;
>> + }
>> + }
>>
>> - device_create_bin_file(info->dev, &edid_attr);
>> + retval = device_create_bin_file(info->dev, &edid_attr);
>> + if (retval) {
>> + pr_err("device_create_bin_file failed %d\n", retval);
>> + goto error;
>> + }
>>
>
> While this will get rid of the warnings, it doesn't take care of cleaning
> up the created files in the error case..
>
^ permalink raw reply
* [PATCH v4] [resend] s3fb: add DDC support
From: Ondrej Zary @ 2011-04-18 10:14 UTC (permalink / raw)
To: Paul Mundt; +Cc: Ondrej Zajicek, linux-fbdev, Kernel development list
Add I2C support for the DDC bus and also default mode initialization by
reading monitor EDID to the s3fb driver.
Tested on Trio64V+ (2 cards), Trio64V2/DX, Virge (3 cards),
Virge/DX (3 cards), Virge/GX2, Trio3D/2X (4 cards), Trio3D.
Will probably not work on Trio32 - my 2 cards have DDC support in BIOS that
looks different from the other cards but the DDC pins on the VGA connector
are not connected.
Signed-off-by: Ondrej Zary <linux@rainbow-software.org>
--- linux-2.6.39-rc2-/drivers/video/s3fb.c 2011-04-11 23:29:44.000000000 +0200
+++ linux-2.6.39-rc2/drivers/video/s3fb.c 2011-04-11 23:10:35.000000000 +0200
@@ -25,6 +25,9 @@
#include <linux/console.h> /* Why should fb driver call console functions? because console_lock() */
#include <video/vga.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+
#ifdef CONFIG_MTRR
#include <asm/mtrr.h>
#endif
@@ -36,6 +39,12 @@ struct s3fb_info {
struct mutex open_lock;
unsigned int ref_count;
u32 pseudo_palette[16];
+#ifdef CONFIG_FB_S3_DDC
+ u8 __iomem *mmio;
+ bool ddc_registered;
+ struct i2c_adapter ddc_adapter;
+ struct i2c_algo_bit_data ddc_algo;
+#endif
};
@@ -105,6 +114,9 @@ static const char * const s3_names[] = {
#define CHIP_UNDECIDED_FLAG 0x80
#define CHIP_MASK 0xFF
+#define MMIO_OFFSET 0x1000000
+#define MMIO_SIZE 0x10000
+
/* CRT timing register sets */
static const struct vga_regset s3_h_total_regs[] = {{0x00, 0, 7}, {0x5D, 0, 0}, VGA_REGSET_END};
@@ -140,7 +152,7 @@ static const struct svga_timing_regs s3_
/* Module parameters */
-static char *mode_option __devinitdata = "640x480-8@60";
+static char *mode_option __devinitdata;
#ifdef CONFIG_MTRR
static int mtrr __devinitdata = 1;
@@ -169,6 +181,119 @@ MODULE_PARM_DESC(fasttext, "Enable S3 fa
/* ------------------------------------------------------------------------- */
+#ifdef CONFIG_FB_S3_DDC
+
+#define DDC_REG 0xaa /* Trio 3D/1X/2X */
+#define DDC_MMIO_REG 0xff20 /* all other chips */
+#define DDC_SCL_OUT (1 << 0)
+#define DDC_SDA_OUT (1 << 1)
+#define DDC_SCL_IN (1 << 2)
+#define DDC_SDA_IN (1 << 3)
+#define DDC_DRIVE_EN (1 << 4)
+
+static bool s3fb_ddc_needs_mmio(int chip)
+{
+ return !(chip = CHIP_360_TRIO3D_1X ||
+ chip = CHIP_362_TRIO3D_2X ||
+ chip = CHIP_368_TRIO3D_2X);
+}
+
+static u8 s3fb_ddc_read(struct s3fb_info *par)
+{
+ if (s3fb_ddc_needs_mmio(par->chip))
+ return readb(par->mmio + DDC_MMIO_REG);
+ else
+ return vga_rcrt(par->state.vgabase, DDC_REG);
+}
+
+static void s3fb_ddc_write(struct s3fb_info *par, u8 val)
+{
+ if (s3fb_ddc_needs_mmio(par->chip))
+ writeb(val, par->mmio + DDC_MMIO_REG);
+ else
+ vga_wcrt(par->state.vgabase, DDC_REG, val);
+}
+
+static void s3fb_ddc_setscl(void *data, int val)
+{
+ struct s3fb_info *par = data;
+ unsigned char reg;
+
+ reg = s3fb_ddc_read(par) | DDC_DRIVE_EN;
+ if (val)
+ reg |= DDC_SCL_OUT;
+ else
+ reg &= ~DDC_SCL_OUT;
+ s3fb_ddc_write(par, reg);
+}
+
+static void s3fb_ddc_setsda(void *data, int val)
+{
+ struct s3fb_info *par = data;
+ unsigned char reg;
+
+ reg = s3fb_ddc_read(par) | DDC_DRIVE_EN;
+ if (val)
+ reg |= DDC_SDA_OUT;
+ else
+ reg &= ~DDC_SDA_OUT;
+ s3fb_ddc_write(par, reg);
+}
+
+static int s3fb_ddc_getscl(void *data)
+{
+ struct s3fb_info *par = data;
+
+ return !!(s3fb_ddc_read(par) & DDC_SCL_IN);
+}
+
+static int s3fb_ddc_getsda(void *data)
+{
+ struct s3fb_info *par = data;
+
+ return !!(s3fb_ddc_read(par) & DDC_SDA_IN);
+}
+
+static int __devinit s3fb_setup_ddc_bus(struct fb_info *info)
+{
+ struct s3fb_info *par = info->par;
+
+ strlcpy(par->ddc_adapter.name, info->fix.id,
+ sizeof(par->ddc_adapter.name));
+ par->ddc_adapter.owner = THIS_MODULE;
+ par->ddc_adapter.class = I2C_CLASS_DDC;
+ par->ddc_adapter.algo_data = &par->ddc_algo;
+ par->ddc_adapter.dev.parent = info->device;
+ par->ddc_algo.setsda = s3fb_ddc_setsda;
+ par->ddc_algo.setscl = s3fb_ddc_setscl;
+ par->ddc_algo.getsda = s3fb_ddc_getsda;
+ par->ddc_algo.getscl = s3fb_ddc_getscl;
+ par->ddc_algo.udelay = 10;
+ par->ddc_algo.timeout = 20;
+ par->ddc_algo.data = par;
+
+ i2c_set_adapdata(&par->ddc_adapter, par);
+
+ /*
+ * some Virge cards have external MUX to switch chip I2C bus between
+ * DDC and extension pins - switch it do DDC
+ */
+/* vga_wseq(par->state.vgabase, 0x08, 0x06); - not needed, already unlocked */
+ if (par->chip = CHIP_357_VIRGE_GX2 ||
+ par->chip = CHIP_359_VIRGE_GX2P)
+ svga_wseq_mask(par->state.vgabase, 0x0d, 0x01, 0x03);
+ else
+ svga_wseq_mask(par->state.vgabase, 0x0d, 0x00, 0x03);
+ /* some Virge need this or the DDC is ignored */
+ svga_wcrt_mask(par->state.vgabase, 0x5c, 0x03, 0x03);
+
+ return i2c_bit_add_bus(&par->ddc_adapter);
+}
+#endif /* CONFIG_FB_S3_DDC */
+
+
+/* ------------------------------------------------------------------------- */
+
/* Set font in S3 fast text mode */
static void s3fb_settile_fast(struct fb_info *info, struct fb_tilemap *map)
@@ -994,6 +1119,7 @@ static int __devinit s3_pci_probe(struct
struct s3fb_info *par;
int rc;
u8 regval, cr38, cr39;
+ bool found = false;
/* Ignore secondary VGA device because there is no VGA arbitration */
if (! svga_primary_device(dev)) {
@@ -1110,12 +1236,69 @@ static int __devinit s3_pci_probe(struct
info->fix.ypanstep = 0;
info->fix.accel = FB_ACCEL_NONE;
info->pseudo_palette = (void*) (par->pseudo_palette);
+ info->var.bits_per_pixel = 8;
+
+#ifdef CONFIG_FB_S3_DDC
+ /* Enable MMIO if needed */
+ if (s3fb_ddc_needs_mmio(par->chip)) {
+ par->mmio = ioremap(info->fix.smem_start + MMIO_OFFSET, MMIO_SIZE);
+ if (par->mmio)
+ svga_wcrt_mask(par->state.vgabase, 0x53, 0x08, 0x08); /* enable MMIO */
+ else
+ dev_err(info->device, "unable to map MMIO at 0x%lx, disabling DDC",
+ info->fix.smem_start + MMIO_OFFSET);
+ }
+ if (!s3fb_ddc_needs_mmio(par->chip) || par->mmio)
+ if (s3fb_setup_ddc_bus(info) = 0) {
+ u8 *edid = fb_ddc_read(&par->ddc_adapter);
+ par->ddc_registered = true;
+ if (edid) {
+ fb_edid_to_monspecs(edid, &info->monspecs);
+ kfree(edid);
+ if (!info->monspecs.modedb)
+ dev_err(info->device, "error getting mode database\n");
+ else {
+ const struct fb_videomode *m;
+
+ fb_videomode_to_modelist(info->monspecs.modedb,
+ info->monspecs.modedb_len,
+ &info->modelist);
+ m = fb_find_best_display(&info->monspecs, &info->modelist);
+ if (m) {
+ fb_videomode_to_var(&info->var, m);
+ /* fill all other info->var's fields */
+ if (s3fb_check_var(&info->var, info) = 0)
+ found = true;
+ }
+ }
+ }
+ }
+#endif
+ if (!mode_option && !found)
+ mode_option = "640x480-8@60";
/* Prepare startup mode */
- rc = fb_find_mode(&(info->var), info, mode_option, NULL, 0, NULL, 8);
- if (! ((rc = 1) || (rc = 2))) {
- rc = -EINVAL;
- dev_err(info->device, "mode %s not found\n", mode_option);
+ if (mode_option) {
+ rc = fb_find_mode(&info->var, info, mode_option,
+ info->monspecs.modedb, info->monspecs.modedb_len,
+ NULL, info->var.bits_per_pixel);
+ if (!rc || rc = 4) {
+ rc = -EINVAL;
+ dev_err(info->device, "mode %s not found\n", mode_option);
+ fb_destroy_modedb(info->monspecs.modedb);
+ info->monspecs.modedb = NULL;
+ goto err_find_mode;
+ }
+ }
+
+ fb_destroy_modedb(info->monspecs.modedb);
+ info->monspecs.modedb = NULL;
+
+ /* maximize virtual vertical size for fast scrolling */
+ info->var.yres_virtual = info->fix.smem_len * 8 /
+ (info->var.bits_per_pixel * info->var.xres_virtual);
+ if (info->var.yres_virtual < info->var.yres) {
+ dev_err(info->device, "virtual vertical size smaller than real\n");
goto err_find_mode;
}
@@ -1164,6 +1347,12 @@ err_reg_fb:
fb_dealloc_cmap(&info->cmap);
err_alloc_cmap:
err_find_mode:
+#ifdef CONFIG_FB_S3_DDC
+ if (par->ddc_registered)
+ i2c_del_adapter(&par->ddc_adapter);
+ if (par->mmio)
+ iounmap(par->mmio);
+#endif
pci_iounmap(dev, info->screen_base);
err_iomap:
pci_release_regions(dev);
@@ -1195,6 +1384,13 @@ static void __devexit s3_pci_remove(stru
unregister_framebuffer(info);
fb_dealloc_cmap(&info->cmap);
+#ifdef CONFIG_FB_S3_DDC
+ if (par->ddc_registered)
+ i2c_del_adapter(&par->ddc_adapter);
+ if (par->mmio)
+ iounmap(par->mmio);
+#endif
+
pci_iounmap(dev, info->screen_base);
pci_release_regions(dev);
/* pci_disable_device(dev); */
--- linux-2.6.39-rc2-orig/drivers/video/Kconfig 2011-04-06 03:30:43.000000000 +0200
+++ linux-2.6.39-rc2/drivers/video/Kconfig 2011-04-11 22:41:18.000000000 +0200
@@ -1463,6 +1463,14 @@ config FB_S3
---help---
Driver for graphics boards with S3 Trio / S3 Virge chip.
+config FB_S3_DDC
+ bool "DDC for S3 support"
+ depends on FB_S3
+ select FB_DDC
+ default y
+ help
+ Say Y here if you want DDC support for your S3 graphics card.
+
config FB_SAVAGE
tristate "S3 Savage support"
depends on FB && PCI && EXPERIMENTAL
--
Ondrej Zary
^ permalink raw reply
* Re: [GIT PULL] OMAP DSS fixes for 39 rc
From: Paul Mundt @ 2011-04-18 8:49 UTC (permalink / raw)
To: Tomi Valkeinen; +Cc: lo-ml, lfbdev-ml
In-Reply-To: <1303110761.2062.11.camel@deskari>
On Mon, Apr 18, 2011 at 10:12:41AM +0300, Tomi Valkeinen wrote:
> Here are a few OMAP DSS fixes for the next rc.
>
Pulled and pushed out, thanks.
^ permalink raw reply
* Re: [PATCH] video, udlfb: Fix two build warning about 'ignoring return value'
From: Paul Mundt @ 2011-04-18 8:46 UTC (permalink / raw)
To: Liu Yuan; +Cc: linux-fbdev, linux-kernel
In-Reply-To: <1302769070-21670-1-git-send-email-namei.unix@gmail.com>
On Thu, Apr 14, 2011 at 04:17:50PM +0800, Liu Yuan wrote:
> Build warning:
> ...
> drivers/video/udlfb.c:1590: warning: ignoring return value of ???device_create_file???, declared with attribute warn_unused_result
> drivers/video/udlfb.c:1592: warning: ignoring return value of ???device_create_bin_file???, declared with attribute warn_unused_result
>
> So add two checks to get rid of 'em.
>
> Signed-off-by: Liu Yuan <tailai.ly@taobao.com>
> ---
> drivers/video/udlfb.c | 15 ++++++++++++---
> 1 files changed, 12 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/video/udlfb.c b/drivers/video/udlfb.c
> index 68041d9..55d6de6 100644
> --- a/drivers/video/udlfb.c
> +++ b/drivers/video/udlfb.c
> @@ -1586,10 +1586,19 @@ static int dlfb_usb_probe(struct usb_interface *interface,
> goto error;
> }
>
> - for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++)
> - device_create_file(info->dev, &fb_device_attrs[i]);
> + for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++) {
> + retval = device_create_file(info->dev, &fb_device_attrs[i]);
> + if (retval) {
> + pr_err("device_create_file failed %d\n", retval);
> + goto error;
> + }
> + }
>
> - device_create_bin_file(info->dev, &edid_attr);
> + retval = device_create_bin_file(info->dev, &edid_attr);
> + if (retval) {
> + pr_err("device_create_bin_file failed %d\n", retval);
> + goto error;
> + }
>
While this will get rid of the warnings, it doesn't take care of cleaning
up the created files in the error case..
^ permalink raw reply
* [GIT PULL] OMAP DSS fixes for 39 rc
From: Tomi Valkeinen @ 2011-04-18 7:12 UTC (permalink / raw)
To: lethal; +Cc: lo-ml, lfbdev-ml
Hi Paul,
Here are a few OMAP DSS fixes for the next rc.
Tomi
The following changes since commit a6360dd37e1a144ed11e6548371bade559a1e4df:
Linux 2.6.39-rc3 (2011-04-11 17:21:51 -0700)
are available in the git repository at:
git://gitorious.org/linux-omap-dss2/linux.git for-paul-39-rc
Archit Taneja (1):
OMAP: DSS2: Fix: Return correct lcd clock source for OMAP2/3
Tomi Valkeinen (4):
OMAP: DSS2: DSI: fix use_sys_clk & highfreq
OMAP: DSS2: DSI: fix dsi_dump_clocks()
OMAP: DSS2: DSI: Fix DSI PLL power bug
OMAP: DSS2: fix panel Kconfig dependencies
drivers/video/omap2/displays/Kconfig | 9 +++++----
drivers/video/omap2/dss/dsi.c | 14 +++++++++-----
drivers/video/omap2/dss/dss.c | 10 ++++++++--
drivers/video/omap2/dss/dss_features.c | 2 +-
drivers/video/omap2/dss/dss_features.h | 2 ++
5 files changed, 25 insertions(+), 12 deletions(-)
^ permalink raw reply
* Re: [REGRESSION] [2.6.39-rc3] Wrong resolution in framebuffer and X Window
From: Maciej Rutecki @ 2011-04-17 16:06 UTC (permalink / raw)
To: linux-fbdev; +Cc: Rafael J. Wysocki, dri-devel, mbroemme
In-Reply-To: <201104171804.04664.maciej.rutecki@gmail.com>
On niedziela, 17 kwietnia 2011 o 18:04:04 Maciej Rutecki wrote:
> Hi
>
> Last known good: 2.6.38
> Failing kernel: 2.6.39-rc3
> Subsystem: Intel graphics driver.
>
> Description:
> PC should work with 1440x900 resolution. But console (and after) X Window
> start work with 1024x768.
>
> I attach dmesg and Xorg.0.log with drm.debug\x14 log_buf_len\x16M options:
> http://unixy.pl/maciek/download/kernel/2.6.39-rc1/zlom/kms/
>
> seems that driver cannot detect resolution higher than 1024x768.
>
> Also I boot kernel replace "i915.modeset=1" with "nomodeset" option:
> http://unixy.pl/maciek/download/kernel/2.6.39-rc1/zlom/nomodeset/
>
> But then X Window fails to start and got message: "(EE) No devices
> detected."
>
> Config for 2.6.39-rc3:
> http://unixy.pl/maciek/download/kernel/2.6.39-rc1/zlom/config-2.6.39-rc3
>
> Best regards
Forgot:
00:02.0 VGA compatible controller: Intel Corporation 82G33/G31 Express
Integrated Graphics Controller (rev 02)
Regards
--
Maciej Rutecki
http://www.maciek.unixy.pl
^ permalink raw reply
* [REGRESSION] [2.6.39-rc3] Wrong resolution in framebuffer and X Window
From: Maciej Rutecki @ 2011-04-17 16:04 UTC (permalink / raw)
To: linux-fbdev, mbroemme, airlied, dri-devel, Rafael J. Wysocki
Hi
Last known good: 2.6.38
Failing kernel: 2.6.39-rc3
Subsystem: Intel graphics driver.
Description:
PC should work with 1440x900 resolution. But console (and after) X Window
start work with 1024x768.
I attach dmesg and Xorg.0.log with drm.debug\x14 log_buf_len\x16M options:
http://unixy.pl/maciek/download/kernel/2.6.39-rc1/zlom/kms/
seems that driver cannot detect resolution higher than 1024x768.
Also I boot kernel replace "i915.modeset=1" with "nomodeset" option:
http://unixy.pl/maciek/download/kernel/2.6.39-rc1/zlom/nomodeset/
But then X Window fails to start and got message: "(EE) No devices detected."
Config for 2.6.39-rc3:
http://unixy.pl/maciek/download/kernel/2.6.39-rc1/zlom/config-2.6.39-rc3
Best regards
--
Maciej Rutecki
http://www.maciek.unixy.pl
^ permalink raw reply
* [PATCH] viafb: fix OLPC DCON refresh rate
From: Florian Tobias Schandinat @ 2011-04-15 21:52 UTC (permalink / raw)
To: linux-fbdev; +Cc: linux-kernel, Daniel Drake, Florian Tobias Schandinat
In-Reply-To: <4DA62C4D.8070407@gmx.de>
This patch fixes a regression introduced by
fd3cc69848b7e1873e5f12bbcdd572b20277ecf3a
"viafb: remove duplicated clock storage"
caused by an incosistent mode which pretended to have a higher
refresh rate than it actually had. The wrong refresh rate resulted
in a calculated higher pixclock which the OLPC DCON could not handle.
By reducing the refresh rate to 50Hz we get close to the old
pixclock which makes the OLPC display usable again.
Minor other adjustments are needed as 60Hz is assumed to be a safe
value which is not true for OLPC DCON. This is no problem as we only
support 1200x900 on the OLPC.
Signed-off-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
Reported-by: Daniel Drake <dsd@laptop.org>
---
drivers/video/via/hw.c | 8 ++++++--
drivers/video/via/viamode.c | 2 +-
2 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c
index dc4c778..980e263 100644
--- a/drivers/video/via/hw.c
+++ b/drivers/video/via/hw.c
@@ -2598,8 +2598,12 @@ int viafb_get_refresh(int hres, int vres, u32 long_refresh)
best = &vmode->crtc[i];
}
- if (abs(best->refresh_rate - long_refresh) > 3)
- return 60;
+ if (abs(best->refresh_rate - long_refresh) > 3) {
+ if (hres = 1200 && vres = 900)
+ return 50; /* OLPC DCON only supports 50 Hz */
+ else
+ return 60;
+ }
return best->refresh_rate;
}
diff --git a/drivers/video/via/viamode.c b/drivers/video/via/viamode.c
index 8c5bc41..260d339 100644
--- a/drivers/video/via/viamode.c
+++ b/drivers/video/via/viamode.c
@@ -606,7 +606,7 @@ static struct crt_mode_table CRTM1200x720[] = {
/* 1200x900 (DCON) */
static struct crt_mode_table DCON1200x900[] = {
/* r_rate, hsp, vsp */
- {REFRESH_60, M1200X900_R60_HSP, M1200X900_R60_VSP,
+ {REFRESH_50, M1200X900_R60_HSP, M1200X900_R60_VSP,
/* The correct htotal is 1240, but this doesn't raster on VX855. */
/* Via suggested changing to a multiple of 16, hence 1264. */
/* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
--
1.6.3.2
^ permalink raw reply related
* Re: [PATCH 0/5] OMAP: DSS: fixes for rc
From: Steve Sakoman @ 2011-04-15 17:32 UTC (permalink / raw)
To: Tomi Valkeinen; +Cc: linux-omap, linux-fbdev, archit
In-Reply-To: <1302855071-5510-1-git-send-email-tomi.valkeinen@ti.com>
On Fri, Apr 15, 2011 at 1:11 AM, Tomi Valkeinen <tomi.valkeinen@ti.com> wrote:
> Some small fixes to OMAP DSS for the next rc.
>
> I will send a pull request to Paul Mundt soon if there are no problems with the
> patches.
Tested on Overo (both 35XX and 37XX versions).
This patch series fixes the earlier issue of no video output on 37XX boards.
Tested-by: Steve Sakoman <steve@sakoman.com>
^ permalink raw reply
* [PATCH 5/5] OMAP: DSS2: fix panel Kconfig dependencies
From: Tomi Valkeinen @ 2011-04-15 8:11 UTC (permalink / raw)
To: linux-omap, linux-fbdev; +Cc: archit, Tomi Valkeinen
In-Reply-To: <1302855071-5510-1-git-send-email-tomi.valkeinen@ti.com>
All DPI panels were missing dependency to OMAP2_DSS_DPI. Add the
dependency.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
drivers/video/omap2/displays/Kconfig | 9 +++++----
1 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/drivers/video/omap2/displays/Kconfig b/drivers/video/omap2/displays/Kconfig
index d18ad6b..609a280 100644
--- a/drivers/video/omap2/displays/Kconfig
+++ b/drivers/video/omap2/displays/Kconfig
@@ -3,6 +3,7 @@ menu "OMAP2/3 Display Device Drivers"
config PANEL_GENERIC_DPI
tristate "Generic DPI Panel"
+ depends on OMAP2_DSS_DPI
help
Generic DPI panel driver.
Supports DVI output for Beagle and OMAP3 SDP.
@@ -11,20 +12,20 @@ config PANEL_GENERIC_DPI
config PANEL_LGPHILIPS_LB035Q02
tristate "LG.Philips LB035Q02 LCD Panel"
- depends on OMAP2_DSS && SPI
+ depends on OMAP2_DSS_DPI && SPI
help
LCD Panel used on the Gumstix Overo Palo35
config PANEL_SHARP_LS037V7DW01
tristate "Sharp LS037V7DW01 LCD Panel"
- depends on OMAP2_DSS
+ depends on OMAP2_DSS_DPI
select BACKLIGHT_CLASS_DEVICE
help
LCD Panel used in TI's SDP3430 and EVM boards
config PANEL_NEC_NL8048HL11_01B
tristate "NEC NL8048HL11-01B Panel"
- depends on OMAP2_DSS
+ depends on OMAP2_DSS_DPI
help
This NEC NL8048HL11-01B panel is TFT LCD
used in the Zoom2/3/3630 sdp boards.
@@ -37,7 +38,7 @@ config PANEL_TAAL
config PANEL_TPO_TD043MTEA1
tristate "TPO TD043MTEA1 LCD Panel"
- depends on OMAP2_DSS && SPI
+ depends on OMAP2_DSS_DPI && SPI
help
LCD Panel used in OMAP3 Pandora
--
1.7.1
^ permalink raw reply related
* [PATCH 4/5] OMAP: DSS2: DSI: Fix DSI PLL power bug
From: Tomi Valkeinen @ 2011-04-15 8:11 UTC (permalink / raw)
To: linux-omap, linux-fbdev; +Cc: archit, Tomi Valkeinen
In-Reply-To: <1302855071-5510-1-git-send-email-tomi.valkeinen@ti.com>
OMAP3630 has a HW bug causing DSI PLL power command POWER_ON_DIV (0x3)
to not work properly. The bug prevents us from enabling DSI PLL power
only to HS divider block.
This patch adds a dss feature for the bug and converts POWER_ON_DIV
requests to POWER_ON_ALL (0x2).
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
drivers/video/omap2/dss/dsi.c | 5 +++++
drivers/video/omap2/dss/dss_features.c | 2 +-
drivers/video/omap2/dss/dss_features.h | 2 ++
3 files changed, 8 insertions(+), 1 deletions(-)
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
index 1464ac4..cbd9ca4 100644
--- a/drivers/video/omap2/dss/dsi.c
+++ b/drivers/video/omap2/dss/dsi.c
@@ -1059,6 +1059,11 @@ static int dsi_pll_power(enum dsi_pll_power_state state)
{
int t = 0;
+ /* DSI-PLL power command 0x3 is not working */
+ if (dss_has_feature(FEAT_DSI_PLL_PWR_BUG) &&
+ state = DSI_PLL_POWER_ON_DIV)
+ state = DSI_PLL_POWER_ON_ALL;
+
REG_FLD_MOD(DSI_CLK_CTRL, state, 31, 30); /* PLL_PWR_CMD */
/* PLL_PWR_STATUS */
diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c
index aa16222..8c50e18 100644
--- a/drivers/video/omap2/dss/dss_features.c
+++ b/drivers/video/omap2/dss/dss_features.c
@@ -271,7 +271,7 @@ static struct omap_dss_features omap3630_dss_features = {
FEAT_LCDENABLESIGNAL | FEAT_PCKFREEENABLE |
FEAT_PRE_MULT_ALPHA | FEAT_FUNCGATED |
FEAT_ROWREPEATENABLE | FEAT_LINEBUFFERSPLIT |
- FEAT_RESIZECONF,
+ FEAT_RESIZECONF | FEAT_DSI_PLL_PWR_BUG,
.num_mgrs = 2,
.num_ovls = 3,
diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h
index 12e9c4e..37922ce 100644
--- a/drivers/video/omap2/dss/dss_features.h
+++ b/drivers/video/omap2/dss/dss_features.h
@@ -40,6 +40,8 @@ enum dss_feat_id {
/* Independent core clk divider */
FEAT_CORE_CLK_DIV = 1 << 11,
FEAT_LCD_CLK_SRC = 1 << 12,
+ /* DSI-PLL power command 0x3 is not working */
+ FEAT_DSI_PLL_PWR_BUG = 1 << 13,
};
/* DSS register field id */
--
1.7.1
^ permalink raw reply related
* [PATCH 3/5] OMAP: DSS2: Fix: Return correct lcd clock source for OMAP2/3
From: Tomi Valkeinen @ 2011-04-15 8:11 UTC (permalink / raw)
To: linux-omap, linux-fbdev; +Cc: archit, Tomi Valkeinen
In-Reply-To: <1302855071-5510-1-git-send-email-tomi.valkeinen@ti.com>
From: Archit Taneja <archit@ti.com>
dss.lcd_clk_source is set to the default value DSS_CLK_SRC_FCK at dss_init.
For OMAP2 and OMAP3, the dss.lcd_clk_source should always be the same as
dss.dispc_clk_source. The function dss_get_lcd_clk_source() always returns the
default value DSS_CLK_SRC_FCK for OMAP2/3. This leads to wrong clock dumps when
dispc_clk_source is not DSS_CLK_SRC_FCK.
Correct this function to always return dss.dispc_clk_source for OMAP2/3.
Signed-off-by: Archit Taneja <archit@ti.com>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
drivers/video/omap2/dss/dss.c | 10 ++++++++--
1 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c
index 3f1fee6..c3b48a0 100644
--- a/drivers/video/omap2/dss/dss.c
+++ b/drivers/video/omap2/dss/dss.c
@@ -385,8 +385,14 @@ enum dss_clk_source dss_get_dsi_clk_source(void)
enum dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel)
{
- int ix = channel = OMAP_DSS_CHANNEL_LCD ? 0 : 1;
- return dss.lcd_clk_source[ix];
+ if (dss_has_feature(FEAT_LCD_CLK_SRC)) {
+ int ix = channel = OMAP_DSS_CHANNEL_LCD ? 0 : 1;
+ return dss.lcd_clk_source[ix];
+ } else {
+ /* LCD_CLK source is the same as DISPC_FCLK source for
+ * OMAP2 and OMAP3 */
+ return dss.dispc_clk_source;
+ }
}
/* calculate clock rates using dividers in cinfo */
--
1.7.1
^ permalink raw reply related
* [PATCH 2/5] OMAP: DSS2: DSI: fix dsi_dump_clocks()
From: Tomi Valkeinen @ 2011-04-15 8:11 UTC (permalink / raw)
To: linux-omap, linux-fbdev; +Cc: archit, Tomi Valkeinen
In-Reply-To: <1302855071-5510-1-git-send-email-tomi.valkeinen@ti.com>
On OMAP4, reading DSI_PLL_CONFIGURATION2 register requires the L3 clock
(CIO_CLK_ICG) to PLL. Currently dsi_dump_clocks() tries to read that
register without enabling the L3 clock, leading to crash if DSI is not
in use.
The status of the bit being read from DSI_PLL_CONFIGURATION2 is
available from dsi_clock_info->use_sys_clk, so we can avoid the whole
problem by just using that.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
drivers/video/omap2/dss/dsi.c | 6 +-----
1 files changed, 1 insertions(+), 5 deletions(-)
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
index 8604153..1464ac4 100644
--- a/drivers/video/omap2/dss/dsi.c
+++ b/drivers/video/omap2/dss/dsi.c
@@ -1491,7 +1491,6 @@ void dsi_pll_uninit(void)
void dsi_dump_clocks(struct seq_file *s)
{
- int clksel;
struct dsi_clock_info *cinfo = &dsi.current_cinfo;
enum dss_clk_source dispc_clk_src, dsi_clk_src;
@@ -1500,13 +1499,10 @@ void dsi_dump_clocks(struct seq_file *s)
enable_clocks(1);
- clksel = REG_GET(DSI_PLL_CONFIGURATION2, 11, 11);
-
seq_printf(s, "- DSI PLL -\n");
seq_printf(s, "dsi pll source = %s\n",
- clksel = 0 ?
- "dss_sys_clk" : "pclkfree");
+ cinfo->use_sys_clk ? "dss_sys_clk" : "pclkfree");
seq_printf(s, "Fint\t\t%-16luregn %u\n", cinfo->fint, cinfo->regn);
--
1.7.1
^ permalink raw reply related
* [PATCH 1/5] OMAP: DSS2: DSI: fix use_sys_clk & highfreq
From: Tomi Valkeinen @ 2011-04-15 8:11 UTC (permalink / raw)
To: linux-omap, linux-fbdev; +Cc: archit, Tomi Valkeinen
In-Reply-To: <1302855071-5510-1-git-send-email-tomi.valkeinen@ti.com>
use_sys_clk and highfreq fields in dsi.current_cinfo were never set.
Luckily they weren't used anywhere so it didn't cause any problems.
This patch fixes those fields and they are now set at the same time as
the rest of the fields.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
drivers/video/omap2/dss/dsi.c | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
index 0a7f1a4..8604153 100644
--- a/drivers/video/omap2/dss/dsi.c
+++ b/drivers/video/omap2/dss/dsi.c
@@ -1276,6 +1276,9 @@ int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo)
DSSDBGF();
+ dsi.current_cinfo.use_sys_clk = cinfo->use_sys_clk;
+ dsi.current_cinfo.highfreq = cinfo->highfreq;
+
dsi.current_cinfo.fint = cinfo->fint;
dsi.current_cinfo.clkin4ddr = cinfo->clkin4ddr;
dsi.current_cinfo.dsi_pll_hsdiv_dispc_clk --
1.7.1
^ permalink raw reply related
* [PATCH 0/5] OMAP: DSS: fixes for rc
From: Tomi Valkeinen @ 2011-04-15 8:11 UTC (permalink / raw)
To: linux-omap, linux-fbdev; +Cc: archit, Tomi Valkeinen
Some small fixes to OMAP DSS for the next rc.
I will send a pull request to Paul Mundt soon if there are no problems with the
patches.
Note that DSS doesn't still work for OMAP4. It needs a clock patch which has
been discussed on l-o, and Paul Walmsley will handle that patch.
Tomi
Archit Taneja (1):
OMAP: DSS2: Fix: Return correct lcd clock source for OMAP2/3
Tomi Valkeinen (4):
OMAP: DSS2: DSI: fix use_sys_clk & highfreq
OMAP: DSS2: DSI: fix dsi_dump_clocks()
OMAP: DSS2: DSI: Fix DSI PLL power bug
OMAP: DSS2: fix panel Kconfig dependencies
drivers/video/omap2/displays/Kconfig | 9 +++++----
drivers/video/omap2/dss/dsi.c | 14 +++++++++-----
drivers/video/omap2/dss/dss.c | 10 ++++++++--
drivers/video/omap2/dss/dss_features.c | 2 +-
drivers/video/omap2/dss/dss_features.h | 2 ++
5 files changed, 25 insertions(+), 12 deletions(-)
^ permalink raw reply
* Re: [PATCH 1/2] video: add Samsung SoC MIPI-DSI controller driver.
From: daeinki @ 2011-04-15 2:32 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <BANLkTi=VCpDp6aPZc9sPqmos0XmtJ+UvyQ@mail.gmail.com>
Kyungmin Park 쓴 글:
> Mr. Dae,
>
> If only MIPI header files are used at video, just place it under video
> directory.
all structure and definitions included in mipi_dsim.h file should be set
as machine specific data such as config data(pixel format, lane count,
..), platform data, mipi dsim device structure and so on.
>
> regardless this issue, how about the make a generic mipi dsi interface at video?
> then other soc will be helpful also.
>
> e.g., one generic MIPI DSI framework and each SoCs register the
> operations or override the functions or better way.
>
> No need to think/consider the samsung SOCs only.
I agree to your opinion. common framework for mipi dsi would be helpful
and also I think we could avoid duplicated codes. for this, first of all
it needs open source developer's opinions related to MIPI-DSI because
some mipi-dsi drivers, as I know, omap dss and ARM-shmobile, have been
already applied to mainline. I guess someone who is mipi-dsi driver
developer tried to propose common framework for mipi-dsi before.
so Mr. Pual, have you ever been discussed about common framework for
mipi-dsi before?, if not or needs it, I'd like to propose common
framework for it. of course, this work would take a long time and needs
many hard work and RFC.
I'll look forward to your answer. thank you.
>
> Thank you,
> Kyungmin Park
>
> On Thu, Apr 14, 2011 at 9:15 PM, Inki Dae <inki.dae@samsung.com> wrote:
>> Samsung S5PV210 and EXYNOS4 SoC platform have one or two MIPI-DSI controller.
>> MIPI-DSI based LCD Panel could be used with MIPI-DSI controller driver.
>> this patch adds the MIPI-DSI controller driver and also this driver would
>> support both platforms.
>>
>> to use MIPI-DSI based LCD Panel driver, mipi_dsim_lcd_device should be
>> registered to MIPI-DSI Driver through s5p_mipi_dsi_register_lcd_device() call
>> in machine code or machine specific somewhere first, and mipi_dsim_lcd_driver
>> should be registered when s5p_mipi_dsi_register_lcd_driver() is called at init
>> function of lcd driver, and then probe() of that driver would be called by
>> MIPI-DSI controller driver if lcd panel name and id of mipi_dsim_lcd_device
>> are same as ones of mipi_dsim_lcd_driver.
>>
>> for this, you can refer to sample lcd panel driver.
>> please see "Documentation/s5p_mipi_dsim/dsim_sample_lcd.c"
>>
>> Signed-off-by: Inki Dae <inki.dae@samsung.com>
>> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
>> ---
>> arch/arm/plat-s5p/include/plat/mipi_dsim.h | 345 +++++++++++++++
>> arch/arm/plat-s5p/include/plat/regs-dsim.h | 143 ++++++
>> drivers/video/Kconfig | 7 +
>> drivers/video/Makefile | 2 +
>> drivers/video/s5p_mipi_dsi.c | 481 ++++++++++++++++++++
>> drivers/video/s5p_mipi_dsi_common.c | 655 ++++++++++++++++++++++++++++
>> drivers/video/s5p_mipi_dsi_common.h | 39 ++
>> drivers/video/s5p_mipi_dsi_lowlevel.c | 558 +++++++++++++++++++++++
>> drivers/video/s5p_mipi_dsi_lowlevel.h | 100 +++++
>> 9 files changed, 2330 insertions(+), 0 deletions(-)
>> create mode 100644 arch/arm/plat-s5p/include/plat/mipi_dsim.h
>> create mode 100644 arch/arm/plat-s5p/include/plat/regs-dsim.h
>> create mode 100644 drivers/video/s5p_mipi_dsi.c
>> create mode 100644 drivers/video/s5p_mipi_dsi_common.c
>> create mode 100644 drivers/video/s5p_mipi_dsi_common.h
>> create mode 100644 drivers/video/s5p_mipi_dsi_lowlevel.c
>> create mode 100644 drivers/video/s5p_mipi_dsi_lowlevel.h
>>
>> diff --git a/arch/arm/plat-s5p/include/plat/mipi_dsim.h b/arch/arm/plat-s5p/include/plat/mipi_dsim.h
>> new file mode 100644
>> index 0000000..0fa2d7e
>> --- /dev/null
>> +++ b/arch/arm/plat-s5p/include/plat/mipi_dsim.h
>> @@ -0,0 +1,345 @@
>> +/* linux/arm/arch/plat-s5p/include/plat/mipi_dsim.h
>> + *
>> + * Platform data header for Samsung SoC MIPI-DSIM.
>> + *
>> + * Copyright (c) 2011 Samsung Electronics Co., Ltd
>> + *
>> + * InKi Dae <inki.dae@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.
>> +*/
>> +
>> +#ifndef _DSIM_H
>> +#define _DSIM_H
>> +
>> +#include <linux/device.h>
>> +#include <linux/fb.h>
>> +
>> +#define PANEL_NAME_SIZE (32)
>> +
>> +enum mipi_dsim_interface_type {
>> + DSIM_COMMAND,
>> + DSIM_VIDEO
>> +};
>> +
>> +enum mipi_dsim_virtual_ch_no {
>> + DSIM_VIRTUAL_CH_0,
>> + DSIM_VIRTUAL_CH_1,
>> + DSIM_VIRTUAL_CH_2,
>> + DSIM_VIRTUAL_CH_3
>> +};
>> +
>> +enum mipi_dsim_burst_mode_type {
>> + DSIM_NON_BURST_SYNC_EVENT,
>> + DSIM_NON_BURST_SYNC_PULSE = 2,
>> + DSIM_BURST,
>> + DSIM_NON_VIDEO_MODE
>> +};
>> +
>> +enum mipi_dsim_no_of_data_lane {
>> + DSIM_DATA_LANE_1,
>> + DSIM_DATA_LANE_2,
>> + DSIM_DATA_LANE_3,
>> + DSIM_DATA_LANE_4
>> +};
>> +
>> +enum mipi_dsim_byte_clk_src {
>> + DSIM_PLL_OUT_DIV8,
>> + DSIM_EXT_CLK_DIV8,
>> + DSIM_EXT_CLK_BYPASS
>> +};
>> +
>> +enum mipi_dsim_pixel_format {
>> + DSIM_CMD_3BPP,
>> + DSIM_CMD_8BPP,
>> + DSIM_CMD_12BPP,
>> + DSIM_CMD_16BPP,
>> + DSIM_VID_16BPP_565,
>> + DSIM_VID_18BPP_666PACKED,
>> + DSIM_18BPP_666LOOSELYPACKED,
>> + DSIM_24BPP_888
>> +};
>> +
>> +/**
>> + * struct mipi_dsim_config - interface for configuring mipi-dsi controller.
>> + *
>> + * @auto_flush: enable or disable Auto flush of MD FIFO using VSYNC pulse.
>> + * @eot_disable: enable or disable EoT packet in HS mode.
>> + * @auto_vertical_cnt: specifies auto vertical count mode.
>> + * in Video mode, the vertical line transition uses line counter
>> + * configured by VSA, VBP, and Vertical resolution.
>> + * If this bit is set to '1', the line counter does not use VSA and VBP
>> + * registers.(in command mode, this variable is ignored)
>> + * @hse: set horizontal sync event mode.
>> + * In VSYNC pulse and Vporch area, MIPI DSI master transfers only HSYNC
>> + * start packet to MIPI DSI slave at MIPI DSI spec1.1r02.
>> + * this bit transfers HSYNC end packet in VSYNC pulse and Vporch area
>> + * (in mommand mode, this variable is ignored)
>> + * @hfp: specifies HFP disable mode.
>> + * if this variable is set, DSI master ignores HFP area in VIDEO mode.
>> + * (in command mode, this variable is ignored)
>> + * @hbp: specifies HBP disable mode.
>> + * if this variable is set, DSI master ignores HBP area in VIDEO mode.
>> + * (in command mode, this variable is ignored)
>> + * @hsa: specifies HSA disable mode.
>> + * if this variable is set, DSI master ignores HSA area in VIDEO mode.
>> + * (in command mode, this variable is ignored)
>> + * @e_interface: specifies interface to be used.(CPU or RGB interface)
>> + * @e_virtual_ch: specifies virtual channel number that main or
>> + * sub diaplsy uses.
>> + * @e_pixel_format: specifies pixel stream format for main or sub display.
>> + * @e_burst_mode: selects Burst mode in Video mode.
>> + * in Non-burst mode, RGB data area is filled with RGB data and NULL
>> + * packets, according to input bandwidth of RGB interface.
>> + * In Burst mode, RGB data area is filled with RGB data only.
>> + * @e_no_data_lane: specifies data lane count to be used by Master.
>> + * @e_byte_clk: select byte clock source. (it must be DSIM_PLL_OUT_DIV8)
>> + * DSIM_EXT_CLK_DIV8 and DSIM_EXT_CLK_BYPASSS are not supported.
>> + * @pll_stable_time: specifies the PLL Timer for stability of the ganerated
>> + * clock(System clock cycle base)
>> + * if the timer value goes to 0x00000000, the clock stable bit of status
>> + * and interrupt register is set.
>> + * @esc_clk: specifies escape clock frequency for getting the escape clock
>> + * prescaler value.
>> + * @stop_holding_cnt: specifies the interval value between transmitting
>> + * read packet(or write "set_tear_on" command) and BTA request.
>> + * after transmitting read packet or write "set_tear_on" command,
>> + * BTA requests to D-PHY automatically. this counter value specifies
>> + * the interval between them.
>> + * @bta_timeout: specifies the timer for BTA.
>> + * this register specifies time out from BTA request to change
>> + * the direction with respect to Tx escape clock.
>> + * @rx_timeout: specifies the timer for LP Rx mode timeout.
>> + * this register specifies time out on how long RxValid deasserts,
>> + * after RxLpdt asserts with respect to Tx escape clock.
>> + * - RxValid specifies Rx data valid indicator.
>> + * - RxLpdt specifies an indicator that D-PHY is under RxLpdt mode.
>> + * - RxValid and RxLpdt specifies signal from D-PHY.
>> + */
>> +struct mipi_dsim_config {
>> + unsigned char auto_flush;
>> + unsigned char eot_disable;
>> +
>> + unsigned char auto_vertical_cnt;
>> + unsigned char hse;
>> + unsigned char hfp;
>> + unsigned char hbp;
>> + unsigned char hsa;
>> +
>> + enum mipi_dsim_interface_type e_interface;
>> + enum mipi_dsim_virtual_ch_no e_virtual_ch;
>> + enum mipi_dsim_pixel_format e_pixel_format;
>> + enum mipi_dsim_burst_mode_type e_burst_mode;
>> + enum mipi_dsim_no_of_data_lane e_no_data_lane;
>> + enum mipi_dsim_byte_clk_src e_byte_clk;
>> +
>> + /*
>> + * =====================>> + * | P | M | S | MHz |
>> + * -------------------------------------------
>> + * | 3 | 100 | 3 | 100 |
>> + * | 3 | 100 | 2 | 200 |
>> + * | 3 | 63 | 1 | 252 |
>> + * | 4 | 100 | 1 | 300 |
>> + * | 4 | 110 | 1 | 330 |
>> + * | 12 | 350 | 1 | 350 |
>> + * | 3 | 100 | 1 | 400 |
>> + * | 4 | 150 | 1 | 450 |
>> + * | 3 | 118 | 1 | 472 |
>> + * | 12 | 250 | 0 | 500 |
>> + * | 4 | 100 | 0 | 600 |
>> + * | 3 | 81 | 0 | 648 |
>> + * | 3 | 88 | 0 | 704 |
>> + * | 3 | 90 | 0 | 720 |
>> + * | 3 | 100 | 0 | 800 |
>> + * | 12 | 425 | 0 | 850 |
>> + * | 4 | 150 | 0 | 900 |
>> + * | 12 | 475 | 0 | 950 |
>> + * | 6 | 250 | 0 | 1000 |
>> + * -------------------------------------------
>> + */
>> + unsigned char p;
>> + unsigned short m;
>> + unsigned char s;
>> +
>> + unsigned int pll_stable_time;
>> + unsigned long esc_clk;
>> +
>> + unsigned short stop_holding_cnt;
>> + unsigned char bta_timeout;
>> + unsigned short rx_timeout;
>> +};
>> +
>> +/**
>> + * struct mipi_dsim_device - global interface for mipi-dsi driver.
>> + *
>> + * @dev: driver model representation of the device.
>> + * @id: unique device id.
>> + * @clock: pointer to MIPI-DSI clock of clock framework.
>> + * @irq: interrupt number to MIPI-DSI controller.
>> + * @reg_base: base address to memory mapped SRF of MIPI-DSI controller.
>> + * (virtual address)
>> + * @lock: the mutex protecting this data structure.
>> + * @dsim_info: infomation for configuring mipi-dsi controller.
>> + * @master_ops: callbacks to mipi-dsi operations.
>> + * @dsim_lcd_dev: pointer to activated ddi device.
>> + * (it would be registered by mipi-dsi driver.)
>> + * @dsim_lcd_drv: pointer to activated_ddi driver.
>> + * (it would be registered by mipi-dsi driver.)
>> + * @lcd_info: pointer to mipi_lcd_info structure.
>> + * @state: specifies status of MIPI-DSI controller.
>> + * the status could be RESET, INIT, STOP, HSCLKEN and ULPS.
>> + * @resume_complete: indicates whether resume operation is completed or not.
>> + * @data_lane: specifiec enabled data lane number.
>> + * this variable would be set by driver according to e_no_data_lane
>> + * automatically.
>> + * @e_clk_src: select byte clock source.
>> + * @pd: pointer to MIPI-DSI driver platform data.
>> + */
>> +struct mipi_dsim_device {
>> + struct device *dev;
>> + int id;
>> + struct resource *res;
>> + struct clk *clock;
>> + unsigned int irq;
>> + void __iomem *reg_base;
>> + struct mutex lock;
>> +
>> + struct mipi_dsim_config *dsim_config;
>> + struct mipi_dsim_master_ops *master_ops;
>> + struct mipi_dsim_lcd_device *dsim_lcd_dev;
>> + struct mipi_dsim_lcd_driver *dsim_lcd_drv;
>> +
>> + unsigned int state;
>> + unsigned int resume_complete;
>> + unsigned int data_lane;
>> + enum mipi_dsim_byte_clk_src e_clk_src;
>> +
>> + struct s5p_platform_mipi_dsim *pd;
>> +};
>> +
>> +/**
>> + * struct s5p_platform_mipi_dsim - interface to platform data
>> + * for mipi-dsi driver.
>> + *
>> + * @lcd_panel_name: specifies lcd panel name registered to mipi-dsi driver.
>> + * lcd panel driver searched would be actived.
>> + * @dsim_config: pointer of structure for configuring mipi-dsi controller.
>> + * @lcd_panel_info: pointer for lcd panel specific structure.
>> + * this structure specifies width, height, timing and polarity and so on.
>> + * @mipi_power: callback pointer for enabling or disabling mipi power.
>> + * @phy_enable: pointer to a callback controlling D-PHY enable/reset
>> + */
>> +struct s5p_platform_mipi_dsim {
>> + char lcd_panel_name[PANEL_NAME_SIZE];
>> +
>> + struct mipi_dsim_config *dsim_config;
>> + void *lcd_panel_info;
>> +
>> + int (*mipi_power)(struct platform_device *pdev, unsigned int enable);
>> + int (*phy_enable)(struct platform_device *pdev, bool on);
>> +};
>> +/**
>> + * struct mipi_dsim_master_ops - callbacks to mipi-dsi operations.
>> + *
>> + * @cmd_write: transfer command to lcd panel at LP mode.
>> + * @cmd_read: read command from rx register.
>> + * @get_dsim_frame_done: get the status that all screen data have been
>> + * transferred to mipi-dsi.
>> + * @clear_dsim_frame_done: clear frame done status.
>> + * @get_fb_frame_done: get frame done status of display controller.
>> + * @trigger: trigger display controller.
>> + * - this one would be used only in case of CPU mode.
>> + */
>> +
>> +struct mipi_dsim_master_ops {
>> + int (*cmd_write)(struct mipi_dsim_device *dsim, unsigned int data_id,
>> + unsigned int data0, unsigned int data1);
>> + int (*cmd_read)(struct mipi_dsim_device *dsim, unsigned int data_id,
>> + unsigned int data0, unsigned int data1);
>> + int (*get_dsim_frame_done)(struct mipi_dsim_device *dsim);
>> + int (*clear_dsim_frame_done)(struct mipi_dsim_device *dsim);
>> +
>> + int (*get_fb_frame_done)(struct fb_info *info);
>> + void (*trigger)(struct fb_info *info);
>> +};
>> +
>> +/**
>> + * device structure for mipi-dsi based lcd panel.
>> + *
>> + * @name: name of the device to use with this device, or an
>> + * alias for that name.
>> + * @dev: driver model representation of the device.
>> + * @id: id of device to be registered.
>> + * @bus_id: bus id for identifing connected bus
>> + * and this bus id should be same as id of mipi_dsim_device.
>> + * @irq: irq number for signaling when framebuffer transfer of
>> + * lcd panel module is completed.
>> + * this irq would be used only for MIPI-DSI based CPU mode lcd panel.
>> + * @master: pointer to mipi-dsi master device object.
>> + * @platform_data: lcd panel specific platform data.
>> + */
>> +struct mipi_dsim_lcd_device {
>> + char *name;
>> + struct device dev;
>> + int id;
>> + int bus_id;
>> + int irq;
>> +
>> + struct mipi_dsim_device *master;
>> + void *platform_data;
>> +};
>> +
>> +/**
>> + * driver structure for mipi-dsi based lcd panel.
>> + *
>> + * this structure should be registered by lcd panel driver.
>> + * mipi-dsi driver seeks lcd panel registered through name field
>> + * and calls these callback functions in appropriate time.
>> + *
>> + * @name: name of the driver to use with this device, or an
>> + * alias for that name.
>> + * @id: id of driver to be registered.
>> + * this id would be used for finding device object registered.
>> + */
>> +struct mipi_dsim_lcd_driver {
>> + char *name;
>> + int id;
>> +
>> + int (*probe)(struct mipi_dsim_lcd_device *dsim_dev);
>> + int (*remove)(struct mipi_dsim_lcd_device *dsim_dev);
>> + void (*shutdown)(struct mipi_dsim_lcd_device *dsim_dev);
>> + int (*suspend)(struct mipi_dsim_lcd_device *dsim_dev);
>> + int (*resume)(struct mipi_dsim_lcd_device *dsim_dev);
>> +};
>> +
>> +/**
>> + * register mipi_dsim_lcd_driver object defined by lcd panel driver
>> + * to mipi-dsi driver.
>> + */
>> +int s5p_mipi_dsi_register_lcd_driver(struct mipi_dsim_lcd_driver
>> + *lcd_drv);
>> +
>> +/**
>> + * register mipi_dsim_lcd_device to mipi-dsi master.
>> + */
>> +int s5p_mipi_dsi_register_lcd_device(struct mipi_dsim_lcd_device
>> + *lcd_dev);
>> +
>> +/**
>> + * enable regulators to MIPI-DSI power.
>> + */
>> +int s5p_mipi_dsi_dphy_power(struct mipi_dsim_device *dsim,
>> + unsigned int enable);
>> +
>> +/**
>> + * s5p_dsim_phy_enable - global MIPI-DSI receiver D-PHY control
>> + * @pdev: MIPI-DSIM platform device
>> + * @on: true to enable D-PHY and deassert its reset
>> + * false to disable D-PHY
>> + */
>> +int s5p_dsim_phy_enable(struct platform_device *pdev, bool on);
>> +
>> +#endif /* _DSIM_H */
>> diff --git a/arch/arm/plat-s5p/include/plat/regs-dsim.h b/arch/arm/plat-s5p/include/plat/regs-dsim.h
>> new file mode 100644
>> index 0000000..5f0e4fa
>> --- /dev/null
>> +++ b/arch/arm/plat-s5p/include/plat/regs-dsim.h
>> @@ -0,0 +1,143 @@
>> +/* linux/arch/arm/plat-s5p/include/plat/regs-dsim.h
>> + *
>> + * Register definition file for Samsung MIPI-DSIM driver
>> + *
>> + * Copyright (c) 2011 Samsung Electronics Co., Ltd
>> + *
>> + * InKi Dae <inki.dae@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.
>> +*/
>> +
>> +#ifndef _REGS_DSIM_H
>> +#define _REGS_DSIM_H
>> +
>> +#define S5P_DSIM_STATUS (0x0) /* Status register */
>> +#define S5P_DSIM_SWRST (0x4) /* Software reset register */
>> +#define S5P_DSIM_CLKCTRL (0x8) /* Clock control register */
>> +#define S5P_DSIM_TIMEOUT (0xc) /* Time out register */
>> +#define S5P_DSIM_CONFIG (0x10) /* Configuration register */
>> +#define S5P_DSIM_ESCMODE (0x14) /* Escape mode register */
>> +
>> +/* Main display image resolution register */
>> +#define S5P_DSIM_MDRESOL (0x18)
>> +#define S5P_DSIM_MVPORCH (0x1c) /* Main display Vporch register */
>> +#define S5P_DSIM_MHPORCH (0x20) /* Main display Hporch register */
>> +#define S5P_DSIM_MSYNC (0x24) /* Main display sync area register */
>> +
>> +/* Sub display image resolution register */
>> +#define S5P_DSIM_SDRESOL (0x28)
>> +#define S5P_DSIM_INTSRC (0x2c) /* Interrupt source register */
>> +#define S5P_DSIM_INTMSK (0x30) /* Interrupt mask register */
>> +#define S5P_DSIM_PKTHDR (0x34) /* Packet Header FIFO register */
>> +#define S5P_DSIM_PAYLOAD (0x38) /* Payload FIFO register */
>> +#define S5P_DSIM_RXFIFO (0x3c) /* Read FIFO register */
>> +#define S5P_DSIM_FIFOTHLD (0x40) /* FIFO threshold level register */
>> +#define S5P_DSIM_FIFOCTRL (0x44) /* FIFO status and control register */
>> +
>> +/* FIFO memory AC characteristic register */
>> +#define S5P_DSIM_PLLCTRL (0x4c) /* PLL control register */
>> +#define S5P_DSIM_PLLTMR (0x50) /* PLL timer register */
>> +#define S5P_DSIM_PHYACCHR (0x54) /* D-PHY AC characteristic register */
>> +#define S5P_DSIM_PHYACCHR1 (0x58) /* D-PHY AC characteristic register1 */
>> +
>> +/* DSIM_STATUS */
>> +#define DSIM_STOP_STATE_DAT(x) (((x) & 0xf) << 0)
>> +#define DSIM_STOP_STATE_CLK (1 << 8)
>> +#define DSIM_TX_READY_HS_CLK (1 << 10)
>> +
>> +/* DSIM_SWRST */
>> +#define DSIM_FUNCRST (1 << 16)
>> +#define DSIM_SWRST (1 << 0)
>> +
>> +/* S5P_DSIM_TIMEOUT */
>> +#define DSIM_LPDR_TOUT_SHIFT (0)
>> +#define DSIM_BTA_TOUT_SHIFT (16)
>> +
>> +/* S5P_DSIM_CLKCTRL */
>> +#define DSIM_LANE_ESC_CLKEN_SHIFT (19)
>> +#define DSIM_BYTE_CLKEN_SHIFT (24)
>> +#define DSIM_BYTE_CLK_SRC_SHIFT (25)
>> +#define DSIM_PLL_BYPASS_SHIFT (27)
>> +#define DSIM_ESC_CLKEN_SHIFT (28)
>> +#define DSIM_TX_REQUEST_HSCLK_SHIFT (31)
>> +#define DSIM_LANE_ESC_CLKEN(x) (((x) & 0x1f) << \
>> + DSIM_LANE_ESC_CLKEN_SHIFT)
>> +#define DSIM_BYTE_CLK_ENABLE (1 << DSIM_BYTE_CLKEN_SHIFT)
>> +#define DSIM_BYTE_CLK_DISABLE (0 << DSIM_BYTE_CLKEN_SHIFT)
>> +#define DSIM_PLL_BYPASS_EXTERNAL (1 << DSIM_PLL_BYPASS_SHIFT)
>> +#define DSIM_ESC_CLKEN_ENABLE (1 << DSIM_ESC_CLKEN_SHIFT)
>> +#define DSIM_ESC_CLKEN_DISABLE (0 << DSIM_ESC_CLKEN_SHIFT)
>> +
>> +/* S5P_DSIM_CONFIG */
>> +#define DSIM_NUM_OF_DATALANE_SHIFT (5)
>> +#define DSIM_HSA_MODE_SHIFT (20)
>> +#define DSIM_HBP_MODE_SHIFT (21)
>> +#define DSIM_HFP_MODE_SHIFT (22)
>> +#define DSIM_HSE_MODE_SHIFT (23)
>> +#define DSIM_AUTO_MODE_SHIFT (24)
>> +#define DSIM_LANE_ENx(x) (((x) & 0x1f) << 0)
>> +
>> +#define DSIM_NUM_OF_DATA_LANE(x) ((x) << DSIM_NUM_OF_DATALANE_SHIFT)
>> +
>> +/* S5P_DSIM_ESCMODE */
>> +#define DSIM_TX_LPDT_SHIFT (6)
>> +#define DSIM_CMD_LPDT_SHIFT (7)
>> +#define DSIM_TX_LPDT_LP (1 << DSIM_TX_LPDT_SHIFT)
>> +#define DSIM_CMD_LPDT_LP (1 << DSIM_CMD_LPDT_SHIFT)
>> +#define DSIM_STOP_STATE_CNT_SHIFT (21)
>> +#define DSIM_FORCE_STOP_STATE_SHIFT (20)
>> +
>> +/* S5P_DSIM_MDRESOL */
>> +#define DSIM_MAIN_STAND_BY (1 << 31)
>> +#define DSIM_MAIN_VRESOL(x) (((x) & 0x7ff) << 16)
>> +#define DSIM_MAIN_HRESOL(x) (((x) & 0X7ff) << 0)
>> +
>> +/* S5P_DSIM_MVPORCH */
>> +#define DSIM_CMD_ALLOW_SHIFT (28)
>> +#define DSIM_STABLE_VFP_SHIFT (16)
>> +#define DSIM_MAIN_VBP_SHIFT (0)
>> +#define DSIM_CMD_ALLOW_MASK (0xf << DSIM_CMD_ALLOW_SHIFT)
>> +#define DSIM_STABLE_VFP_MASK (0x7ff << DSIM_STABLE_VFP_SHIFT)
>> +#define DSIM_MAIN_VBP_MASK (0x7ff << DSIM_MAIN_VBP_SHIFT)
>> +
>> +/* S5P_DSIM_MHPORCH */
>> +#define DSIM_MAIN_HFP_SHIFT (16)
>> +#define DSIM_MAIN_HBP_SHIFT (0)
>> +#define DSIM_MAIN_HFP_MASK ((0xffff) << DSIM_MAIN_HFP_SHIFT)
>> +#define DSIM_MAIN_HBP_MASK ((0xffff) << DSIM_MAIN_HBP_SHIFT)
>> +
>> +/* S5P_DSIM_MSYNC */
>> +#define DSIM_MAIN_VSA_SHIFT (22)
>> +#define DSIM_MAIN_HSA_SHIFT (0)
>> +#define DSIM_MAIN_VSA_MASK ((0x3ff) << DSIM_MAIN_VSA_SHIFT)
>> +#define DSIM_MAIN_HSA_MASK ((0xffff) << DSIM_MAIN_HSA_SHIFT)
>> +
>> +/* S5P_DSIM_SDRESOL */
>> +#define DSIM_SUB_STANDY_SHIFT (31)
>> +#define DSIM_SUB_VRESOL_SHIFT (16)
>> +#define DSIM_SUB_HRESOL_SHIFT (0)
>> +#define DSIM_SUB_STANDY_MASK ((0x1) << DSIM_SUB_STANDY_SHIFT)
>> +#define DSIM_SUB_VRESOL_MASK ((0x7ff) << DSIM_SUB_VRESOL_SHIFT)
>> +#define DSIM_SUB_HRESOL_MASK ((0x7ff) << DSIM_SUB_HRESOL_SHIFT)
>> +
>> +/* S5P_DSIM_INTSRC */
>> +#define INTSRC_FRAME_DONE (1 << 24)
>> +#define INTSRC_PLL_STABLE (1 << 31)
>> +
>> +/* S5P_DSIM_INTMSK */
>> +#define INTMSK_FRAME_DONE (1 << 24)
>> +
>> +/* S5P_DSIM_FIFOCTRL */
>> +#define SFR_HEADER_EMPTY (1 << 22)
>> +
>> +/* S5P_DSIM_PHYACCHR */
>> +#define DSIM_AFC_CTL(x) (((x) & 0x7) << 5)
>> +
>> +/* S5P_DSIM_PLLCTRL */
>> +#define DSIM_PLL_EN_SHIFT (23)
>> +#define DSIM_FREQ_BAND_SHIFT (24)
>> +
>> +#endif /* _REGS_DSIM_H */
>> diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
>> index e6a8d8c..1e71a54 100644
>> --- a/drivers/video/Kconfig
>> +++ b/drivers/video/Kconfig
>> @@ -2044,6 +2044,13 @@ config FB_S3C2410_DEBUG
>> Turn on debugging messages. Note that you can set/unset at run time
>> through sysfs
>>
>> +config S5P_MIPI_DSI
>> + tristate "Samsung SoC MIPI-DSI support."
>> + depends on FB_S3C && (ARCH_S5PV210 || ARCH_EXYNOS4)
>> + default n
>> + ---help---
>> + This enables support for MIPI-DSI device.
>> +
>> config FB_NUC900
>> bool "NUC900 LCD framebuffer support"
>> depends on FB && ARCH_W90X900
>> diff --git a/drivers/video/Makefile b/drivers/video/Makefile
>> index 2ea44b6..ee5a1d5 100644
>> --- a/drivers/video/Makefile
>> +++ b/drivers/video/Makefile
>> @@ -119,6 +119,8 @@ obj-$(CONFIG_FB_SH7760) += sh7760fb.o
>> obj-$(CONFIG_FB_IMX) += imxfb.o
>> obj-$(CONFIG_FB_S3C) += s3c-fb.o
>> obj-$(CONFIG_FB_S3C2410) += s3c2410fb.o
>> +obj-$(CONFIG_S5P_MIPI_DSI) += s5p_mipi_dsi.o s5p_mipi_dsi_common.o \
>> + s5p_mipi_dsi_lowlevel.o
>> obj-$(CONFIG_FB_FSL_DIU) += fsl-diu-fb.o
>> obj-$(CONFIG_FB_COBALT) += cobalt_lcdfb.o
>> obj-$(CONFIG_FB_PNX4008_DUM) += pnx4008/
>> diff --git a/drivers/video/s5p_mipi_dsi.c b/drivers/video/s5p_mipi_dsi.c
>> new file mode 100644
>> index 0000000..50fc00e
>> --- /dev/null
>> +++ b/drivers/video/s5p_mipi_dsi.c
>> @@ -0,0 +1,481 @@
>> +/* linux/drivers/video/s5p_mipi_dsi.c
>> + *
>> + * Samsung SoC MIPI-DSIM driver.
>> + *
>> + * Copyright (c) 2011 Samsung Electronics Co., Ltd
>> + *
>> + * InKi Dae, <inki.dae@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/clk.h>
>> +#include <linux/mutex.h>
>> +#include <linux/wait.h>
>> +#include <linux/fs.h>
>> +#include <linux/mm.h>
>> +#include <linux/fb.h>
>> +#include <linux/ctype.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/io.h>
>> +#include <linux/irq.h>
>> +#include <linux/memory.h>
>> +#include <linux/delay.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/kthread.h>
>> +#include <linux/notifier.h>
>> +
>> +#include <plat/fb.h>
>> +#include <plat/mipi_dsim.h>
>> +
>> +#include "s5p_mipi_dsi_common.h"
>> +
>> +#define master_to_driver(a) (a->dsim_lcd_drv)
>> +#define master_to_device(a) (a->dsim_lcd_dev)
>> +
>> +struct mipi_dsim_ddi {
>> + int bus_id;
>> + struct list_head list;
>> + struct mipi_dsim_lcd_device *dsim_lcd_dev;
>> + struct mipi_dsim_lcd_driver *dsim_lcd_drv;
>> +};
>> +
>> +static LIST_HEAD(dsim_ddi_list);
>> +static LIST_HEAD(dsim_lcd_dev_list);
>> +
>> +static DEFINE_MUTEX(mipi_dsim_lock);
>> +
>> +static struct s5p_platform_mipi_dsim *to_dsim_plat(struct platform_device *pdev)
>> +{
>> + return (struct s5p_platform_mipi_dsim *)pdev->dev.platform_data;
>> +}
>> +
>> +static irqreturn_t s5p_mipi_dsi_interrupt_handler(int irq, void *dev_id)
>> +{
>> + return IRQ_HANDLED;
>> +}
>> +
>> +int s5p_mipi_dsi_register_lcd_device(struct mipi_dsim_lcd_device *lcd_dev)
>> +{
>> + struct mipi_dsim_ddi *dsim_ddi;
>> +
>> + if (!lcd_dev) {
>> + printk(KERN_ERR "mipi_dsim_lcd_device is NULL.\n");
>> + return -EFAULT;
>> + }
>> +
>> + if (!lcd_dev->name) {
>> + printk(KERN_ERR "dsim_lcd_device name is NULL.\n");
>> + return -EFAULT;
>> + }
>> +
>> + dsim_ddi = kzalloc(sizeof(struct mipi_dsim_ddi), GFP_KERNEL);
>> + if (!dsim_ddi) {
>> + printk(KERN_ERR "failed to allocate dsim_ddi object.\n");
>> + return -EFAULT;
>> + }
>> +
>> + dsim_ddi->dsim_lcd_dev = lcd_dev;
>> +
>> + mutex_lock(&mipi_dsim_lock);
>> + list_add_tail(&dsim_ddi->list, &dsim_ddi_list);
>> + mutex_unlock(&mipi_dsim_lock);
>> +
>> + return 0;
>> +}
>> +
>> +struct mipi_dsim_ddi
>> + *s5p_mipi_dsi_find_lcd_device(struct mipi_dsim_lcd_driver *lcd_drv)
>> +{
>> + struct mipi_dsim_ddi *dsim_ddi;
>> + struct mipi_dsim_lcd_device *lcd_dev;
>> +
>> + mutex_lock(&mipi_dsim_lock);
>> +
>> + list_for_each_entry(dsim_ddi, &dsim_ddi_list, list) {
>> + lcd_dev = dsim_ddi->dsim_lcd_dev;
>> + if (!lcd_dev)
>> + continue;
>> +
>> + if (lcd_drv->id >= 0) {
>> + if ((strcmp(lcd_drv->name, lcd_dev->name)) = 0 &&
>> + lcd_drv->id = lcd_dev->id) {
>> + /**
>> + * bus_id would be used to identify
>> + * connected bus.
>> + */
>> + dsim_ddi->bus_id = lcd_dev->bus_id;
>> + mutex_unlock(&mipi_dsim_lock);
>> +
>> + return dsim_ddi;
>> + }
>> + } else {
>> + if ((strcmp(lcd_drv->name, lcd_dev->name)) = 0) {
>> + /**
>> + * bus_id would be used to identify
>> + * connected bus.
>> + */
>> + dsim_ddi->bus_id = lcd_dev->bus_id;
>> + mutex_unlock(&mipi_dsim_lock);
>> +
>> + return dsim_ddi;
>> + }
>> + }
>> +
>> + kfree(dsim_ddi);
>> + list_del(&dsim_ddi_list);
>> + }
>> +
>> + mutex_unlock(&mipi_dsim_lock);
>> +
>> + return NULL;
>> +}
>> +
>> +int s5p_mipi_dsi_register_lcd_driver(struct mipi_dsim_lcd_driver *lcd_drv)
>> +{
>> + struct mipi_dsim_ddi *dsim_ddi;
>> +
>> + if (!lcd_drv) {
>> + printk(KERN_ERR "mipi_dsim_lcd_driver is NULL.\n");
>> + return -EFAULT;
>> + }
>> +
>> + if (!lcd_drv->name) {
>> + printk(KERN_ERR "dsim_lcd_driver name is NULL.\n");
>> + return -EFAULT;
>> + }
>> +
>> + dsim_ddi = s5p_mipi_dsi_find_lcd_device(lcd_drv);
>> + if (!dsim_ddi) {
>> + printk(KERN_ERR "mipi_dsim_ddi object not found.\n");
>> + return -EFAULT;
>> + }
>> +
>> + dsim_ddi->dsim_lcd_drv = lcd_drv;
>> +
>> + printk(KERN_INFO "registered panel driver(%s) to mipi-dsi driver.\n",
>> + lcd_drv->name);
>> +
>> + return 0;
>> +
>> +}
>> +
>> +struct mipi_dsim_ddi
>> + *s5p_mipi_dsi_bind_lcd_ddi(struct mipi_dsim_device *dsim,
>> + const char *name)
>> +{
>> + struct mipi_dsim_ddi *dsim_ddi;
>> + struct mipi_dsim_lcd_driver *lcd_drv;
>> + struct mipi_dsim_lcd_device *lcd_dev;
>> + int ret;
>> +
>> + mutex_lock(&dsim->lock);
>> +
>> + list_for_each_entry(dsim_ddi, &dsim_ddi_list, list) {
>> + lcd_drv = dsim_ddi->dsim_lcd_drv;
>> + lcd_dev = dsim_ddi->dsim_lcd_dev;
>> + if (!lcd_drv || !lcd_dev ||
>> + (dsim->id != dsim_ddi->bus_id))
>> + continue;
>> +
>> + dev_dbg(dsim->dev, "lcd_drv->id = %d, lcd_dev->id = %d\n",
>> + lcd_drv->id, lcd_dev->id);
>> + dev_dbg(dsim->dev, "lcd_dev->bus_id = %d, dsim->id = %d\n",
>> + lcd_dev->bus_id, dsim->id);
>> +
>> + if ((strcmp(lcd_drv->name, name) = 0)) {
>> + lcd_dev->master = dsim;
>> +
>> + lcd_dev->dev.parent = dsim->dev;
>> + dev_set_name(&lcd_dev->dev, "%s", lcd_drv->name);
>> +
>> + ret = device_register(&lcd_dev->dev);
>> + if (ret < 0) {
>> + dev_err(dsim->dev,
>> + "can't register %s, status %d\n",
>> + dev_name(&lcd_dev->dev), ret);
>> + mutex_unlock(&dsim->lock);
>> +
>> + return NULL;
>> + }
>> +
>> + dsim->dsim_lcd_dev = lcd_dev;
>> + dsim->dsim_lcd_drv = lcd_drv;
>> +
>> + mutex_unlock(&dsim->lock);
>> +
>> + return dsim_ddi;
>> + }
>> + }
>> +
>> + mutex_unlock(&dsim->lock);
>> +
>> + return NULL;
>> +}
>> +
>> +/* define MIPI-DSI Master operations. */
>> +static struct mipi_dsim_master_ops master_ops = {
>> + .cmd_write = s5p_mipi_dsi_wr_data,
>> + .get_dsim_frame_done = s5p_mipi_dsi_get_frame_done_status,
>> + .clear_dsim_frame_done = s5p_mipi_dsi_clear_frame_done,
>> +};
>> +
>> +static int s5p_mipi_dsi_probe(struct platform_device *pdev)
>> +{
>> + struct resource *res;
>> + struct mipi_dsim_device *dsim;
>> + struct mipi_dsim_config *dsim_config;
>> + struct s5p_platform_mipi_dsim *dsim_pd;
>> + struct mipi_dsim_ddi *dsim_ddi;
>> + int ret = -1;
>> +
>> + dsim = kzalloc(sizeof(struct mipi_dsim_device), GFP_KERNEL);
>> + if (!dsim) {
>> + dev_err(&pdev->dev, "failed to allocate dsim object.\n");
>> + return -EFAULT;
>> + }
>> +
>> + dsim->pd = to_dsim_plat(pdev);
>> + dsim->dev = &pdev->dev;
>> + dsim->id = pdev->id;
>> + dsim->resume_complete = 0;
>> +
>> + /* get s5p_platform_mipi_dsim. */
>> + dsim_pd = (struct s5p_platform_mipi_dsim *)dsim->pd;
>> + if (dsim_pd = NULL) {
>> + dev_err(&pdev->dev, "failed to get platform data for dsim.\n");
>> + return -EFAULT;
>> + }
>> + /* get mipi_dsim_config. */
>> + dsim_config = dsim_pd->dsim_config;
>> + if (dsim_config = NULL) {
>> + dev_err(&pdev->dev, "failed to get dsim config data.\n");
>> + return -EFAULT;
>> + }
>> +
>> + dsim->dsim_config = dsim_config;
>> + dsim->master_ops = &master_ops;
>> +
>> + dsim->clock = clk_get(&pdev->dev, "dsim");
>> + if (IS_ERR(dsim->clock)) {
>> + dev_err(&pdev->dev, "failed to get dsim clock source\n");
>> + goto err_clock_get;
>> + }
>> +
>> + clk_enable(dsim->clock);
>> +
>> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> + if (!res) {
>> + dev_err(&pdev->dev, "failed to get io memory region\n");
>> + ret = -EINVAL;
>> + goto err_platform_get;
>> + }
>> +
>> + res = request_mem_region(res->start, resource_size(res),
>> + dev_name(&pdev->dev));
>> + if (!res) {
>> + dev_err(&pdev->dev, "failed to request io memory region\n");
>> + ret = -EINVAL;
>> + goto err_mem_region;
>> + }
>> +
>> + dsim->res = res;
>> +
>> + dsim->reg_base = ioremap(res->start, resource_size(res));
>> + if (!dsim->reg_base) {
>> + dev_err(&pdev->dev, "failed to remap io region\n");
>> + ret = -EINVAL;
>> + goto err_mem_region;
>> + }
>> +
>> + /*
>> + * in case of MIPI Video mode,
>> + * frame done interrupt handler would be used.
>> + */
>> + if (dsim_config->e_interface = DSIM_VIDEO) {
>> + dsim->irq = platform_get_irq(pdev, 0);
>> + if (request_irq(dsim->irq, s5p_mipi_dsi_interrupt_handler,
>> + IRQF_DISABLED, "mipi-dsi", dsim)) {
>> + dev_err(&pdev->dev, "request_irq failed.\n");
>> + goto err_request_irq;
>> + }
>> + }
>> +
>> + mutex_init(&dsim->lock);
>> +
>> + if (dsim->pd->mipi_power)
>> + dsim->pd->mipi_power(pdev, 1);
>> + else {
>> + dev_err(&pdev->dev, "mipi_power is NULL.\n");
>> + goto err_request_irq;
>> + }
>> +
>> + /* bind lcd ddi matched with panel name. */
>> + dsim_ddi = s5p_mipi_dsi_bind_lcd_ddi(dsim, dsim_pd->lcd_panel_name);
>> + if (!dsim_ddi) {
>> + dev_err(&pdev->dev, "mipi_dsim_ddi object not found.\n");
>> + goto err_bind;
>> + }
>> +
>> + /* enable MIPI-DSI PHY. */
>> + if (dsim->pd->phy_enable)
>> + dsim->pd->phy_enable(pdev, true);
>> +
>> + s5p_mipi_dsi_init_dsim(dsim);
>> + s5p_mipi_dsi_init_link(dsim);
>> +
>> + s5p_mipi_dsi_set_hs_enable(dsim);
>> +
>> + /* set display timing. */
>> + s5p_mipi_dsi_set_display_mode(dsim, dsim->dsim_config);
>> +
>> + platform_set_drvdata(pdev, dsim);
>> +
>> + /* initialize mipi-dsi client(lcd panel). */
>> + if (dsim_ddi->dsim_lcd_drv && dsim_ddi->dsim_lcd_drv->probe)
>> + dsim_ddi->dsim_lcd_drv->probe(dsim_ddi->dsim_lcd_dev);
>> +
>> + dev_dbg(&pdev->dev, "mipi-dsi driver(%s mode) has been probed.\n",
>> + (dsim_config->e_interface = DSIM_COMMAND) ?
>> + "CPU" : "RGB");
>> +
>> + return 0;
>> +
>> +err_bind:
>> + dsim->pd->mipi_power(pdev, 0);
>> +
>> +err_request_irq:
>> + release_resource(dsim->res);
>> + kfree(dsim->res);
>> +
>> + iounmap((void __iomem *) dsim->reg_base);
>> +
>> +err_mem_region:
>> +err_platform_get:
>> + clk_disable(dsim->clock);
>> +
>> +err_clock_get:
>> + clk_put(dsim->clock);
>> + kfree(dsim);
>> +
>> + return ret;
>> +
>> +}
>> +
>> +static int __devexit s5p_mipi_dsi_remove(struct platform_device *pdev)
>> +{
>> + struct mipi_dsim_device *dsim = platform_get_drvdata(pdev);
>> + struct mipi_dsim_ddi *dsim_ddi = NULL;
>> +
>> + if (dsim->dsim_config->e_interface = DSIM_VIDEO)
>> + free_irq(dsim->irq, dsim);
>> +
>> + iounmap(dsim->reg_base);
>> +
>> + clk_disable(dsim->clock);
>> + clk_put(dsim->clock);
>> +
>> + release_resource(dsim->res);
>> + kfree(dsim->res);
>> +
>> + list_for_each_entry(dsim_ddi, &dsim_ddi_list, list) {
>> + if (dsim_ddi) {
>> + if (dsim->id = dsim_ddi->bus_id) {
>> + kfree(dsim_ddi);
>> + dsim_ddi = NULL;
>> + }
>> + }
>> + }
>> +
>> + kfree(dsim);
>> +
>> + return 0;
>> +}
>> +
>> +#ifdef CONFIG_PM
>> +static int s5p_mipi_dsi_suspend(struct platform_device *pdev,
>> + pm_message_t state)
>> +{
>> + struct mipi_dsim_device *dsim = platform_get_drvdata(pdev);
>> +
>> + dsim->resume_complete = 0;
>> +
>> + if (master_to_driver(dsim) && (master_to_driver(dsim))->suspend)
>> + (master_to_driver(dsim))->suspend(master_to_device(dsim));
>> +
>> + clk_disable(dsim->clock);
>> +
>> + if (dsim->pd->mipi_power)
>> + dsim->pd->mipi_power(pdev, 0);
>> +
>> + return 0;
>> +}
>> +
>> +static int s5p_mipi_dsi_resume(struct platform_device *pdev)
>> +{
>> + struct mipi_dsim_device *dsim = platform_get_drvdata(pdev);
>> +
>> + if (dsim->pd->mipi_power)
>> + dsim->pd->mipi_power(pdev, 1);
>> +
>> + clk_enable(dsim->clock);
>> +
>> + s5p_mipi_dsi_init_dsim(dsim);
>> + s5p_mipi_dsi_init_link(dsim);
>> +
>> + s5p_mipi_dsi_set_hs_enable(dsim);
>> +
>> + /* change cpu command transfer mode to hs. */
>> + s5p_mipi_dsi_set_data_transfer_mode(dsim, 0);
>> +
>> + if (master_to_driver(dsim) && (master_to_driver(dsim))->resume)
>> + (master_to_driver(dsim))->resume(master_to_device(dsim));
>> +
>> + s5p_mipi_dsi_set_display_mode(dsim, dsim->dsim_config);
>> +
>> + /* change lcdc data transfer mode to hs. */
>> + s5p_mipi_dsi_set_data_transfer_mode(dsim, 1);
>> +
>> + dsim->resume_complete = 1;
>> +
>> + return 0;
>> +}
>> +#else
>> +#define s5p_mipi_dsi_suspend NULL
>> +#define s5p_mipi_dsi_resume NULL
>> +#endif
>> +
>> +static struct platform_driver s5p_mipi_dsi_driver = {
>> + .probe = s5p_mipi_dsi_probe,
>> + .remove = __devexit_p(s5p_mipi_dsi_remove),
>> + .suspend = s5p_mipi_dsi_suspend,
>> + .resume = s5p_mipi_dsi_resume,
>> + .driver = {
>> + .name = "s5p-mipi-dsim",
>> + .owner = THIS_MODULE,
>> + },
>> +};
>> +
>> +static int s5p_mipi_dsi_register(void)
>> +{
>> + platform_driver_register(&s5p_mipi_dsi_driver);
>> +
>> + return 0;
>> +}
>> +
>> +static void s5p_mipi_dsi_unregister(void)
>> +{
>> + platform_driver_unregister(&s5p_mipi_dsi_driver);
>> +}
>> +
>> +module_init(s5p_mipi_dsi_register);
>> +module_exit(s5p_mipi_dsi_unregister);
>> +
>> +MODULE_AUTHOR("InKi Dae <inki.dae@samsung.com>");
>> +MODULE_DESCRIPTION("Samusung SoC MIPI-DSI driver");
>> +MODULE_LICENSE("GPL");
>> diff --git a/drivers/video/s5p_mipi_dsi_common.c b/drivers/video/s5p_mipi_dsi_common.c
>> new file mode 100644
>> index 0000000..51ee4ed
>> --- /dev/null
>> +++ b/drivers/video/s5p_mipi_dsi_common.c
>> @@ -0,0 +1,655 @@
>> +/* linux/drivers/video/s5p_mipi_dsi_common.c
>> + *
>> + * Samsung SoC MIPI-DSI common driver.
>> + *
>> + * Copyright (c) 2011 Samsung Electronics Co., Ltd
>> + *
>> + * InKi Dae, <inki.dae@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/fs.h>
>> +#include <linux/mm.h>
>> +#include <linux/fb.h>
>> +#include <linux/ctype.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/io.h>
>> +#include <linux/memory.h>
>> +#include <linux/delay.h>
>> +#include <linux/kthread.h>
>> +
>> +#include <video/mipi_display.h>
>> +
>> +#include <plat/fb.h>
>> +#include <plat/regs-dsim.h>
>> +
>> +#include <mach/map.h>
>> +#include <plat/mipi_dsim.h>
>> +#include <plat/regs-dsim.h>
>> +
>> +#include "s5p_mipi_dsi_lowlevel.h"
>> +
>> +#define MHZ (1000 * 1000)
>> +#define FIN_HZ (24 * MHZ)
>> +
>> +#define DFIN_PLL_MIN_HZ (6 * MHZ)
>> +#define DFIN_PLL_MAX_HZ (12 * MHZ)
>> +
>> +#define DFVCO_MIN_HZ (500 * MHZ)
>> +#define DFVCO_MAX_HZ (1000 * MHZ)
>> +
>> +#define TRY_GET_FIFO_TIMEOUT (5000 * 2)
>> +
>> +#define DSIM_ESCCLK_ON (0x0)
>> +#define DSIM_ESCCLK_OFF (0x1)
>> +
>> +/* MIPI-DSIM status types. */
>> +enum {
>> + DSIM_STATE_INIT, /* should be initialized. */
>> + DSIM_STATE_STOP, /* CPU and LCDC are LP mode. */
>> + DSIM_STATE_HSCLKEN, /* HS clock was enabled. */
>> + DSIM_STATE_ULPS
>> +};
>> +
>> +/* define DSI lane types. */
>> +enum {
>> + DSIM_LANE_CLOCK = (1 << 0),
>> + DSIM_LANE_DATA0 = (1 << 1),
>> + DSIM_LANE_DATA1 = (1 << 2),
>> + DSIM_LANE_DATA2 = (1 << 3),
>> + DSIM_LANE_DATA3 = (1 << 4)
>> +};
>> +
>> +static unsigned int dpll_table[15] = {
>> + 100, 120, 170, 220, 270,
>> + 320, 390, 450, 510, 560,
>> + 640, 690, 770, 870, 950 };
>> +
>> +static void s5p_mipi_dsi_long_data_wr(struct mipi_dsim_device *dsim,
>> + unsigned int data0, unsigned int data1)
>> +{
>> + unsigned int data_cnt = 0, payload = 0;
>> +
>> + /* in case that data count is more then 4 */
>> + for (data_cnt = 0; data_cnt < data1; data_cnt += 4) {
>> + /*
>> + * after sending 4bytes per one time,
>> + * send remainder data less then 4.
>> + */
>> + if ((data1 - data_cnt) < 4) {
>> + if ((data1 - data_cnt) = 3) {
>> + payload = *(u8 *)(data0 + data_cnt) |
>> + (*(u8 *)(data0 + (data_cnt + 1))) << 8 |
>> + (*(u8 *)(data0 + (data_cnt + 2))) << 16;
>> + dev_dbg(dsim->dev, "count = 3 payload = %x, %x %x %x\n",
>> + payload, *(u8 *)(data0 + data_cnt),
>> + *(u8 *)(data0 + (data_cnt + 1)),
>> + *(u8 *)(data0 + (data_cnt + 2)));
>> + } else if ((data1 - data_cnt) = 2) {
>> + payload = *(u8 *)(data0 + data_cnt) |
>> + (*(u8 *)(data0 + (data_cnt + 1))) << 8;
>> + dev_dbg(dsim->dev,
>> + "count = 2 payload = %x, %x %x\n", payload,
>> + *(u8 *)(data0 + data_cnt),
>> + *(u8 *)(data0 + (data_cnt + 1)));
>> + } else if ((data1 - data_cnt) = 1) {
>> + payload = *(u8 *)(data0 + data_cnt);
>> + }
>> +
>> + s5p_mipi_dsi_wr_tx_data(dsim, payload);
>> + /* send 4bytes per one time. */
>> + } else {
>> + payload = *(u8 *)(data0 + data_cnt) |
>> + (*(u8 *)(data0 + (data_cnt + 1))) << 8 |
>> + (*(u8 *)(data0 + (data_cnt + 2))) << 16 |
>> + (*(u8 *)(data0 + (data_cnt + 3))) << 24;
>> +
>> + dev_dbg(dsim->dev,
>> + "count = 4 payload = %x, %x %x %x %x\n",
>> + payload, *(u8 *)(data0 + data_cnt),
>> + *(u8 *)(data0 + (data_cnt + 1)),
>> + *(u8 *)(data0 + (data_cnt + 2)),
>> + *(u8 *)(data0 + (data_cnt + 3)));
>> +
>> + s5p_mipi_dsi_wr_tx_data(dsim, payload);
>> + }
>> + }
>> +}
>> +
>> +int s5p_mipi_dsi_wr_data(struct mipi_dsim_device *dsim, unsigned int data_id,
>> + unsigned int data0, unsigned int data1)
>> +{
>> + unsigned int timeout = TRY_GET_FIFO_TIMEOUT;
>> + unsigned long delay_val, udelay;
>> + unsigned int check_rx_ack = 0;
>> +
>> + if (dsim->state = DSIM_STATE_ULPS) {
>> + dev_err(dsim->dev, "state is ULPS.\n");
>> +
>> + return -EINVAL;
>> + }
>> +
>> + delay_val = MHZ / dsim->dsim_config->esc_clk;
>> + udelay = 10 * delay_val;
>> +
>> + mdelay(udelay);
>> +
>> + /* only if transfer mode is LPDT, wait SFR becomes empty. */
>> + if (dsim->state = DSIM_STATE_STOP) {
>> + while (!(s5p_mipi_dsi_get_fifo_state(dsim) &
>> + SFR_HEADER_EMPTY)) {
>> + if ((timeout--) > 0)
>> + mdelay(1);
>> + else {
>> + dev_err(dsim->dev,
>> + "SRF header fifo is not empty.\n");
>> + return -EINVAL;
>> + }
>> + }
>> + }
>> +
>> + switch (data_id) {
>> + /* short packet types of packet types for command. */
>> + case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM:
>> + case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM:
>> + case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM:
>> + case MIPI_DSI_DCS_SHORT_WRITE:
>> + case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
>> + case MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE:
>> + s5p_mipi_dsi_wr_tx_header(dsim, data_id, data0, data1);
>> + if (check_rx_ack)
>> + /* process response func should be implemented */
>> + return 0;
>> + else
>> + return -EINVAL;
>> +
>> + /* general command */
>> + case MIPI_DSI_COLOR_MODE_OFF:
>> + case MIPI_DSI_COLOR_MODE_ON:
>> + case MIPI_DSI_SHUTDOWN_PERIPHERAL:
>> + case MIPI_DSI_TURN_ON_PERIPHERAL:
>> + s5p_mipi_dsi_wr_tx_header(dsim, data_id, data0, data1);
>> + if (check_rx_ack)
>> + /* process response func should be implemented. */
>> + return 0;
>> + else
>> + return -EINVAL;
>> +
>> + /* packet types for video data */
>> + case MIPI_DSI_V_SYNC_START:
>> + case MIPI_DSI_V_SYNC_END:
>> + case MIPI_DSI_H_SYNC_START:
>> + case MIPI_DSI_H_SYNC_END:
>> + case MIPI_DSI_END_OF_TRANSMISSION:
>> + return 0;
>> +
>> + /* short and response packet types for command */
>> + case MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM:
>> + case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM:
>> + case MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM:
>> + case MIPI_DSI_DCS_READ:
>> + s5p_mipi_dsi_clear_all_interrupt(dsim);
>> + s5p_mipi_dsi_wr_tx_header(dsim, data_id, data0, data1);
>> + /* process response func should be implemented. */
>> + return 0;
>> +
>> + /* long packet type and null packet */
>> + case MIPI_DSI_NULL_PACKET:
>> + case MIPI_DSI_BLANKING_PACKET:
>> + return 0;
>> + case MIPI_DSI_GENERIC_LONG_WRITE:
>> + case MIPI_DSI_DCS_LONG_WRITE:
>> + {
>> + unsigned int size, data_cnt = 0, payload = 0;
>> +
>> + size = data1 * 4;
>> +
>> + /* if data count is less then 4, then send 3bytes data. */
>> + if (data1 < 4) {
>> + payload = *(u8 *)(data0) |
>> + *(u8 *)(data0 + 1) << 8 |
>> + *(u8 *)(data0 + 2) << 16;
>> +
>> + s5p_mipi_dsi_wr_tx_data(dsim, payload);
>> +
>> + dev_dbg(dsim->dev, "count = %d payload = %x,%x %x %x\n",
>> + data1, payload,
>> + *(u8 *)(data0 + data_cnt),
>> + *(u8 *)(data0 + (data_cnt + 1)),
>> + *(u8 *)(data0 + (data_cnt + 2)));
>> + /* in case that data count is more then 4 */
>> + } else
>> + s5p_mipi_dsi_long_data_wr(dsim, data0, data1);
>> +
>> + /* put data into header fifo */
>> + s5p_mipi_dsi_wr_tx_header(dsim, data_id, data1 & 0xff,
>> + (data1 & 0xff00) >> 8);
>> +
>> + }
>> + if (check_rx_ack)
>> + /* process response func should be implemented. */
>> + return 0;
>> + else
>> + return -EINVAL;
>> +
>> + /* packet typo for video data */
>> + case MIPI_DSI_PACKED_PIXEL_STREAM_16:
>> + case MIPI_DSI_PACKED_PIXEL_STREAM_18:
>> + case MIPI_DSI_PIXEL_STREAM_3BYTE_18:
>> + case MIPI_DSI_PACKED_PIXEL_STREAM_24:
>> + if (check_rx_ack)
>> + /* process response func should be implemented. */
>> + return 0;
>> + else
>> + return -EINVAL;
>> + default:
>> + dev_warn(dsim->dev,
>> + "data id %x is not supported current DSI spec.\n",
>> + data_id);
>> +
>> + return -EINVAL;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +int s5p_mipi_dsi_pll_on(struct mipi_dsim_device *dsim, unsigned int enable)
>> +{
>> + int sw_timeout;
>> +
>> + if (enable) {
>> + sw_timeout = 1000;
>> +
>> + s5p_mipi_dsi_clear_interrupt(dsim);
>> + s5p_mipi_dsi_enable_pll(dsim, 1);
>> + while (1) {
>> + sw_timeout--;
>> + if (s5p_mipi_dsi_is_pll_stable(dsim))
>> + return 0;
>> + if (sw_timeout = 0)
>> + return -EINVAL;
>> + }
>> + } else
>> + s5p_mipi_dsi_enable_pll(dsim, 0);
>> +
>> + return 0;
>> +}
>> +
>> +unsigned long s5p_mipi_dsi_change_pll(struct mipi_dsim_device *dsim,
>> + unsigned int pre_divider, unsigned int main_divider,
>> + unsigned int scaler)
>> +{
>> + unsigned long dfin_pll, dfvco, dpll_out;
>> + unsigned int i, freq_band = 0xf;
>> +
>> + dfin_pll = (FIN_HZ / pre_divider);
>> +
>> + /******************************************************
>> + * Serial Clock(=ByteClk X 8) FreqBand[3:0] *
>> + ******************************************************
>> + * ~ 99.99 MHz 0000
>> + * 100 ~ 119.99 MHz 0001
>> + * 120 ~ 159.99 MHz 0010
>> + * 160 ~ 199.99 MHz 0011
>> + * 200 ~ 239.99 MHz 0100
>> + * 140 ~ 319.99 MHz 0101
>> + * 320 ~ 389.99 MHz 0110
>> + * 390 ~ 449.99 MHz 0111
>> + * 450 ~ 509.99 MHz 1000
>> + * 510 ~ 559.99 MHz 1001
>> + * 560 ~ 639.99 MHz 1010
>> + * 640 ~ 689.99 MHz 1011
>> + * 690 ~ 769.99 MHz 1100
>> + * 770 ~ 869.99 MHz 1101
>> + * 870 ~ 949.99 MHz 1110
>> + * 950 ~ 1000 MHz 1111
>> + ******************************************************/
>> + if (dfin_pll < DFIN_PLL_MIN_HZ || dfin_pll > DFIN_PLL_MAX_HZ) {
>> + dev_warn(dsim->dev, "fin_pll range should be 6MHz ~ 12MHz\n");
>> + s5p_mipi_dsi_enable_afc(dsim, 0, 0);
>> + } else {
>> + if (dfin_pll < 7 * MHZ)
>> + s5p_mipi_dsi_enable_afc(dsim, 1, 0x1);
>> + else if (dfin_pll < 8 * MHZ)
>> + s5p_mipi_dsi_enable_afc(dsim, 1, 0x0);
>> + else if (dfin_pll < 9 * MHZ)
>> + s5p_mipi_dsi_enable_afc(dsim, 1, 0x3);
>> + else if (dfin_pll < 10 * MHZ)
>> + s5p_mipi_dsi_enable_afc(dsim, 1, 0x2);
>> + else if (dfin_pll < 11 * MHZ)
>> + s5p_mipi_dsi_enable_afc(dsim, 1, 0x5);
>> + else
>> + s5p_mipi_dsi_enable_afc(dsim, 1, 0x4);
>> + }
>> +
>> + dfvco = dfin_pll * main_divider;
>> + dev_dbg(dsim->dev, "dfvco = %lu, dfin_pll = %lu, main_divider = %d\n",
>> + dfvco, dfin_pll, main_divider);
>> + if (dfvco < DFVCO_MIN_HZ || dfvco > DFVCO_MAX_HZ)
>> + dev_warn(dsim->dev, "fvco range should be 500MHz ~ 1000MHz\n");
>> +
>> + dpll_out = dfvco / (1 << scaler);
>> + dev_dbg(dsim->dev, "dpll_out = %lu, dfvco = %lu, scaler = %d\n",
>> + dpll_out, dfvco, scaler);
>> +
>> + for (i = 0; i < ARRAY_SIZE(dpll_table); i++) {
>> + if (dpll_out < dpll_table[i] * MHZ) {
>> + freq_band = i;
>> + break;
>> + }
>> + }
>> +
>> + dev_dbg(dsim->dev, "freq_band = %d\n", freq_band);
>> +
>> + s5p_mipi_dsi_pll_freq(dsim, pre_divider, main_divider, scaler);
>> +
>> + s5p_mipi_dsi_hs_zero_ctrl(dsim, 0);
>> + s5p_mipi_dsi_prep_ctrl(dsim, 0);
>> +
>> + /* Freq Band */
>> + s5p_mipi_dsi_pll_freq_band(dsim, freq_band);
>> +
>> + /* Stable time */
>> + s5p_mipi_dsi_pll_stable_time(dsim, dsim->dsim_config->pll_stable_time);
>> +
>> + /* Enable PLL */
>> + dev_dbg(dsim->dev, "FOUT of mipi dphy pll is %luMHz\n",
>> + (dpll_out / MHZ));
>> +
>> + return dpll_out;
>> +}
>> +
>> +int s5p_mipi_dsi_set_clock(struct mipi_dsim_device *dsim,
>> + unsigned int byte_clk_sel, unsigned int enable)
>> +{
>> + unsigned int esc_div;
>> + unsigned long esc_clk_error_rate;
>> + unsigned long hs_clk = 0, byte_clk = 0, escape_clk = 0;
>> +
>> + if (enable) {
>> + dsim->e_clk_src = byte_clk_sel;
>> +
>> + /* Escape mode clock and byte clock source */
>> + s5p_mipi_dsi_set_byte_clock_src(dsim, byte_clk_sel);
>> +
>> + /* DPHY, DSIM Link : D-PHY clock out */
>> + if (byte_clk_sel = DSIM_PLL_OUT_DIV8) {
>> + hs_clk = s5p_mipi_dsi_change_pll(dsim,
>> + dsim->dsim_config->p, dsim->dsim_config->m,
>> + dsim->dsim_config->s);
>> + if (hs_clk = 0) {
>> + dev_err(dsim->dev,
>> + "failed to get hs clock.\n");
>> + return -EINVAL;
>> + }
>> +
>> + byte_clk = hs_clk / 8;
>> + s5p_mipi_dsi_enable_pll_bypass(dsim, 0);
>> + s5p_mipi_dsi_pll_on(dsim, 1);
>> + /* DPHY : D-PHY clock out, DSIM link : external clock out */
>> + } else if (byte_clk_sel = DSIM_EXT_CLK_DIV8)
>> + dev_warn(dsim->dev,
>> + "this project is not support \
>> + external clock source for MIPI DSIM\n");
>> + else if (byte_clk_sel = DSIM_EXT_CLK_BYPASS)
>> + dev_warn(dsim->dev,
>> + "this project is not support \
>> + external clock source for MIPI DSIM\n");
>> +
>> + /* escape clock divider */
>> + esc_div = byte_clk / (dsim->dsim_config->esc_clk);
>> + dev_dbg(dsim->dev,
>> + "esc_div = %d, byte_clk = %lu, esc_clk = %lu\n",
>> + esc_div, byte_clk, dsim->dsim_config->esc_clk);
>> + if ((byte_clk / esc_div) >= (20 * MHZ) ||
>> + (byte_clk / esc_div) >
>> + dsim->dsim_config->esc_clk)
>> + esc_div += 1;
>> +
>> + escape_clk = byte_clk / esc_div;
>> + dev_dbg(dsim->dev,
>> + "escape_clk = %lu, byte_clk = %lu, esc_div = %d\n",
>> + escape_clk, byte_clk, esc_div);
>> +
>> + /* enable escape clock. */
>> + s5p_mipi_dsi_enable_byte_clock(dsim, DSIM_ESCCLK_ON);
>> +
>> + /* enable byte clk and escape clock */
>> + s5p_mipi_dsi_set_esc_clk_prs(dsim, 1, esc_div);
>> + /* escape clock on lane */
>> + s5p_mipi_dsi_enable_esc_clk_on_lane(dsim,
>> + (DSIM_LANE_CLOCK | dsim->data_lane), 1);
>> +
>> + dev_dbg(dsim->dev, "byte clock is %luMHz\n",
>> + (byte_clk / MHZ));
>> + dev_dbg(dsim->dev, "escape clock that user's need is %lu\n",
>> + (dsim->dsim_config->esc_clk / MHZ));
>> + dev_dbg(dsim->dev, "escape clock divider is %x\n", esc_div);
>> + dev_dbg(dsim->dev, "escape clock is %luMHz\n",
>> + ((byte_clk / esc_div) / MHZ));
>> +
>> + if ((byte_clk / esc_div) > escape_clk) {
>> + esc_clk_error_rate = escape_clk /
>> + (byte_clk / esc_div);
>> + dev_warn(dsim->dev, "error rate is %lu over.\n",
>> + (esc_clk_error_rate / 100));
>> + } else if ((byte_clk / esc_div) < (escape_clk)) {
>> + esc_clk_error_rate = (byte_clk / esc_div) /
>> + escape_clk;
>> + dev_warn(dsim->dev, "error rate is %lu under.\n",
>> + (esc_clk_error_rate / 100));
>> + }
>> + } else {
>> + s5p_mipi_dsi_enable_esc_clk_on_lane(dsim,
>> + (DSIM_LANE_CLOCK | dsim->data_lane), 0);
>> + s5p_mipi_dsi_set_esc_clk_prs(dsim, 0, 0);
>> +
>> + /* disable escape clock. */
>> + s5p_mipi_dsi_enable_byte_clock(dsim, DSIM_ESCCLK_OFF);
>> +
>> + if (byte_clk_sel = DSIM_PLL_OUT_DIV8)
>> + s5p_mipi_dsi_pll_on(dsim, 0);
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +int s5p_mipi_dsi_init_dsim(struct mipi_dsim_device *dsim)
>> +{
>> + dsim->state = DSIM_STATE_INIT;
>> +
>> + switch (dsim->dsim_config->e_no_data_lane) {
>> + case DSIM_DATA_LANE_1:
>> + dsim->data_lane = DSIM_LANE_DATA0;
>> + break;
>> + case DSIM_DATA_LANE_2:
>> + dsim->data_lane = DSIM_LANE_DATA0 | DSIM_LANE_DATA1;
>> + break;
>> + case DSIM_DATA_LANE_3:
>> + dsim->data_lane = DSIM_LANE_DATA0 | DSIM_LANE_DATA1 |
>> + DSIM_LANE_DATA2;
>> + break;
>> + case DSIM_DATA_LANE_4:
>> + dsim->data_lane = DSIM_LANE_DATA0 | DSIM_LANE_DATA1 |
>> + DSIM_LANE_DATA2 | DSIM_LANE_DATA3;
>> + break;
>> + default:
>> + dev_info(dsim->dev, "data lane is invalid.\n");
>> + return -EINVAL;
>> + };
>> +
>> + s5p_mipi_dsi_sw_reset(dsim);
>> + s5p_mipi_dsi_dp_dn_swap(dsim, 0);
>> +
>> + return 0;
>> +}
>> +
>> +int s5p_mipi_dsi_enable_frame_done_int(struct mipi_dsim_device *dsim,
>> + unsigned int enable)
>> +{
>> + /* enable only frame done interrupt */
>> + s5p_mipi_dsi_set_interrupt_mask(dsim, INTMSK_FRAME_DONE, enable);
>> +
>> + return 0;
>> +}
>> +
>> +int s5p_mipi_dsi_set_display_mode(struct mipi_dsim_device *dsim,
>> + struct mipi_dsim_config *dsim_config)
>> +{
>> + struct s5p_platform_mipi_dsim *dsim_pd;
>> + struct fb_videomode *lcd_video = NULL;
>> +
>> + dsim_pd = (struct s5p_platform_mipi_dsim *)dsim->pd;
>> + lcd_video = (struct fb_videomode *)dsim_pd->lcd_panel_info;
>> +
>> + /* in case of VIDEO MODE (RGB INTERFACE), it sets polarities. */
>> + if (dsim->dsim_config->e_interface = (u32) DSIM_VIDEO) {
>> + if (dsim->dsim_config->auto_vertical_cnt = 0) {
>> + s5p_mipi_dsi_set_main_disp_vporch(dsim,
>> + lcd_video->upper_margin,
>> + lcd_video->lower_margin, 0);
>> + s5p_mipi_dsi_set_main_disp_hporch(dsim,
>> + lcd_video->left_margin,
>> + lcd_video->right_margin);
>> + s5p_mipi_dsi_set_main_disp_sync_area(dsim,
>> + lcd_video->vsync_len,
>> + lcd_video->hsync_len);
>> + }
>> + }
>> +
>> + s5p_mipi_dsi_set_main_disp_resol(dsim, lcd_video->xres,
>> + lcd_video->yres);
>> +
>> + s5p_mipi_dsi_display_config(dsim, dsim->dsim_config);
>> +
>> + dev_dbg(dsim->dev, "lcd panel => width = %d, height = %d\n",
>> + lcd_video->xres, lcd_video->yres);
>> +
>> + return 0;
>> +}
>> +
>> +int s5p_mipi_dsi_init_link(struct mipi_dsim_device *dsim)
>> +{
>> + unsigned int time_out = 100;
>> +
>> + switch (dsim->state) {
>> + case DSIM_STATE_INIT:
>> + s5p_mipi_dsi_sw_reset(dsim);
>> +
>> + s5p_mipi_dsi_init_fifo_pointer(dsim, 0x1f);
>> +
>> + /* dsi configuration */
>> + s5p_mipi_dsi_init_config(dsim);
>> + s5p_mipi_dsi_enable_lane(dsim, DSIM_LANE_CLOCK, 1);
>> + s5p_mipi_dsi_enable_lane(dsim, dsim->data_lane, 1);
>> +
>> + /* set clock configuration */
>> + s5p_mipi_dsi_set_clock(dsim, dsim->dsim_config->e_byte_clk, 1);
>> +
>> + /* check clock and data lane state are stop state */
>> + while (!(s5p_mipi_dsi_is_lane_state(dsim))) {
>> + time_out--;
>> + if (time_out = 0) {
>> + dev_err(dsim->dev,
>> + "DSI Master is not stop state.\n");
>> + dev_err(dsim->dev,
>> + "Check initialization process\n");
>> +
>> + return -EINVAL;
>> + }
>> + }
>> +
>> + if (time_out != 0) {
>> + dev_info(dsim->dev,
>> + "DSI Master driver has been completed.\n");
>> + dev_info(dsim->dev, "DSI Master state is stop state\n");
>> + }
>> +
>> + dsim->state = DSIM_STATE_STOP;
>> +
>> + /* BTA sequence counters */
>> + s5p_mipi_dsi_set_stop_state_counter(dsim,
>> + dsim->dsim_config->stop_holding_cnt);
>> + s5p_mipi_dsi_set_bta_timeout(dsim,
>> + dsim->dsim_config->bta_timeout);
>> + s5p_mipi_dsi_set_lpdr_timeout(dsim,
>> + dsim->dsim_config->rx_timeout);
>> +
>> + return 0;
>> + default:
>> + dev_info(dsim->dev, "DSI Master is already init.\n");
>> + return 0;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +int s5p_mipi_dsi_set_hs_enable(struct mipi_dsim_device *dsim)
>> +{
>> + if (dsim->state = DSIM_STATE_STOP) {
>> + if (dsim->e_clk_src != DSIM_EXT_CLK_BYPASS) {
>> + dsim->state = DSIM_STATE_HSCLKEN;
>> +
>> + /* set LCDC and CPU transfer mode to HS. */
>> + s5p_mipi_dsi_set_lcdc_transfer_mode(dsim, 0);
>> + s5p_mipi_dsi_set_cpu_transfer_mode(dsim, 0);
>> +
>> + s5p_mipi_dsi_enable_hs_clock(dsim, 1);
>> +
>> + return 0;
>> + } else
>> + dev_warn(dsim->dev,
>> + "clock source is external bypass.\n");
>> + } else
>> + dev_warn(dsim->dev, "DSIM is not stop state.\n");
>> +
>> + return 0;
>> +}
>> +
>> +int s5p_mipi_dsi_set_data_transfer_mode(struct mipi_dsim_device *dsim,
>> + unsigned int mode)
>> +{
>> + if (mode) {
>> + if (dsim->state != DSIM_STATE_HSCLKEN) {
>> + dev_err(dsim->dev, "HS Clock lane is not enabled.\n");
>> + return -EINVAL;
>> + }
>> +
>> + s5p_mipi_dsi_set_lcdc_transfer_mode(dsim, 0);
>> + } else {
>> + if (dsim->state = DSIM_STATE_INIT || dsim->state =
>> + DSIM_STATE_ULPS) {
>> + dev_err(dsim->dev,
>> + "DSI Master is not STOP or HSDT state.\n");
>> + return -EINVAL;
>> + }
>> +
>> + s5p_mipi_dsi_set_cpu_transfer_mode(dsim, 0);
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +int s5p_mipi_dsi_get_frame_done_status(struct mipi_dsim_device *dsim)
>> +{
>> + return _s5p_mipi_dsi_get_frame_done_status(dsim);
>> +}
>> +
>> +int s5p_mipi_dsi_clear_frame_done(struct mipi_dsim_device *dsim)
>> +{
>> + _s5p_mipi_dsi_clear_frame_done(dsim);
>> +
>> + return 0;
>> +}
>> +
>> +MODULE_AUTHOR("InKi Dae <inki.dae@samsung.com>");
>> +MODULE_DESCRIPTION("Samusung MIPI-DSIM common driver");
>> +MODULE_LICENSE("GPL");
>> diff --git a/drivers/video/s5p_mipi_dsi_common.h b/drivers/video/s5p_mipi_dsi_common.h
>> new file mode 100644
>> index 0000000..5ade1d6
>> --- /dev/null
>> +++ b/drivers/video/s5p_mipi_dsi_common.h
>> @@ -0,0 +1,39 @@
>> +/* linux/drivers/video/s5p_mipi_dsi_common.h
>> + *
>> + * Header file for Samsung SoC MIPI-DSI common driver.
>> + *
>> + * Copyright (c) 2011 Samsung Electronics Co., Ltd
>> + *
>> + * InKi Dae <inki.dae@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.
>> +*/
>> +
>> +#ifndef _S5P_MIPI_DSI_COMMON_H
>> +#define _S5P_MIPI_DSI_COMMON_H
>> +
>> +int s5p_mipi_dsi_wr_data(struct mipi_dsim_device *dsim, unsigned int data_id,
>> + unsigned int data0, unsigned int data1);
>> +int s5p_mipi_dsi_pll_on(struct mipi_dsim_device *dsim, unsigned int enable);
>> +unsigned long s5p_mipi_dsi_change_pll(struct mipi_dsim_device *dsim,
>> + unsigned int pre_divider, unsigned int main_divider,
>> + unsigned int scaler);
>> +int s5p_mipi_dsi_set_clock(struct mipi_dsim_device *dsim,
>> + unsigned int byte_clk_sel, unsigned int enable);
>> +int s5p_mipi_dsi_init_dsim(struct mipi_dsim_device *dsim);
>> +int s5p_mipi_dsi_set_display_mode(struct mipi_dsim_device *dsim,
>> + struct mipi_dsim_config *dsim_info);
>> +int s5p_mipi_dsi_init_link(struct mipi_dsim_device *dsim);
>> +int s5p_mipi_dsi_set_hs_enable(struct mipi_dsim_device *dsim);
>> +int s5p_mipi_dsi_set_data_transfer_mode(struct mipi_dsim_device *dsim,
>> + unsigned int mode);
>> +int s5p_mipi_dsi_enable_frame_done_int(struct mipi_dsim_device *dsim,
>> + unsigned int enable);
>> +int s5p_mipi_dsi_get_frame_done_status(struct mipi_dsim_device *dsim);
>> +int s5p_mipi_dsi_clear_frame_done(struct mipi_dsim_device *dsim);
>> +
>> +extern struct fb_info *registered_fb[FB_MAX] __read_mostly;
>> +
>> +#endif /* _S5P_MIPI_DSI_COMMON_H */
>> diff --git a/drivers/video/s5p_mipi_dsi_lowlevel.c b/drivers/video/s5p_mipi_dsi_lowlevel.c
>> new file mode 100644
>> index 0000000..86d2881
>> --- /dev/null
>> +++ b/drivers/video/s5p_mipi_dsi_lowlevel.c
>> @@ -0,0 +1,558 @@
>> +/* linux/drivers/video/s5p_mipi_dsi_lowlevel.c
>> + *
>> + * Samsung SoC MIPI-DSI lowlevel driver.
>> + *
>> + * Copyright (c) 2011 Samsung Electronics Co., Ltd
>> + *
>> + * InKi Dae, <inki.dae@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/delay.h>
>> +#include <linux/fs.h>
>> +#include <linux/mm.h>
>> +#include <linux/ctype.h>
>> +#include <linux/io.h>
>> +
>> +#include <mach/map.h>
>> +
>> +#include <plat/mipi_dsim.h>
>> +#include <plat/regs-dsim.h>
>> +
>> +void s5p_mipi_dsi_func_reset(struct mipi_dsim_device *dsim)
>> +{
>> + unsigned int reg;
>> +
>> + reg = readl(dsim->reg_base + S5P_DSIM_SWRST);
>> +
>> + reg |= DSIM_FUNCRST;
>> +
>> + writel(reg, dsim->reg_base + S5P_DSIM_SWRST);
>> +}
>> +
>> +void s5p_mipi_dsi_sw_reset(struct mipi_dsim_device *dsim)
>> +{
>> + unsigned int reg;
>> +
>> + reg = readl(dsim->reg_base + S5P_DSIM_SWRST);
>> +
>> + reg |= DSIM_SWRST;
>> +
>> + writel(reg, dsim->reg_base + S5P_DSIM_SWRST);
>> +}
>> +
>> +void s5p_mipi_dsi_set_interrupt_mask(struct mipi_dsim_device *dsim,
>> + unsigned int mode, unsigned int mask)
>> +{
>> + unsigned int reg = readl(dsim->reg_base + S5P_DSIM_INTMSK);
>> +
>> + if (mask)
>> + reg |= mode;
>> + else
>> + reg &= ~mode;
>> +
>> + writel(reg, dsim->reg_base + S5P_DSIM_INTMSK);
>> +}
>> +
>> +void s5p_mipi_dsi_init_fifo_pointer(struct mipi_dsim_device *dsim,
>> + unsigned int cfg)
>> +{
>> + unsigned int reg;
>> +
>> + reg = readl(dsim->reg_base + S5P_DSIM_FIFOCTRL);
>> +
>> + writel(reg & ~(cfg), dsim->reg_base + S5P_DSIM_FIFOCTRL);
>> + mdelay(10);
>> + reg |= cfg;
>> +
>> + writel(reg, dsim->reg_base + S5P_DSIM_FIFOCTRL);
>> +}
>> +
>> +/*
>> + * this function set PLL P, M and S value in D-PHY
>> + */
>> +void s5p_mipi_dsi_set_phy_tunning(struct mipi_dsim_device *dsim,
>> + unsigned int value)
>> +{
>> + writel(DSIM_AFC_CTL(value), dsim->reg_base + S5P_DSIM_PHYACCHR);
>> +}
>> +
>> +void s5p_mipi_dsi_set_main_disp_resol(struct mipi_dsim_device *dsim,
>> + unsigned int width_resol, unsigned int height_resol)
>> +{
>> + unsigned int reg;
>> +
>> + /* standby should be set after configuration so set to not ready*/
>> + reg = (readl(dsim->reg_base + S5P_DSIM_MDRESOL)) &
>> + ~(DSIM_MAIN_STAND_BY);
>> + writel(reg, dsim->reg_base + S5P_DSIM_MDRESOL);
>> +
>> + reg &= ~(0x7ff << 16) & ~(0x7ff << 0);
>> + reg |= DSIM_MAIN_VRESOL(height_resol) | DSIM_MAIN_HRESOL(width_resol);
>> +
>> + reg |= DSIM_MAIN_STAND_BY;
>> + writel(reg, dsim->reg_base + S5P_DSIM_MDRESOL);
>> +}
>> +
>> +void s5p_mipi_dsi_set_main_disp_vporch(struct mipi_dsim_device *dsim,
>> + unsigned int cmd_allow, unsigned int vfront, unsigned int vback)
>> +{
>> + unsigned int reg;
>> +
>> + reg = (readl(dsim->reg_base + S5P_DSIM_MVPORCH)) &
>> + ~(DSIM_CMD_ALLOW_MASK) & ~(DSIM_STABLE_VFP_MASK) &
>> + ~(DSIM_MAIN_VBP_MASK);
>> +
>> + reg |= ((cmd_allow & 0xf) << DSIM_CMD_ALLOW_SHIFT) |
>> + ((vfront & 0x7ff) << DSIM_STABLE_VFP_SHIFT) |
>> + ((vback & 0x7ff) << DSIM_MAIN_VBP_SHIFT);
>> +
>> + writel(reg, dsim->reg_base + S5P_DSIM_MVPORCH);
>> +}
>> +
>> +void s5p_mipi_dsi_set_main_disp_hporch(struct mipi_dsim_device *dsim,
>> + unsigned int front, unsigned int back)
>> +{
>> + unsigned int reg;
>> +
>> + reg = (readl(dsim->reg_base + S5P_DSIM_MHPORCH)) &
>> + ~(DSIM_MAIN_HFP_MASK) & ~(DSIM_MAIN_HBP_MASK);
>> +
>> + reg |= (front << DSIM_MAIN_HFP_SHIFT) | (back << DSIM_MAIN_HBP_SHIFT);
>> +
>> + writel(reg, dsim->reg_base + S5P_DSIM_MHPORCH);
>> +}
>> +
>> +void s5p_mipi_dsi_set_main_disp_sync_area(struct mipi_dsim_device *dsim,
>> + unsigned int vert, unsigned int hori)
>> +{
>> + unsigned int reg;
>> +
>> + reg = (readl(dsim->reg_base + S5P_DSIM_MSYNC)) &
>> + ~(DSIM_MAIN_VSA_MASK) & ~(DSIM_MAIN_HSA_MASK);
>> +
>> + reg |= ((vert & 0x3ff) << DSIM_MAIN_VSA_SHIFT) |
>> + (hori << DSIM_MAIN_HSA_SHIFT);
>> +
>> + writel(reg, dsim->reg_base + S5P_DSIM_MSYNC);
>> +}
>> +
>> +void s5p_mipi_dsi_set_sub_disp_resol(struct mipi_dsim_device *dsim,
>> + unsigned int vert, unsigned int hori)
>> +{
>> + unsigned int reg;
>> +
>> + reg = (readl(dsim->reg_base + S5P_DSIM_SDRESOL)) &
>> + ~(DSIM_SUB_STANDY_MASK);
>> +
>> + writel(reg, dsim->reg_base + S5P_DSIM_SDRESOL);
>> +
>> + reg &= ~(DSIM_SUB_VRESOL_MASK) | ~(DSIM_SUB_HRESOL_MASK);
>> + reg |= ((vert & 0x7ff) << DSIM_SUB_VRESOL_SHIFT) |
>> + ((hori & 0x7ff) << DSIM_SUB_HRESOL_SHIFT);
>> + writel(reg, dsim->reg_base + S5P_DSIM_SDRESOL);
>> +
>> + reg |= (1 << DSIM_SUB_STANDY_SHIFT);
>> + writel(reg, dsim->reg_base + S5P_DSIM_SDRESOL);
>> +}
>> +
>> +void s5p_mipi_dsi_init_config(struct mipi_dsim_device *dsim)
>> +{
>> + struct mipi_dsim_config *dsim_config = dsim->dsim_config;
>> +
>> + unsigned int cfg = (readl(dsim->reg_base + S5P_DSIM_CONFIG)) &
>> + ~(1 << 28) & ~(0x1f << 20) & ~(0x3 << 5);
>> +
>> + cfg = (dsim_config->auto_flush << 29) |
>> + (dsim_config->eot_disable << 28) |
>> + (dsim_config->auto_vertical_cnt << DSIM_AUTO_MODE_SHIFT) |
>> + (dsim_config->hse << DSIM_HSE_MODE_SHIFT) |
>> + (dsim_config->hfp << DSIM_HFP_MODE_SHIFT) |
>> + (dsim_config->hbp << DSIM_HBP_MODE_SHIFT) |
>> + (dsim_config->hsa << DSIM_HSA_MODE_SHIFT) |
>> + (dsim_config->e_no_data_lane << DSIM_NUM_OF_DATALANE_SHIFT);
>> +
>> + writel(cfg, dsim->reg_base + S5P_DSIM_CONFIG);
>> +}
>> +
>> +void s5p_mipi_dsi_display_config(struct mipi_dsim_device *dsim,
>> + struct mipi_dsim_config *dsim_config)
>> +{
>> + u32 reg = (readl(dsim->reg_base + S5P_DSIM_CONFIG)) &
>> + ~(0x3 << 26) & ~(1 << 25) & ~(0x3 << 18) & ~(0x7 << 12) &
>> + ~(0x3 << 16) & ~(0x7 << 8);
>> +
>> + if (dsim_config->e_interface = DSIM_VIDEO)
>> + reg |= (1 << 25);
>> + else if (dsim_config->e_interface = DSIM_COMMAND)
>> + reg &= ~(1 << 25);
>> + else {
>> + dev_err(dsim->dev, "this ddi is not MIPI interface.\n");
>> + return;
>> + }
>> +
>> + /* main lcd */
>> + reg |= ((u8) (dsim_config->e_burst_mode) & 0x3) << 26 |
>> + ((u8) (dsim_config->e_virtual_ch) & 0x3) << 18 |
>> + ((u8) (dsim_config->e_pixel_format) & 0x7) << 12;
>> +
>> + writel(reg, dsim->reg_base + S5P_DSIM_CONFIG);
>> +}
>> +
>> +void s5p_mipi_dsi_enable_lane(struct mipi_dsim_device *dsim, unsigned int lane,
>> + unsigned int enable)
>> +{
>> + unsigned int reg;
>> +
>> + reg = readl(dsim->reg_base + S5P_DSIM_CONFIG);
>> +
>> + if (enable)
>> + reg |= DSIM_LANE_ENx(lane);
>> + else
>> + reg &= ~DSIM_LANE_ENx(lane);
>> +
>> + writel(reg, dsim->reg_base + S5P_DSIM_CONFIG);
>> +}
>> +
>> +
>> +void s5p_mipi_dsi_set_data_lane_number(struct mipi_dsim_device *dsim,
>> + unsigned int count)
>> +{
>> + unsigned int cfg;
>> +
>> + /* get the data lane number. */
>> + cfg = DSIM_NUM_OF_DATA_LANE(count);
>> +
>> + writel(cfg, dsim->reg_base + S5P_DSIM_CONFIG);
>> +}
>> +
>> +void s5p_mipi_dsi_enable_afc(struct mipi_dsim_device *dsim, unsigned int enable,
>> + unsigned int afc_code)
>> +{
>> + unsigned int reg = readl(dsim->reg_base + S5P_DSIM_PHYACCHR);
>> +
>> + if (enable) {
>> + reg |= (1 << 14);
>> + reg &= ~(0x7 << 5);
>> + reg |= (afc_code & 0x7) << 5;
>> + } else
>> + reg &= ~(1 << 14);
>> +
>> + writel(reg, dsim->reg_base + S5P_DSIM_PHYACCHR);
>> +}
>> +
>> +void s5p_mipi_dsi_enable_pll_bypass(struct mipi_dsim_device *dsim,
>> + unsigned int enable)
>> +{
>> + unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_CLKCTRL)) &
>> + ~(DSIM_PLL_BYPASS_EXTERNAL);
>> +
>> + reg |= enable << DSIM_PLL_BYPASS_SHIFT;
>> +
>> + writel(reg, dsim->reg_base + S5P_DSIM_CLKCTRL);
>> +}
>> +
>> +void s5p_mipi_dsi_set_pll_pms(struct mipi_dsim_device *dsim, unsigned int p,
>> + unsigned int m, unsigned int s)
>> +{
>> + unsigned int reg = readl(dsim->reg_base + S5P_DSIM_PLLCTRL);
>> +
>> + reg |= ((p & 0x3f) << 13) | ((m & 0x1ff) << 4) | ((s & 0x7) << 1);
>> +
>> + writel(reg, dsim->reg_base + S5P_DSIM_PLLCTRL);
>> +}
>> +
>> +void s5p_mipi_dsi_pll_freq_band(struct mipi_dsim_device *dsim,
>> + unsigned int freq_band)
>> +{
>> + unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_PLLCTRL)) &
>> + ~(0x1f << DSIM_FREQ_BAND_SHIFT);
>> +
>> + reg |= ((freq_band & 0x1f) << DSIM_FREQ_BAND_SHIFT);
>> +
>> + writel(reg, dsim->reg_base + S5P_DSIM_PLLCTRL);
>> +}
>> +
>> +void s5p_mipi_dsi_pll_freq(struct mipi_dsim_device *dsim,
>> + unsigned int pre_divider, unsigned int main_divider,
>> + unsigned int scaler)
>> +{
>> + unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_PLLCTRL)) &
>> + ~(0x7ffff << 1);
>> +
>> + reg |= (pre_divider & 0x3f) << 13 | (main_divider & 0x1ff) << 4 |
>> + (scaler & 0x7) << 1;
>> +
>> + writel(reg, dsim->reg_base + S5P_DSIM_PLLCTRL);
>> +}
>> +
>> +void s5p_mipi_dsi_pll_stable_time(struct mipi_dsim_device *dsim,
>> + unsigned int lock_time)
>> +{
>> + writel(lock_time, dsim->reg_base + S5P_DSIM_PLLTMR);
>> +}
>> +
>> +void s5p_mipi_dsi_enable_pll(struct mipi_dsim_device *dsim, unsigned int enable)
>> +{
>> + unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_PLLCTRL)) &
>> + ~(0x1 << DSIM_PLL_EN_SHIFT);
>> +
>> + reg |= ((enable & 0x1) << DSIM_PLL_EN_SHIFT);
>> +
>> + writel(reg, dsim->reg_base + S5P_DSIM_PLLCTRL);
>> +}
>> +
>> +void s5p_mipi_dsi_set_byte_clock_src(struct mipi_dsim_device *dsim,
>> + unsigned int src)
>> +{
>> + unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_CLKCTRL)) &
>> + ~(0x3 << DSIM_BYTE_CLK_SRC_SHIFT);
>> +
>> + reg |= ((unsigned int) src) << DSIM_BYTE_CLK_SRC_SHIFT;
>> +
>> + writel(reg, dsim->reg_base + S5P_DSIM_CLKCTRL);
>> +}
>> +
>> +void s5p_mipi_dsi_enable_byte_clock(struct mipi_dsim_device *dsim,
>> + unsigned int enable)
>> +{
>> + unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_CLKCTRL)) &
>> + ~(1 << DSIM_BYTE_CLKEN_SHIFT);
>> +
>> + reg |= enable << DSIM_BYTE_CLKEN_SHIFT;
>> +
>> + writel(reg, dsim->reg_base + S5P_DSIM_CLKCTRL);
>> +}
>> +
>> +void s5p_mipi_dsi_set_esc_clk_prs(struct mipi_dsim_device *dsim,
>> + unsigned int enable, unsigned int prs_val)
>> +{
>> + unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_CLKCTRL)) &
>> + ~(1 << DSIM_ESC_CLKEN_SHIFT) & ~(0xffff);
>> +
>> + reg |= enable << DSIM_ESC_CLKEN_SHIFT;
>> + if (enable)
>> + reg |= prs_val;
>> +
>> + writel(reg, dsim->reg_base + S5P_DSIM_CLKCTRL);
>> +}
>> +
>> +void s5p_mipi_dsi_enable_esc_clk_on_lane(struct mipi_dsim_device *dsim,
>> + unsigned int lane_sel, unsigned int enable)
>> +{
>> + unsigned int reg = readl(dsim->reg_base + S5P_DSIM_CLKCTRL);
>> +
>> + if (enable)
>> + reg |= DSIM_LANE_ESC_CLKEN(lane_sel);
>> + else
>> +
>> + reg &= ~DSIM_LANE_ESC_CLKEN(lane_sel);
>> +
>> + writel(reg, dsim->reg_base + S5P_DSIM_CLKCTRL);
>> +}
>> +
>> +void s5p_mipi_dsi_force_dphy_stop_state(struct mipi_dsim_device *dsim,
>> + unsigned int enable)
>> +{
>> + unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_ESCMODE)) &
>> + ~(0x1 << DSIM_FORCE_STOP_STATE_SHIFT);
>> +
>> + reg |= ((enable & 0x1) << DSIM_FORCE_STOP_STATE_SHIFT);
>> +
>> + writel(reg, dsim->reg_base + S5P_DSIM_ESCMODE);
>> +}
>> +
>> +unsigned int s5p_mipi_dsi_is_lane_state(struct mipi_dsim_device *dsim)
>> +{
>> + unsigned int reg = readl(dsim->reg_base + S5P_DSIM_STATUS);
>> +
>> + /**
>> + * check clock and data lane states.
>> + * if MIPI-DSI controller was enabled at bootloader then
>> + * TX_READY_HS_CLK is enabled otherwise STOP_STATE_CLK.
>> + * so it should be checked for two case.
>> + */
>> + if ((reg & DSIM_STOP_STATE_DAT(0xf)) &&
>> + ((reg & DSIM_STOP_STATE_CLK) ||
>> + (reg & DSIM_TX_READY_HS_CLK)))
>> + return 1;
>> + else
>> + return 0;
>> +
>> + return 0;
>> +}
>> +
>> +void s5p_mipi_dsi_set_stop_state_counter(struct mipi_dsim_device *dsim,
>> + unsigned int cnt_val)
>> +{
>> + unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_ESCMODE)) &
>> + ~(0x7ff << DSIM_STOP_STATE_CNT_SHIFT);
>> +
>> + reg |= ((cnt_val & 0x7ff) << DSIM_STOP_STATE_CNT_SHIFT);
>> +
>> + writel(reg, dsim->reg_base + S5P_DSIM_ESCMODE);
>> +}
>> +
>> +void s5p_mipi_dsi_set_bta_timeout(struct mipi_dsim_device *dsim,
>> + unsigned int timeout)
>> +{
>> + unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_TIMEOUT)) &
>> + ~(0xff << DSIM_BTA_TOUT_SHIFT);
>> +
>> + reg |= (timeout << DSIM_BTA_TOUT_SHIFT);
>> +
>> + writel(reg, dsim->reg_base + S5P_DSIM_TIMEOUT);
>> +}
>> +
>> +void s5p_mipi_dsi_set_lpdr_timeout(struct mipi_dsim_device *dsim,
>> + unsigned int timeout)
>> +{
>> + unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_TIMEOUT)) &
>> + ~(0xffff << DSIM_LPDR_TOUT_SHIFT);
>> +
>> + reg |= (timeout << DSIM_LPDR_TOUT_SHIFT);
>> +
>> + writel(reg, dsim->reg_base + S5P_DSIM_TIMEOUT);
>> +}
>> +
>> +void s5p_mipi_dsi_set_cpu_transfer_mode(struct mipi_dsim_device *dsim,
>> + unsigned int lp)
>> +{
>> + unsigned int reg = readl(dsim->reg_base + S5P_DSIM_ESCMODE);
>> +
>> + reg &= ~DSIM_CMD_LPDT_LP;
>> +
>> + if (lp)
>> + reg |= DSIM_CMD_LPDT_LP;
>> +
>> + writel(reg, dsim->reg_base + S5P_DSIM_ESCMODE);
>> +}
>> +
>> +void s5p_mipi_dsi_set_lcdc_transfer_mode(struct mipi_dsim_device *dsim,
>> + unsigned int lp)
>> +{
>> + unsigned int reg = readl(dsim->reg_base + S5P_DSIM_ESCMODE);
>> +
>> + reg &= ~DSIM_TX_LPDT_LP;
>> +
>> + if (lp)
>> + reg |= DSIM_TX_LPDT_LP;
>> +
>> + writel(reg, dsim->reg_base + S5P_DSIM_ESCMODE);
>> +}
>> +
>> +void s5p_mipi_dsi_enable_hs_clock(struct mipi_dsim_device *dsim,
>> + unsigned int enable)
>> +{
>> + unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_CLKCTRL)) &
>> + ~(1 << DSIM_TX_REQUEST_HSCLK_SHIFT);
>> +
>> + reg |= enable << DSIM_TX_REQUEST_HSCLK_SHIFT;
>> +
>> + writel(reg, dsim->reg_base + S5P_DSIM_CLKCTRL);
>> +}
>> +
>> +void s5p_mipi_dsi_dp_dn_swap(struct mipi_dsim_device *dsim,
>> + unsigned int swap_en)
>> +{
>> + unsigned int reg = readl(dsim->reg_base + S5P_DSIM_PHYACCHR1);
>> +
>> + reg &= ~(0x3 << 0);
>> + reg |= (swap_en & 0x3) << 0;
>> +
>> + writel(reg, dsim->reg_base + S5P_DSIM_PHYACCHR1);
>> +}
>> +
>> +void s5p_mipi_dsi_hs_zero_ctrl(struct mipi_dsim_device *dsim,
>> + unsigned int hs_zero)
>> +{
>> + unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_PLLCTRL)) &
>> + ~(0xf << 28);
>> +
>> + reg |= ((hs_zero & 0xf) << 28);
>> +
>> + writel(reg, dsim->reg_base + S5P_DSIM_PLLCTRL);
>> +}
>> +
>> +void s5p_mipi_dsi_prep_ctrl(struct mipi_dsim_device *dsim, unsigned int prep)
>> +{
>> + unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_PLLCTRL)) &
>> + ~(0x7 << 20);
>> +
>> + reg |= ((prep & 0x7) << 20);
>> +
>> + writel(reg, dsim->reg_base + S5P_DSIM_PLLCTRL);
>> +}
>> +
>> +void s5p_mipi_dsi_clear_interrupt(struct mipi_dsim_device *dsim)
>> +{
>> + unsigned int reg = readl(dsim->reg_base + S5P_DSIM_INTSRC);
>> +
>> + reg |= INTSRC_PLL_STABLE;
>> +
>> + writel(reg, dsim->reg_base + S5P_DSIM_INTSRC);
>> +}
>> +
>> +void s5p_mipi_dsi_clear_all_interrupt(struct mipi_dsim_device *dsim)
>> +{
>> + unsigned int reg = readl(dsim->reg_base + S5P_DSIM_INTSRC);
>> +
>> + reg |= 0xffffffff;
>> +
>> + writel(reg, dsim->reg_base + S5P_DSIM_INTSRC);
>> +}
>> +
>> +unsigned int s5p_mipi_dsi_is_pll_stable(struct mipi_dsim_device *dsim)
>> +{
>> + unsigned int reg;
>> +
>> + reg = readl(dsim->reg_base + S5P_DSIM_STATUS);
>> +
>> + return reg & (1 << 31) ? 1 : 0;
>> +}
>> +
>> +unsigned int s5p_mipi_dsi_get_fifo_state(struct mipi_dsim_device *dsim)
>> +{
>> + unsigned int ret;
>> +
>> + ret = readl(dsim->reg_base + S5P_DSIM_FIFOCTRL) & ~(0x1f);
>> +
>> + return ret;
>> +}
>> +
>> +void s5p_mipi_dsi_wr_tx_header(struct mipi_dsim_device *dsim,
>> + unsigned int di, unsigned int data0, unsigned int data1)
>> +{
>> + unsigned int reg = (data1 << 16) | (data0 << 8) | ((di & 0x3f) << 0);
>> +
>> + writel(reg, dsim->reg_base + S5P_DSIM_PKTHDR);
>> +}
>> +
>> +unsigned int _s5p_mipi_dsi_get_frame_done_status(struct mipi_dsim_device *dsim)
>> +{
>> + unsigned int reg = readl(dsim->reg_base + S5P_DSIM_INTSRC);
>> +
>> + return (reg & INTSRC_FRAME_DONE) ? 1 : 0;
>> +}
>> +
>> +void _s5p_mipi_dsi_clear_frame_done(struct mipi_dsim_device *dsim)
>> +{
>> + unsigned int reg = readl(dsim->reg_base + S5P_DSIM_INTSRC);
>> +
>> + writel(reg | INTSRC_FRAME_DONE, dsim->reg_base +
>> + S5P_DSIM_INTSRC);
>> +}
>> +
>> +void s5p_mipi_dsi_wr_tx_data(struct mipi_dsim_device *dsim,
>> + unsigned int tx_data)
>> +{
>> + writel(tx_data, dsim->reg_base + S5P_DSIM_PAYLOAD);
>> +}
>> diff --git a/drivers/video/s5p_mipi_dsi_lowlevel.h b/drivers/video/s5p_mipi_dsi_lowlevel.h
>> new file mode 100644
>> index 0000000..ca9dc56
>> --- /dev/null
>> +++ b/drivers/video/s5p_mipi_dsi_lowlevel.h
>> @@ -0,0 +1,100 @@
>> +/* linux/drivers/video/s5p_mipi_dsi_lowlevel.h
>> + *
>> + * Header file for Samsung SoC MIPI-DSI lowlevel driver.
>> + *
>> + * Copyright (c) 2011 Samsung Electronics Co., Ltd
>> + *
>> + * InKi Dae <inki.dae@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.
>> +*/
>> +
>> +#ifndef _S5P_MIPI_DSI_LOWLEVEL_H
>> +#define _S5P_MIPI_DSI_LOWLEVEL_H
>> +
>> +void s5p_mipi_dsi_func_reset(struct mipi_dsim_device *dsim);
>> +void s5p_mipi_dsi_sw_reset(struct mipi_dsim_device *dsim);
>> +void s5p_mipi_dsi_set_interrupt_mask(struct mipi_dsim_device *dsim,
>> + unsigned int mode, unsigned int mask);
>> +void s5p_mipi_dsi_set_data_lane_number(struct mipi_dsim_device *dsim,
>> + unsigned int count);
>> +void s5p_mipi_dsi_init_fifo_pointer(struct mipi_dsim_device *dsim,
>> + unsigned int cfg);
>> +void s5p_mipi_dsi_set_phy_tunning(struct mipi_dsim_device *dsim,
>> + unsigned int value);
>> +void s5p_mipi_dsi_set_phy_tunning(struct mipi_dsim_device *dsim,
>> + unsigned int value);
>> +void s5p_mipi_dsi_set_main_disp_resol(struct mipi_dsim_device *dsim,
>> + unsigned int width_resol, unsigned int height_resol);
>> +void s5p_mipi_dsi_set_main_disp_vporch(struct mipi_dsim_device *dsim,
>> + unsigned int cmd_allow, unsigned int vfront, unsigned int vback);
>> +void s5p_mipi_dsi_set_main_disp_hporch(struct mipi_dsim_device *dsim,
>> + unsigned int front, unsigned int back);
>> +void s5p_mipi_dsi_set_main_disp_sync_area(struct mipi_dsim_device *dsim,
>> + unsigned int vert, unsigned int hori);
>> +void s5p_mipi_dsi_set_sub_disp_resol(struct mipi_dsim_device *dsim,
>> + unsigned int vert, unsigned int hori);
>> +void s5p_mipi_dsi_init_config(struct mipi_dsim_device *dsim);
>> +void s5p_mipi_dsi_display_config(struct mipi_dsim_device *dsim,
>> + struct mipi_dsim_config *dsim_config);
>> +void s5p_mipi_dsi_set_data_lane_number(struct mipi_dsim_device *dsim,
>> + unsigned int count);
>> +void s5p_mipi_dsi_enable_lane(struct mipi_dsim_device *dsim, unsigned int lane,
>> + unsigned int enable);
>> +void s5p_mipi_dsi_enable_afc(struct mipi_dsim_device *dsim, unsigned int enable,
>> + unsigned int afc_code);
>> +void s5p_mipi_dsi_enable_pll_bypass(struct mipi_dsim_device *dsim,
>> + unsigned int enable);
>> +void s5p_mipi_dsi_set_pll_pms(struct mipi_dsim_device *dsim, unsigned int p,
>> + unsigned int m, unsigned int s);
>> +void s5p_mipi_dsi_pll_freq_band(struct mipi_dsim_device *dsim,
>> + unsigned int freq_band);
>> +void s5p_mipi_dsi_pll_freq(struct mipi_dsim_device *dsim,
>> + unsigned int pre_divider, unsigned int main_divider,
>> + unsigned int scaler);
>> +void s5p_mipi_dsi_pll_stable_time(struct mipi_dsim_device *dsim,
>> + unsigned int lock_time);
>> +void s5p_mipi_dsi_enable_pll(struct mipi_dsim_device *dsim,
>> + unsigned int enable);
>> +void s5p_mipi_dsi_set_byte_clock_src(struct mipi_dsim_device *dsim,
>> + unsigned int src);
>> +void s5p_mipi_dsi_enable_byte_clock(struct mipi_dsim_device *dsim,
>> + unsigned int enable);
>> +void s5p_mipi_dsi_set_esc_clk_prs(struct mipi_dsim_device *dsim,
>> + unsigned int enable, unsigned int prs_val);
>> +void s5p_mipi_dsi_enable_esc_clk_on_lane(struct mipi_dsim_device *dsim,
>> + unsigned int lane_sel, unsigned int enable);
>> +void s5p_mipi_dsi_force_dphy_stop_state(struct mipi_dsim_device *dsim,
>> + unsigned int enable);
>> +unsigned int s5p_mipi_dsi_is_lane_state(struct mipi_dsim_device *dsim);
>> +void s5p_mipi_dsi_set_stop_state_counter(struct mipi_dsim_device *dsim,
>> + unsigned int cnt_val);
>> +void s5p_mipi_dsi_set_bta_timeout(struct mipi_dsim_device *dsim,
>> + unsigned int timeout);
>> +void s5p_mipi_dsi_set_lpdr_timeout(struct mipi_dsim_device *dsim,
>> + unsigned int timeout);
>> +void s5p_mipi_dsi_set_lcdc_transfer_mode(struct mipi_dsim_device *dsim,
>> + unsigned int lp);
>> +void s5p_mipi_dsi_set_cpu_transfer_mode(struct mipi_dsim_device *dsim,
>> + unsigned int lp);
>> +void s5p_mipi_dsi_enable_hs_clock(struct mipi_dsim_device *dsim,
>> + unsigned int enable);
>> +void s5p_mipi_dsi_dp_dn_swap(struct mipi_dsim_device *dsim,
>> + unsigned int swap_en);
>> +void s5p_mipi_dsi_hs_zero_ctrl(struct mipi_dsim_device *dsim,
>> + unsigned int hs_zero);
>> +void s5p_mipi_dsi_prep_ctrl(struct mipi_dsim_device *dsim, unsigned int prep);
>> +void s5p_mipi_dsi_clear_interrupt(struct mipi_dsim_device *dsim);
>> +void s5p_mipi_dsi_clear_all_interrupt(struct mipi_dsim_device *dsim);
>> +unsigned int s5p_mipi_dsi_is_pll_stable(struct mipi_dsim_device *dsim);
>> +unsigned int s5p_mipi_dsi_get_fifo_state(struct mipi_dsim_device *dsim);
>> +unsigned int _s5p_mipi_dsi_get_frame_done_status(struct mipi_dsim_device *dsim);
>> +void _s5p_mipi_dsi_clear_frame_done(struct mipi_dsim_device *dsim);
>> +void s5p_mipi_dsi_wr_tx_header(struct mipi_dsim_device *dsim, unsigned int di,
>> + unsigned int data0, unsigned int data1);
>> +void s5p_mipi_dsi_wr_tx_data(struct mipi_dsim_device *dsim,
>> + unsigned int tx_data);
>> +
>> +#endif /* _S5P_MIPI_DSI_LOWLEVEL_H */
>> --
>> 1.7.0.4
>>
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> linux-arm-kernel@lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>>
>
^ permalink raw reply
* Re: [PATCH 1/2] video: add Samsung SoC MIPI-DSI controller driver.
From: Kyungmin Park @ 2011-04-15 0:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1302783320-31230-1-git-send-email-inki.dae@samsung.com>
Mr. Dae,
If only MIPI header files are used at video, just place it under video
directory.
regardless this issue, how about the make a generic mipi dsi interface at video?
then other soc will be helpful also.
e.g., one generic MIPI DSI framework and each SoCs register the
operations or override the functions or better way.
No need to think/consider the samsung SOCs only.
Thank you,
Kyungmin Park
On Thu, Apr 14, 2011 at 9:15 PM, Inki Dae <inki.dae@samsung.com> wrote:
> Samsung S5PV210 and EXYNOS4 SoC platform have one or two MIPI-DSI controller.
> MIPI-DSI based LCD Panel could be used with MIPI-DSI controller driver.
> this patch adds the MIPI-DSI controller driver and also this driver would
> support both platforms.
>
> to use MIPI-DSI based LCD Panel driver, mipi_dsim_lcd_device should be
> registered to MIPI-DSI Driver through s5p_mipi_dsi_register_lcd_device() call
> in machine code or machine specific somewhere first, and mipi_dsim_lcd_driver
> should be registered when s5p_mipi_dsi_register_lcd_driver() is called at init
> function of lcd driver, and then probe() of that driver would be called by
> MIPI-DSI controller driver if lcd panel name and id of mipi_dsim_lcd_device
> are same as ones of mipi_dsim_lcd_driver.
>
> for this, you can refer to sample lcd panel driver.
> please see "Documentation/s5p_mipi_dsim/dsim_sample_lcd.c"
>
> Signed-off-by: Inki Dae <inki.dae@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> ---
> arch/arm/plat-s5p/include/plat/mipi_dsim.h | 345 +++++++++++++++
> arch/arm/plat-s5p/include/plat/regs-dsim.h | 143 ++++++
> drivers/video/Kconfig | 7 +
> drivers/video/Makefile | 2 +
> drivers/video/s5p_mipi_dsi.c | 481 ++++++++++++++++++++
> drivers/video/s5p_mipi_dsi_common.c | 655 ++++++++++++++++++++++++++++
> drivers/video/s5p_mipi_dsi_common.h | 39 ++
> drivers/video/s5p_mipi_dsi_lowlevel.c | 558 +++++++++++++++++++++++
> drivers/video/s5p_mipi_dsi_lowlevel.h | 100 +++++
> 9 files changed, 2330 insertions(+), 0 deletions(-)
> create mode 100644 arch/arm/plat-s5p/include/plat/mipi_dsim.h
> create mode 100644 arch/arm/plat-s5p/include/plat/regs-dsim.h
> create mode 100644 drivers/video/s5p_mipi_dsi.c
> create mode 100644 drivers/video/s5p_mipi_dsi_common.c
> create mode 100644 drivers/video/s5p_mipi_dsi_common.h
> create mode 100644 drivers/video/s5p_mipi_dsi_lowlevel.c
> create mode 100644 drivers/video/s5p_mipi_dsi_lowlevel.h
>
> diff --git a/arch/arm/plat-s5p/include/plat/mipi_dsim.h b/arch/arm/plat-s5p/include/plat/mipi_dsim.h
> new file mode 100644
> index 0000000..0fa2d7e
> --- /dev/null
> +++ b/arch/arm/plat-s5p/include/plat/mipi_dsim.h
> @@ -0,0 +1,345 @@
> +/* linux/arm/arch/plat-s5p/include/plat/mipi_dsim.h
> + *
> + * Platform data header for Samsung SoC MIPI-DSIM.
> + *
> + * Copyright (c) 2011 Samsung Electronics Co., Ltd
> + *
> + * InKi Dae <inki.dae@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.
> +*/
> +
> +#ifndef _DSIM_H
> +#define _DSIM_H
> +
> +#include <linux/device.h>
> +#include <linux/fb.h>
> +
> +#define PANEL_NAME_SIZE (32)
> +
> +enum mipi_dsim_interface_type {
> + DSIM_COMMAND,
> + DSIM_VIDEO
> +};
> +
> +enum mipi_dsim_virtual_ch_no {
> + DSIM_VIRTUAL_CH_0,
> + DSIM_VIRTUAL_CH_1,
> + DSIM_VIRTUAL_CH_2,
> + DSIM_VIRTUAL_CH_3
> +};
> +
> +enum mipi_dsim_burst_mode_type {
> + DSIM_NON_BURST_SYNC_EVENT,
> + DSIM_NON_BURST_SYNC_PULSE = 2,
> + DSIM_BURST,
> + DSIM_NON_VIDEO_MODE
> +};
> +
> +enum mipi_dsim_no_of_data_lane {
> + DSIM_DATA_LANE_1,
> + DSIM_DATA_LANE_2,
> + DSIM_DATA_LANE_3,
> + DSIM_DATA_LANE_4
> +};
> +
> +enum mipi_dsim_byte_clk_src {
> + DSIM_PLL_OUT_DIV8,
> + DSIM_EXT_CLK_DIV8,
> + DSIM_EXT_CLK_BYPASS
> +};
> +
> +enum mipi_dsim_pixel_format {
> + DSIM_CMD_3BPP,
> + DSIM_CMD_8BPP,
> + DSIM_CMD_12BPP,
> + DSIM_CMD_16BPP,
> + DSIM_VID_16BPP_565,
> + DSIM_VID_18BPP_666PACKED,
> + DSIM_18BPP_666LOOSELYPACKED,
> + DSIM_24BPP_888
> +};
> +
> +/**
> + * struct mipi_dsim_config - interface for configuring mipi-dsi controller.
> + *
> + * @auto_flush: enable or disable Auto flush of MD FIFO using VSYNC pulse.
> + * @eot_disable: enable or disable EoT packet in HS mode.
> + * @auto_vertical_cnt: specifies auto vertical count mode.
> + * in Video mode, the vertical line transition uses line counter
> + * configured by VSA, VBP, and Vertical resolution.
> + * If this bit is set to '1', the line counter does not use VSA and VBP
> + * registers.(in command mode, this variable is ignored)
> + * @hse: set horizontal sync event mode.
> + * In VSYNC pulse and Vporch area, MIPI DSI master transfers only HSYNC
> + * start packet to MIPI DSI slave at MIPI DSI spec1.1r02.
> + * this bit transfers HSYNC end packet in VSYNC pulse and Vporch area
> + * (in mommand mode, this variable is ignored)
> + * @hfp: specifies HFP disable mode.
> + * if this variable is set, DSI master ignores HFP area in VIDEO mode.
> + * (in command mode, this variable is ignored)
> + * @hbp: specifies HBP disable mode.
> + * if this variable is set, DSI master ignores HBP area in VIDEO mode.
> + * (in command mode, this variable is ignored)
> + * @hsa: specifies HSA disable mode.
> + * if this variable is set, DSI master ignores HSA area in VIDEO mode.
> + * (in command mode, this variable is ignored)
> + * @e_interface: specifies interface to be used.(CPU or RGB interface)
> + * @e_virtual_ch: specifies virtual channel number that main or
> + * sub diaplsy uses.
> + * @e_pixel_format: specifies pixel stream format for main or sub display.
> + * @e_burst_mode: selects Burst mode in Video mode.
> + * in Non-burst mode, RGB data area is filled with RGB data and NULL
> + * packets, according to input bandwidth of RGB interface.
> + * In Burst mode, RGB data area is filled with RGB data only.
> + * @e_no_data_lane: specifies data lane count to be used by Master.
> + * @e_byte_clk: select byte clock source. (it must be DSIM_PLL_OUT_DIV8)
> + * DSIM_EXT_CLK_DIV8 and DSIM_EXT_CLK_BYPASSS are not supported.
> + * @pll_stable_time: specifies the PLL Timer for stability of the ganerated
> + * clock(System clock cycle base)
> + * if the timer value goes to 0x00000000, the clock stable bit of status
> + * and interrupt register is set.
> + * @esc_clk: specifies escape clock frequency for getting the escape clock
> + * prescaler value.
> + * @stop_holding_cnt: specifies the interval value between transmitting
> + * read packet(or write "set_tear_on" command) and BTA request.
> + * after transmitting read packet or write "set_tear_on" command,
> + * BTA requests to D-PHY automatically. this counter value specifies
> + * the interval between them.
> + * @bta_timeout: specifies the timer for BTA.
> + * this register specifies time out from BTA request to change
> + * the direction with respect to Tx escape clock.
> + * @rx_timeout: specifies the timer for LP Rx mode timeout.
> + * this register specifies time out on how long RxValid deasserts,
> + * after RxLpdt asserts with respect to Tx escape clock.
> + * - RxValid specifies Rx data valid indicator.
> + * - RxLpdt specifies an indicator that D-PHY is under RxLpdt mode.
> + * - RxValid and RxLpdt specifies signal from D-PHY.
> + */
> +struct mipi_dsim_config {
> + unsigned char auto_flush;
> + unsigned char eot_disable;
> +
> + unsigned char auto_vertical_cnt;
> + unsigned char hse;
> + unsigned char hfp;
> + unsigned char hbp;
> + unsigned char hsa;
> +
> + enum mipi_dsim_interface_type e_interface;
> + enum mipi_dsim_virtual_ch_no e_virtual_ch;
> + enum mipi_dsim_pixel_format e_pixel_format;
> + enum mipi_dsim_burst_mode_type e_burst_mode;
> + enum mipi_dsim_no_of_data_lane e_no_data_lane;
> + enum mipi_dsim_byte_clk_src e_byte_clk;
> +
> + /*
> + * =====================> + * | P | M | S | MHz |
> + * -------------------------------------------
> + * | 3 | 100 | 3 | 100 |
> + * | 3 | 100 | 2 | 200 |
> + * | 3 | 63 | 1 | 252 |
> + * | 4 | 100 | 1 | 300 |
> + * | 4 | 110 | 1 | 330 |
> + * | 12 | 350 | 1 | 350 |
> + * | 3 | 100 | 1 | 400 |
> + * | 4 | 150 | 1 | 450 |
> + * | 3 | 118 | 1 | 472 |
> + * | 12 | 250 | 0 | 500 |
> + * | 4 | 100 | 0 | 600 |
> + * | 3 | 81 | 0 | 648 |
> + * | 3 | 88 | 0 | 704 |
> + * | 3 | 90 | 0 | 720 |
> + * | 3 | 100 | 0 | 800 |
> + * | 12 | 425 | 0 | 850 |
> + * | 4 | 150 | 0 | 900 |
> + * | 12 | 475 | 0 | 950 |
> + * | 6 | 250 | 0 | 1000 |
> + * -------------------------------------------
> + */
> + unsigned char p;
> + unsigned short m;
> + unsigned char s;
> +
> + unsigned int pll_stable_time;
> + unsigned long esc_clk;
> +
> + unsigned short stop_holding_cnt;
> + unsigned char bta_timeout;
> + unsigned short rx_timeout;
> +};
> +
> +/**
> + * struct mipi_dsim_device - global interface for mipi-dsi driver.
> + *
> + * @dev: driver model representation of the device.
> + * @id: unique device id.
> + * @clock: pointer to MIPI-DSI clock of clock framework.
> + * @irq: interrupt number to MIPI-DSI controller.
> + * @reg_base: base address to memory mapped SRF of MIPI-DSI controller.
> + * (virtual address)
> + * @lock: the mutex protecting this data structure.
> + * @dsim_info: infomation for configuring mipi-dsi controller.
> + * @master_ops: callbacks to mipi-dsi operations.
> + * @dsim_lcd_dev: pointer to activated ddi device.
> + * (it would be registered by mipi-dsi driver.)
> + * @dsim_lcd_drv: pointer to activated_ddi driver.
> + * (it would be registered by mipi-dsi driver.)
> + * @lcd_info: pointer to mipi_lcd_info structure.
> + * @state: specifies status of MIPI-DSI controller.
> + * the status could be RESET, INIT, STOP, HSCLKEN and ULPS.
> + * @resume_complete: indicates whether resume operation is completed or not.
> + * @data_lane: specifiec enabled data lane number.
> + * this variable would be set by driver according to e_no_data_lane
> + * automatically.
> + * @e_clk_src: select byte clock source.
> + * @pd: pointer to MIPI-DSI driver platform data.
> + */
> +struct mipi_dsim_device {
> + struct device *dev;
> + int id;
> + struct resource *res;
> + struct clk *clock;
> + unsigned int irq;
> + void __iomem *reg_base;
> + struct mutex lock;
> +
> + struct mipi_dsim_config *dsim_config;
> + struct mipi_dsim_master_ops *master_ops;
> + struct mipi_dsim_lcd_device *dsim_lcd_dev;
> + struct mipi_dsim_lcd_driver *dsim_lcd_drv;
> +
> + unsigned int state;
> + unsigned int resume_complete;
> + unsigned int data_lane;
> + enum mipi_dsim_byte_clk_src e_clk_src;
> +
> + struct s5p_platform_mipi_dsim *pd;
> +};
> +
> +/**
> + * struct s5p_platform_mipi_dsim - interface to platform data
> + * for mipi-dsi driver.
> + *
> + * @lcd_panel_name: specifies lcd panel name registered to mipi-dsi driver.
> + * lcd panel driver searched would be actived.
> + * @dsim_config: pointer of structure for configuring mipi-dsi controller.
> + * @lcd_panel_info: pointer for lcd panel specific structure.
> + * this structure specifies width, height, timing and polarity and so on.
> + * @mipi_power: callback pointer for enabling or disabling mipi power.
> + * @phy_enable: pointer to a callback controlling D-PHY enable/reset
> + */
> +struct s5p_platform_mipi_dsim {
> + char lcd_panel_name[PANEL_NAME_SIZE];
> +
> + struct mipi_dsim_config *dsim_config;
> + void *lcd_panel_info;
> +
> + int (*mipi_power)(struct platform_device *pdev, unsigned int enable);
> + int (*phy_enable)(struct platform_device *pdev, bool on);
> +};
> +/**
> + * struct mipi_dsim_master_ops - callbacks to mipi-dsi operations.
> + *
> + * @cmd_write: transfer command to lcd panel at LP mode.
> + * @cmd_read: read command from rx register.
> + * @get_dsim_frame_done: get the status that all screen data have been
> + * transferred to mipi-dsi.
> + * @clear_dsim_frame_done: clear frame done status.
> + * @get_fb_frame_done: get frame done status of display controller.
> + * @trigger: trigger display controller.
> + * - this one would be used only in case of CPU mode.
> + */
> +
> +struct mipi_dsim_master_ops {
> + int (*cmd_write)(struct mipi_dsim_device *dsim, unsigned int data_id,
> + unsigned int data0, unsigned int data1);
> + int (*cmd_read)(struct mipi_dsim_device *dsim, unsigned int data_id,
> + unsigned int data0, unsigned int data1);
> + int (*get_dsim_frame_done)(struct mipi_dsim_device *dsim);
> + int (*clear_dsim_frame_done)(struct mipi_dsim_device *dsim);
> +
> + int (*get_fb_frame_done)(struct fb_info *info);
> + void (*trigger)(struct fb_info *info);
> +};
> +
> +/**
> + * device structure for mipi-dsi based lcd panel.
> + *
> + * @name: name of the device to use with this device, or an
> + * alias for that name.
> + * @dev: driver model representation of the device.
> + * @id: id of device to be registered.
> + * @bus_id: bus id for identifing connected bus
> + * and this bus id should be same as id of mipi_dsim_device.
> + * @irq: irq number for signaling when framebuffer transfer of
> + * lcd panel module is completed.
> + * this irq would be used only for MIPI-DSI based CPU mode lcd panel.
> + * @master: pointer to mipi-dsi master device object.
> + * @platform_data: lcd panel specific platform data.
> + */
> +struct mipi_dsim_lcd_device {
> + char *name;
> + struct device dev;
> + int id;
> + int bus_id;
> + int irq;
> +
> + struct mipi_dsim_device *master;
> + void *platform_data;
> +};
> +
> +/**
> + * driver structure for mipi-dsi based lcd panel.
> + *
> + * this structure should be registered by lcd panel driver.
> + * mipi-dsi driver seeks lcd panel registered through name field
> + * and calls these callback functions in appropriate time.
> + *
> + * @name: name of the driver to use with this device, or an
> + * alias for that name.
> + * @id: id of driver to be registered.
> + * this id would be used for finding device object registered.
> + */
> +struct mipi_dsim_lcd_driver {
> + char *name;
> + int id;
> +
> + int (*probe)(struct mipi_dsim_lcd_device *dsim_dev);
> + int (*remove)(struct mipi_dsim_lcd_device *dsim_dev);
> + void (*shutdown)(struct mipi_dsim_lcd_device *dsim_dev);
> + int (*suspend)(struct mipi_dsim_lcd_device *dsim_dev);
> + int (*resume)(struct mipi_dsim_lcd_device *dsim_dev);
> +};
> +
> +/**
> + * register mipi_dsim_lcd_driver object defined by lcd panel driver
> + * to mipi-dsi driver.
> + */
> +int s5p_mipi_dsi_register_lcd_driver(struct mipi_dsim_lcd_driver
> + *lcd_drv);
> +
> +/**
> + * register mipi_dsim_lcd_device to mipi-dsi master.
> + */
> +int s5p_mipi_dsi_register_lcd_device(struct mipi_dsim_lcd_device
> + *lcd_dev);
> +
> +/**
> + * enable regulators to MIPI-DSI power.
> + */
> +int s5p_mipi_dsi_dphy_power(struct mipi_dsim_device *dsim,
> + unsigned int enable);
> +
> +/**
> + * s5p_dsim_phy_enable - global MIPI-DSI receiver D-PHY control
> + * @pdev: MIPI-DSIM platform device
> + * @on: true to enable D-PHY and deassert its reset
> + * false to disable D-PHY
> + */
> +int s5p_dsim_phy_enable(struct platform_device *pdev, bool on);
> +
> +#endif /* _DSIM_H */
> diff --git a/arch/arm/plat-s5p/include/plat/regs-dsim.h b/arch/arm/plat-s5p/include/plat/regs-dsim.h
> new file mode 100644
> index 0000000..5f0e4fa
> --- /dev/null
> +++ b/arch/arm/plat-s5p/include/plat/regs-dsim.h
> @@ -0,0 +1,143 @@
> +/* linux/arch/arm/plat-s5p/include/plat/regs-dsim.h
> + *
> + * Register definition file for Samsung MIPI-DSIM driver
> + *
> + * Copyright (c) 2011 Samsung Electronics Co., Ltd
> + *
> + * InKi Dae <inki.dae@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.
> +*/
> +
> +#ifndef _REGS_DSIM_H
> +#define _REGS_DSIM_H
> +
> +#define S5P_DSIM_STATUS (0x0) /* Status register */
> +#define S5P_DSIM_SWRST (0x4) /* Software reset register */
> +#define S5P_DSIM_CLKCTRL (0x8) /* Clock control register */
> +#define S5P_DSIM_TIMEOUT (0xc) /* Time out register */
> +#define S5P_DSIM_CONFIG (0x10) /* Configuration register */
> +#define S5P_DSIM_ESCMODE (0x14) /* Escape mode register */
> +
> +/* Main display image resolution register */
> +#define S5P_DSIM_MDRESOL (0x18)
> +#define S5P_DSIM_MVPORCH (0x1c) /* Main display Vporch register */
> +#define S5P_DSIM_MHPORCH (0x20) /* Main display Hporch register */
> +#define S5P_DSIM_MSYNC (0x24) /* Main display sync area register */
> +
> +/* Sub display image resolution register */
> +#define S5P_DSIM_SDRESOL (0x28)
> +#define S5P_DSIM_INTSRC (0x2c) /* Interrupt source register */
> +#define S5P_DSIM_INTMSK (0x30) /* Interrupt mask register */
> +#define S5P_DSIM_PKTHDR (0x34) /* Packet Header FIFO register */
> +#define S5P_DSIM_PAYLOAD (0x38) /* Payload FIFO register */
> +#define S5P_DSIM_RXFIFO (0x3c) /* Read FIFO register */
> +#define S5P_DSIM_FIFOTHLD (0x40) /* FIFO threshold level register */
> +#define S5P_DSIM_FIFOCTRL (0x44) /* FIFO status and control register */
> +
> +/* FIFO memory AC characteristic register */
> +#define S5P_DSIM_PLLCTRL (0x4c) /* PLL control register */
> +#define S5P_DSIM_PLLTMR (0x50) /* PLL timer register */
> +#define S5P_DSIM_PHYACCHR (0x54) /* D-PHY AC characteristic register */
> +#define S5P_DSIM_PHYACCHR1 (0x58) /* D-PHY AC characteristic register1 */
> +
> +/* DSIM_STATUS */
> +#define DSIM_STOP_STATE_DAT(x) (((x) & 0xf) << 0)
> +#define DSIM_STOP_STATE_CLK (1 << 8)
> +#define DSIM_TX_READY_HS_CLK (1 << 10)
> +
> +/* DSIM_SWRST */
> +#define DSIM_FUNCRST (1 << 16)
> +#define DSIM_SWRST (1 << 0)
> +
> +/* S5P_DSIM_TIMEOUT */
> +#define DSIM_LPDR_TOUT_SHIFT (0)
> +#define DSIM_BTA_TOUT_SHIFT (16)
> +
> +/* S5P_DSIM_CLKCTRL */
> +#define DSIM_LANE_ESC_CLKEN_SHIFT (19)
> +#define DSIM_BYTE_CLKEN_SHIFT (24)
> +#define DSIM_BYTE_CLK_SRC_SHIFT (25)
> +#define DSIM_PLL_BYPASS_SHIFT (27)
> +#define DSIM_ESC_CLKEN_SHIFT (28)
> +#define DSIM_TX_REQUEST_HSCLK_SHIFT (31)
> +#define DSIM_LANE_ESC_CLKEN(x) (((x) & 0x1f) << \
> + DSIM_LANE_ESC_CLKEN_SHIFT)
> +#define DSIM_BYTE_CLK_ENABLE (1 << DSIM_BYTE_CLKEN_SHIFT)
> +#define DSIM_BYTE_CLK_DISABLE (0 << DSIM_BYTE_CLKEN_SHIFT)
> +#define DSIM_PLL_BYPASS_EXTERNAL (1 << DSIM_PLL_BYPASS_SHIFT)
> +#define DSIM_ESC_CLKEN_ENABLE (1 << DSIM_ESC_CLKEN_SHIFT)
> +#define DSIM_ESC_CLKEN_DISABLE (0 << DSIM_ESC_CLKEN_SHIFT)
> +
> +/* S5P_DSIM_CONFIG */
> +#define DSIM_NUM_OF_DATALANE_SHIFT (5)
> +#define DSIM_HSA_MODE_SHIFT (20)
> +#define DSIM_HBP_MODE_SHIFT (21)
> +#define DSIM_HFP_MODE_SHIFT (22)
> +#define DSIM_HSE_MODE_SHIFT (23)
> +#define DSIM_AUTO_MODE_SHIFT (24)
> +#define DSIM_LANE_ENx(x) (((x) & 0x1f) << 0)
> +
> +#define DSIM_NUM_OF_DATA_LANE(x) ((x) << DSIM_NUM_OF_DATALANE_SHIFT)
> +
> +/* S5P_DSIM_ESCMODE */
> +#define DSIM_TX_LPDT_SHIFT (6)
> +#define DSIM_CMD_LPDT_SHIFT (7)
> +#define DSIM_TX_LPDT_LP (1 << DSIM_TX_LPDT_SHIFT)
> +#define DSIM_CMD_LPDT_LP (1 << DSIM_CMD_LPDT_SHIFT)
> +#define DSIM_STOP_STATE_CNT_SHIFT (21)
> +#define DSIM_FORCE_STOP_STATE_SHIFT (20)
> +
> +/* S5P_DSIM_MDRESOL */
> +#define DSIM_MAIN_STAND_BY (1 << 31)
> +#define DSIM_MAIN_VRESOL(x) (((x) & 0x7ff) << 16)
> +#define DSIM_MAIN_HRESOL(x) (((x) & 0X7ff) << 0)
> +
> +/* S5P_DSIM_MVPORCH */
> +#define DSIM_CMD_ALLOW_SHIFT (28)
> +#define DSIM_STABLE_VFP_SHIFT (16)
> +#define DSIM_MAIN_VBP_SHIFT (0)
> +#define DSIM_CMD_ALLOW_MASK (0xf << DSIM_CMD_ALLOW_SHIFT)
> +#define DSIM_STABLE_VFP_MASK (0x7ff << DSIM_STABLE_VFP_SHIFT)
> +#define DSIM_MAIN_VBP_MASK (0x7ff << DSIM_MAIN_VBP_SHIFT)
> +
> +/* S5P_DSIM_MHPORCH */
> +#define DSIM_MAIN_HFP_SHIFT (16)
> +#define DSIM_MAIN_HBP_SHIFT (0)
> +#define DSIM_MAIN_HFP_MASK ((0xffff) << DSIM_MAIN_HFP_SHIFT)
> +#define DSIM_MAIN_HBP_MASK ((0xffff) << DSIM_MAIN_HBP_SHIFT)
> +
> +/* S5P_DSIM_MSYNC */
> +#define DSIM_MAIN_VSA_SHIFT (22)
> +#define DSIM_MAIN_HSA_SHIFT (0)
> +#define DSIM_MAIN_VSA_MASK ((0x3ff) << DSIM_MAIN_VSA_SHIFT)
> +#define DSIM_MAIN_HSA_MASK ((0xffff) << DSIM_MAIN_HSA_SHIFT)
> +
> +/* S5P_DSIM_SDRESOL */
> +#define DSIM_SUB_STANDY_SHIFT (31)
> +#define DSIM_SUB_VRESOL_SHIFT (16)
> +#define DSIM_SUB_HRESOL_SHIFT (0)
> +#define DSIM_SUB_STANDY_MASK ((0x1) << DSIM_SUB_STANDY_SHIFT)
> +#define DSIM_SUB_VRESOL_MASK ((0x7ff) << DSIM_SUB_VRESOL_SHIFT)
> +#define DSIM_SUB_HRESOL_MASK ((0x7ff) << DSIM_SUB_HRESOL_SHIFT)
> +
> +/* S5P_DSIM_INTSRC */
> +#define INTSRC_FRAME_DONE (1 << 24)
> +#define INTSRC_PLL_STABLE (1 << 31)
> +
> +/* S5P_DSIM_INTMSK */
> +#define INTMSK_FRAME_DONE (1 << 24)
> +
> +/* S5P_DSIM_FIFOCTRL */
> +#define SFR_HEADER_EMPTY (1 << 22)
> +
> +/* S5P_DSIM_PHYACCHR */
> +#define DSIM_AFC_CTL(x) (((x) & 0x7) << 5)
> +
> +/* S5P_DSIM_PLLCTRL */
> +#define DSIM_PLL_EN_SHIFT (23)
> +#define DSIM_FREQ_BAND_SHIFT (24)
> +
> +#endif /* _REGS_DSIM_H */
> diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
> index e6a8d8c..1e71a54 100644
> --- a/drivers/video/Kconfig
> +++ b/drivers/video/Kconfig
> @@ -2044,6 +2044,13 @@ config FB_S3C2410_DEBUG
> Turn on debugging messages. Note that you can set/unset at run time
> through sysfs
>
> +config S5P_MIPI_DSI
> + tristate "Samsung SoC MIPI-DSI support."
> + depends on FB_S3C && (ARCH_S5PV210 || ARCH_EXYNOS4)
> + default n
> + ---help---
> + This enables support for MIPI-DSI device.
> +
> config FB_NUC900
> bool "NUC900 LCD framebuffer support"
> depends on FB && ARCH_W90X900
> diff --git a/drivers/video/Makefile b/drivers/video/Makefile
> index 2ea44b6..ee5a1d5 100644
> --- a/drivers/video/Makefile
> +++ b/drivers/video/Makefile
> @@ -119,6 +119,8 @@ obj-$(CONFIG_FB_SH7760) += sh7760fb.o
> obj-$(CONFIG_FB_IMX) += imxfb.o
> obj-$(CONFIG_FB_S3C) += s3c-fb.o
> obj-$(CONFIG_FB_S3C2410) += s3c2410fb.o
> +obj-$(CONFIG_S5P_MIPI_DSI) += s5p_mipi_dsi.o s5p_mipi_dsi_common.o \
> + s5p_mipi_dsi_lowlevel.o
> obj-$(CONFIG_FB_FSL_DIU) += fsl-diu-fb.o
> obj-$(CONFIG_FB_COBALT) += cobalt_lcdfb.o
> obj-$(CONFIG_FB_PNX4008_DUM) += pnx4008/
> diff --git a/drivers/video/s5p_mipi_dsi.c b/drivers/video/s5p_mipi_dsi.c
> new file mode 100644
> index 0000000..50fc00e
> --- /dev/null
> +++ b/drivers/video/s5p_mipi_dsi.c
> @@ -0,0 +1,481 @@
> +/* linux/drivers/video/s5p_mipi_dsi.c
> + *
> + * Samsung SoC MIPI-DSIM driver.
> + *
> + * Copyright (c) 2011 Samsung Electronics Co., Ltd
> + *
> + * InKi Dae, <inki.dae@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/clk.h>
> +#include <linux/mutex.h>
> +#include <linux/wait.h>
> +#include <linux/fs.h>
> +#include <linux/mm.h>
> +#include <linux/fb.h>
> +#include <linux/ctype.h>
> +#include <linux/platform_device.h>
> +#include <linux/io.h>
> +#include <linux/irq.h>
> +#include <linux/memory.h>
> +#include <linux/delay.h>
> +#include <linux/interrupt.h>
> +#include <linux/kthread.h>
> +#include <linux/notifier.h>
> +
> +#include <plat/fb.h>
> +#include <plat/mipi_dsim.h>
> +
> +#include "s5p_mipi_dsi_common.h"
> +
> +#define master_to_driver(a) (a->dsim_lcd_drv)
> +#define master_to_device(a) (a->dsim_lcd_dev)
> +
> +struct mipi_dsim_ddi {
> + int bus_id;
> + struct list_head list;
> + struct mipi_dsim_lcd_device *dsim_lcd_dev;
> + struct mipi_dsim_lcd_driver *dsim_lcd_drv;
> +};
> +
> +static LIST_HEAD(dsim_ddi_list);
> +static LIST_HEAD(dsim_lcd_dev_list);
> +
> +static DEFINE_MUTEX(mipi_dsim_lock);
> +
> +static struct s5p_platform_mipi_dsim *to_dsim_plat(struct platform_device *pdev)
> +{
> + return (struct s5p_platform_mipi_dsim *)pdev->dev.platform_data;
> +}
> +
> +static irqreturn_t s5p_mipi_dsi_interrupt_handler(int irq, void *dev_id)
> +{
> + return IRQ_HANDLED;
> +}
> +
> +int s5p_mipi_dsi_register_lcd_device(struct mipi_dsim_lcd_device *lcd_dev)
> +{
> + struct mipi_dsim_ddi *dsim_ddi;
> +
> + if (!lcd_dev) {
> + printk(KERN_ERR "mipi_dsim_lcd_device is NULL.\n");
> + return -EFAULT;
> + }
> +
> + if (!lcd_dev->name) {
> + printk(KERN_ERR "dsim_lcd_device name is NULL.\n");
> + return -EFAULT;
> + }
> +
> + dsim_ddi = kzalloc(sizeof(struct mipi_dsim_ddi), GFP_KERNEL);
> + if (!dsim_ddi) {
> + printk(KERN_ERR "failed to allocate dsim_ddi object.\n");
> + return -EFAULT;
> + }
> +
> + dsim_ddi->dsim_lcd_dev = lcd_dev;
> +
> + mutex_lock(&mipi_dsim_lock);
> + list_add_tail(&dsim_ddi->list, &dsim_ddi_list);
> + mutex_unlock(&mipi_dsim_lock);
> +
> + return 0;
> +}
> +
> +struct mipi_dsim_ddi
> + *s5p_mipi_dsi_find_lcd_device(struct mipi_dsim_lcd_driver *lcd_drv)
> +{
> + struct mipi_dsim_ddi *dsim_ddi;
> + struct mipi_dsim_lcd_device *lcd_dev;
> +
> + mutex_lock(&mipi_dsim_lock);
> +
> + list_for_each_entry(dsim_ddi, &dsim_ddi_list, list) {
> + lcd_dev = dsim_ddi->dsim_lcd_dev;
> + if (!lcd_dev)
> + continue;
> +
> + if (lcd_drv->id >= 0) {
> + if ((strcmp(lcd_drv->name, lcd_dev->name)) = 0 &&
> + lcd_drv->id = lcd_dev->id) {
> + /**
> + * bus_id would be used to identify
> + * connected bus.
> + */
> + dsim_ddi->bus_id = lcd_dev->bus_id;
> + mutex_unlock(&mipi_dsim_lock);
> +
> + return dsim_ddi;
> + }
> + } else {
> + if ((strcmp(lcd_drv->name, lcd_dev->name)) = 0) {
> + /**
> + * bus_id would be used to identify
> + * connected bus.
> + */
> + dsim_ddi->bus_id = lcd_dev->bus_id;
> + mutex_unlock(&mipi_dsim_lock);
> +
> + return dsim_ddi;
> + }
> + }
> +
> + kfree(dsim_ddi);
> + list_del(&dsim_ddi_list);
> + }
> +
> + mutex_unlock(&mipi_dsim_lock);
> +
> + return NULL;
> +}
> +
> +int s5p_mipi_dsi_register_lcd_driver(struct mipi_dsim_lcd_driver *lcd_drv)
> +{
> + struct mipi_dsim_ddi *dsim_ddi;
> +
> + if (!lcd_drv) {
> + printk(KERN_ERR "mipi_dsim_lcd_driver is NULL.\n");
> + return -EFAULT;
> + }
> +
> + if (!lcd_drv->name) {
> + printk(KERN_ERR "dsim_lcd_driver name is NULL.\n");
> + return -EFAULT;
> + }
> +
> + dsim_ddi = s5p_mipi_dsi_find_lcd_device(lcd_drv);
> + if (!dsim_ddi) {
> + printk(KERN_ERR "mipi_dsim_ddi object not found.\n");
> + return -EFAULT;
> + }
> +
> + dsim_ddi->dsim_lcd_drv = lcd_drv;
> +
> + printk(KERN_INFO "registered panel driver(%s) to mipi-dsi driver.\n",
> + lcd_drv->name);
> +
> + return 0;
> +
> +}
> +
> +struct mipi_dsim_ddi
> + *s5p_mipi_dsi_bind_lcd_ddi(struct mipi_dsim_device *dsim,
> + const char *name)
> +{
> + struct mipi_dsim_ddi *dsim_ddi;
> + struct mipi_dsim_lcd_driver *lcd_drv;
> + struct mipi_dsim_lcd_device *lcd_dev;
> + int ret;
> +
> + mutex_lock(&dsim->lock);
> +
> + list_for_each_entry(dsim_ddi, &dsim_ddi_list, list) {
> + lcd_drv = dsim_ddi->dsim_lcd_drv;
> + lcd_dev = dsim_ddi->dsim_lcd_dev;
> + if (!lcd_drv || !lcd_dev ||
> + (dsim->id != dsim_ddi->bus_id))
> + continue;
> +
> + dev_dbg(dsim->dev, "lcd_drv->id = %d, lcd_dev->id = %d\n",
> + lcd_drv->id, lcd_dev->id);
> + dev_dbg(dsim->dev, "lcd_dev->bus_id = %d, dsim->id = %d\n",
> + lcd_dev->bus_id, dsim->id);
> +
> + if ((strcmp(lcd_drv->name, name) = 0)) {
> + lcd_dev->master = dsim;
> +
> + lcd_dev->dev.parent = dsim->dev;
> + dev_set_name(&lcd_dev->dev, "%s", lcd_drv->name);
> +
> + ret = device_register(&lcd_dev->dev);
> + if (ret < 0) {
> + dev_err(dsim->dev,
> + "can't register %s, status %d\n",
> + dev_name(&lcd_dev->dev), ret);
> + mutex_unlock(&dsim->lock);
> +
> + return NULL;
> + }
> +
> + dsim->dsim_lcd_dev = lcd_dev;
> + dsim->dsim_lcd_drv = lcd_drv;
> +
> + mutex_unlock(&dsim->lock);
> +
> + return dsim_ddi;
> + }
> + }
> +
> + mutex_unlock(&dsim->lock);
> +
> + return NULL;
> +}
> +
> +/* define MIPI-DSI Master operations. */
> +static struct mipi_dsim_master_ops master_ops = {
> + .cmd_write = s5p_mipi_dsi_wr_data,
> + .get_dsim_frame_done = s5p_mipi_dsi_get_frame_done_status,
> + .clear_dsim_frame_done = s5p_mipi_dsi_clear_frame_done,
> +};
> +
> +static int s5p_mipi_dsi_probe(struct platform_device *pdev)
> +{
> + struct resource *res;
> + struct mipi_dsim_device *dsim;
> + struct mipi_dsim_config *dsim_config;
> + struct s5p_platform_mipi_dsim *dsim_pd;
> + struct mipi_dsim_ddi *dsim_ddi;
> + int ret = -1;
> +
> + dsim = kzalloc(sizeof(struct mipi_dsim_device), GFP_KERNEL);
> + if (!dsim) {
> + dev_err(&pdev->dev, "failed to allocate dsim object.\n");
> + return -EFAULT;
> + }
> +
> + dsim->pd = to_dsim_plat(pdev);
> + dsim->dev = &pdev->dev;
> + dsim->id = pdev->id;
> + dsim->resume_complete = 0;
> +
> + /* get s5p_platform_mipi_dsim. */
> + dsim_pd = (struct s5p_platform_mipi_dsim *)dsim->pd;
> + if (dsim_pd = NULL) {
> + dev_err(&pdev->dev, "failed to get platform data for dsim.\n");
> + return -EFAULT;
> + }
> + /* get mipi_dsim_config. */
> + dsim_config = dsim_pd->dsim_config;
> + if (dsim_config = NULL) {
> + dev_err(&pdev->dev, "failed to get dsim config data.\n");
> + return -EFAULT;
> + }
> +
> + dsim->dsim_config = dsim_config;
> + dsim->master_ops = &master_ops;
> +
> + dsim->clock = clk_get(&pdev->dev, "dsim");
> + if (IS_ERR(dsim->clock)) {
> + dev_err(&pdev->dev, "failed to get dsim clock source\n");
> + goto err_clock_get;
> + }
> +
> + clk_enable(dsim->clock);
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + if (!res) {
> + dev_err(&pdev->dev, "failed to get io memory region\n");
> + ret = -EINVAL;
> + goto err_platform_get;
> + }
> +
> + res = request_mem_region(res->start, resource_size(res),
> + dev_name(&pdev->dev));
> + if (!res) {
> + dev_err(&pdev->dev, "failed to request io memory region\n");
> + ret = -EINVAL;
> + goto err_mem_region;
> + }
> +
> + dsim->res = res;
> +
> + dsim->reg_base = ioremap(res->start, resource_size(res));
> + if (!dsim->reg_base) {
> + dev_err(&pdev->dev, "failed to remap io region\n");
> + ret = -EINVAL;
> + goto err_mem_region;
> + }
> +
> + /*
> + * in case of MIPI Video mode,
> + * frame done interrupt handler would be used.
> + */
> + if (dsim_config->e_interface = DSIM_VIDEO) {
> + dsim->irq = platform_get_irq(pdev, 0);
> + if (request_irq(dsim->irq, s5p_mipi_dsi_interrupt_handler,
> + IRQF_DISABLED, "mipi-dsi", dsim)) {
> + dev_err(&pdev->dev, "request_irq failed.\n");
> + goto err_request_irq;
> + }
> + }
> +
> + mutex_init(&dsim->lock);
> +
> + if (dsim->pd->mipi_power)
> + dsim->pd->mipi_power(pdev, 1);
> + else {
> + dev_err(&pdev->dev, "mipi_power is NULL.\n");
> + goto err_request_irq;
> + }
> +
> + /* bind lcd ddi matched with panel name. */
> + dsim_ddi = s5p_mipi_dsi_bind_lcd_ddi(dsim, dsim_pd->lcd_panel_name);
> + if (!dsim_ddi) {
> + dev_err(&pdev->dev, "mipi_dsim_ddi object not found.\n");
> + goto err_bind;
> + }
> +
> + /* enable MIPI-DSI PHY. */
> + if (dsim->pd->phy_enable)
> + dsim->pd->phy_enable(pdev, true);
> +
> + s5p_mipi_dsi_init_dsim(dsim);
> + s5p_mipi_dsi_init_link(dsim);
> +
> + s5p_mipi_dsi_set_hs_enable(dsim);
> +
> + /* set display timing. */
> + s5p_mipi_dsi_set_display_mode(dsim, dsim->dsim_config);
> +
> + platform_set_drvdata(pdev, dsim);
> +
> + /* initialize mipi-dsi client(lcd panel). */
> + if (dsim_ddi->dsim_lcd_drv && dsim_ddi->dsim_lcd_drv->probe)
> + dsim_ddi->dsim_lcd_drv->probe(dsim_ddi->dsim_lcd_dev);
> +
> + dev_dbg(&pdev->dev, "mipi-dsi driver(%s mode) has been probed.\n",
> + (dsim_config->e_interface = DSIM_COMMAND) ?
> + "CPU" : "RGB");
> +
> + return 0;
> +
> +err_bind:
> + dsim->pd->mipi_power(pdev, 0);
> +
> +err_request_irq:
> + release_resource(dsim->res);
> + kfree(dsim->res);
> +
> + iounmap((void __iomem *) dsim->reg_base);
> +
> +err_mem_region:
> +err_platform_get:
> + clk_disable(dsim->clock);
> +
> +err_clock_get:
> + clk_put(dsim->clock);
> + kfree(dsim);
> +
> + return ret;
> +
> +}
> +
> +static int __devexit s5p_mipi_dsi_remove(struct platform_device *pdev)
> +{
> + struct mipi_dsim_device *dsim = platform_get_drvdata(pdev);
> + struct mipi_dsim_ddi *dsim_ddi = NULL;
> +
> + if (dsim->dsim_config->e_interface = DSIM_VIDEO)
> + free_irq(dsim->irq, dsim);
> +
> + iounmap(dsim->reg_base);
> +
> + clk_disable(dsim->clock);
> + clk_put(dsim->clock);
> +
> + release_resource(dsim->res);
> + kfree(dsim->res);
> +
> + list_for_each_entry(dsim_ddi, &dsim_ddi_list, list) {
> + if (dsim_ddi) {
> + if (dsim->id = dsim_ddi->bus_id) {
> + kfree(dsim_ddi);
> + dsim_ddi = NULL;
> + }
> + }
> + }
> +
> + kfree(dsim);
> +
> + return 0;
> +}
> +
> +#ifdef CONFIG_PM
> +static int s5p_mipi_dsi_suspend(struct platform_device *pdev,
> + pm_message_t state)
> +{
> + struct mipi_dsim_device *dsim = platform_get_drvdata(pdev);
> +
> + dsim->resume_complete = 0;
> +
> + if (master_to_driver(dsim) && (master_to_driver(dsim))->suspend)
> + (master_to_driver(dsim))->suspend(master_to_device(dsim));
> +
> + clk_disable(dsim->clock);
> +
> + if (dsim->pd->mipi_power)
> + dsim->pd->mipi_power(pdev, 0);
> +
> + return 0;
> +}
> +
> +static int s5p_mipi_dsi_resume(struct platform_device *pdev)
> +{
> + struct mipi_dsim_device *dsim = platform_get_drvdata(pdev);
> +
> + if (dsim->pd->mipi_power)
> + dsim->pd->mipi_power(pdev, 1);
> +
> + clk_enable(dsim->clock);
> +
> + s5p_mipi_dsi_init_dsim(dsim);
> + s5p_mipi_dsi_init_link(dsim);
> +
> + s5p_mipi_dsi_set_hs_enable(dsim);
> +
> + /* change cpu command transfer mode to hs. */
> + s5p_mipi_dsi_set_data_transfer_mode(dsim, 0);
> +
> + if (master_to_driver(dsim) && (master_to_driver(dsim))->resume)
> + (master_to_driver(dsim))->resume(master_to_device(dsim));
> +
> + s5p_mipi_dsi_set_display_mode(dsim, dsim->dsim_config);
> +
> + /* change lcdc data transfer mode to hs. */
> + s5p_mipi_dsi_set_data_transfer_mode(dsim, 1);
> +
> + dsim->resume_complete = 1;
> +
> + return 0;
> +}
> +#else
> +#define s5p_mipi_dsi_suspend NULL
> +#define s5p_mipi_dsi_resume NULL
> +#endif
> +
> +static struct platform_driver s5p_mipi_dsi_driver = {
> + .probe = s5p_mipi_dsi_probe,
> + .remove = __devexit_p(s5p_mipi_dsi_remove),
> + .suspend = s5p_mipi_dsi_suspend,
> + .resume = s5p_mipi_dsi_resume,
> + .driver = {
> + .name = "s5p-mipi-dsim",
> + .owner = THIS_MODULE,
> + },
> +};
> +
> +static int s5p_mipi_dsi_register(void)
> +{
> + platform_driver_register(&s5p_mipi_dsi_driver);
> +
> + return 0;
> +}
> +
> +static void s5p_mipi_dsi_unregister(void)
> +{
> + platform_driver_unregister(&s5p_mipi_dsi_driver);
> +}
> +
> +module_init(s5p_mipi_dsi_register);
> +module_exit(s5p_mipi_dsi_unregister);
> +
> +MODULE_AUTHOR("InKi Dae <inki.dae@samsung.com>");
> +MODULE_DESCRIPTION("Samusung SoC MIPI-DSI driver");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/video/s5p_mipi_dsi_common.c b/drivers/video/s5p_mipi_dsi_common.c
> new file mode 100644
> index 0000000..51ee4ed
> --- /dev/null
> +++ b/drivers/video/s5p_mipi_dsi_common.c
> @@ -0,0 +1,655 @@
> +/* linux/drivers/video/s5p_mipi_dsi_common.c
> + *
> + * Samsung SoC MIPI-DSI common driver.
> + *
> + * Copyright (c) 2011 Samsung Electronics Co., Ltd
> + *
> + * InKi Dae, <inki.dae@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/fs.h>
> +#include <linux/mm.h>
> +#include <linux/fb.h>
> +#include <linux/ctype.h>
> +#include <linux/platform_device.h>
> +#include <linux/io.h>
> +#include <linux/memory.h>
> +#include <linux/delay.h>
> +#include <linux/kthread.h>
> +
> +#include <video/mipi_display.h>
> +
> +#include <plat/fb.h>
> +#include <plat/regs-dsim.h>
> +
> +#include <mach/map.h>
> +#include <plat/mipi_dsim.h>
> +#include <plat/regs-dsim.h>
> +
> +#include "s5p_mipi_dsi_lowlevel.h"
> +
> +#define MHZ (1000 * 1000)
> +#define FIN_HZ (24 * MHZ)
> +
> +#define DFIN_PLL_MIN_HZ (6 * MHZ)
> +#define DFIN_PLL_MAX_HZ (12 * MHZ)
> +
> +#define DFVCO_MIN_HZ (500 * MHZ)
> +#define DFVCO_MAX_HZ (1000 * MHZ)
> +
> +#define TRY_GET_FIFO_TIMEOUT (5000 * 2)
> +
> +#define DSIM_ESCCLK_ON (0x0)
> +#define DSIM_ESCCLK_OFF (0x1)
> +
> +/* MIPI-DSIM status types. */
> +enum {
> + DSIM_STATE_INIT, /* should be initialized. */
> + DSIM_STATE_STOP, /* CPU and LCDC are LP mode. */
> + DSIM_STATE_HSCLKEN, /* HS clock was enabled. */
> + DSIM_STATE_ULPS
> +};
> +
> +/* define DSI lane types. */
> +enum {
> + DSIM_LANE_CLOCK = (1 << 0),
> + DSIM_LANE_DATA0 = (1 << 1),
> + DSIM_LANE_DATA1 = (1 << 2),
> + DSIM_LANE_DATA2 = (1 << 3),
> + DSIM_LANE_DATA3 = (1 << 4)
> +};
> +
> +static unsigned int dpll_table[15] = {
> + 100, 120, 170, 220, 270,
> + 320, 390, 450, 510, 560,
> + 640, 690, 770, 870, 950 };
> +
> +static void s5p_mipi_dsi_long_data_wr(struct mipi_dsim_device *dsim,
> + unsigned int data0, unsigned int data1)
> +{
> + unsigned int data_cnt = 0, payload = 0;
> +
> + /* in case that data count is more then 4 */
> + for (data_cnt = 0; data_cnt < data1; data_cnt += 4) {
> + /*
> + * after sending 4bytes per one time,
> + * send remainder data less then 4.
> + */
> + if ((data1 - data_cnt) < 4) {
> + if ((data1 - data_cnt) = 3) {
> + payload = *(u8 *)(data0 + data_cnt) |
> + (*(u8 *)(data0 + (data_cnt + 1))) << 8 |
> + (*(u8 *)(data0 + (data_cnt + 2))) << 16;
> + dev_dbg(dsim->dev, "count = 3 payload = %x, %x %x %x\n",
> + payload, *(u8 *)(data0 + data_cnt),
> + *(u8 *)(data0 + (data_cnt + 1)),
> + *(u8 *)(data0 + (data_cnt + 2)));
> + } else if ((data1 - data_cnt) = 2) {
> + payload = *(u8 *)(data0 + data_cnt) |
> + (*(u8 *)(data0 + (data_cnt + 1))) << 8;
> + dev_dbg(dsim->dev,
> + "count = 2 payload = %x, %x %x\n", payload,
> + *(u8 *)(data0 + data_cnt),
> + *(u8 *)(data0 + (data_cnt + 1)));
> + } else if ((data1 - data_cnt) = 1) {
> + payload = *(u8 *)(data0 + data_cnt);
> + }
> +
> + s5p_mipi_dsi_wr_tx_data(dsim, payload);
> + /* send 4bytes per one time. */
> + } else {
> + payload = *(u8 *)(data0 + data_cnt) |
> + (*(u8 *)(data0 + (data_cnt + 1))) << 8 |
> + (*(u8 *)(data0 + (data_cnt + 2))) << 16 |
> + (*(u8 *)(data0 + (data_cnt + 3))) << 24;
> +
> + dev_dbg(dsim->dev,
> + "count = 4 payload = %x, %x %x %x %x\n",
> + payload, *(u8 *)(data0 + data_cnt),
> + *(u8 *)(data0 + (data_cnt + 1)),
> + *(u8 *)(data0 + (data_cnt + 2)),
> + *(u8 *)(data0 + (data_cnt + 3)));
> +
> + s5p_mipi_dsi_wr_tx_data(dsim, payload);
> + }
> + }
> +}
> +
> +int s5p_mipi_dsi_wr_data(struct mipi_dsim_device *dsim, unsigned int data_id,
> + unsigned int data0, unsigned int data1)
> +{
> + unsigned int timeout = TRY_GET_FIFO_TIMEOUT;
> + unsigned long delay_val, udelay;
> + unsigned int check_rx_ack = 0;
> +
> + if (dsim->state = DSIM_STATE_ULPS) {
> + dev_err(dsim->dev, "state is ULPS.\n");
> +
> + return -EINVAL;
> + }
> +
> + delay_val = MHZ / dsim->dsim_config->esc_clk;
> + udelay = 10 * delay_val;
> +
> + mdelay(udelay);
> +
> + /* only if transfer mode is LPDT, wait SFR becomes empty. */
> + if (dsim->state = DSIM_STATE_STOP) {
> + while (!(s5p_mipi_dsi_get_fifo_state(dsim) &
> + SFR_HEADER_EMPTY)) {
> + if ((timeout--) > 0)
> + mdelay(1);
> + else {
> + dev_err(dsim->dev,
> + "SRF header fifo is not empty.\n");
> + return -EINVAL;
> + }
> + }
> + }
> +
> + switch (data_id) {
> + /* short packet types of packet types for command. */
> + case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM:
> + case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM:
> + case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM:
> + case MIPI_DSI_DCS_SHORT_WRITE:
> + case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
> + case MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE:
> + s5p_mipi_dsi_wr_tx_header(dsim, data_id, data0, data1);
> + if (check_rx_ack)
> + /* process response func should be implemented */
> + return 0;
> + else
> + return -EINVAL;
> +
> + /* general command */
> + case MIPI_DSI_COLOR_MODE_OFF:
> + case MIPI_DSI_COLOR_MODE_ON:
> + case MIPI_DSI_SHUTDOWN_PERIPHERAL:
> + case MIPI_DSI_TURN_ON_PERIPHERAL:
> + s5p_mipi_dsi_wr_tx_header(dsim, data_id, data0, data1);
> + if (check_rx_ack)
> + /* process response func should be implemented. */
> + return 0;
> + else
> + return -EINVAL;
> +
> + /* packet types for video data */
> + case MIPI_DSI_V_SYNC_START:
> + case MIPI_DSI_V_SYNC_END:
> + case MIPI_DSI_H_SYNC_START:
> + case MIPI_DSI_H_SYNC_END:
> + case MIPI_DSI_END_OF_TRANSMISSION:
> + return 0;
> +
> + /* short and response packet types for command */
> + case MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM:
> + case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM:
> + case MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM:
> + case MIPI_DSI_DCS_READ:
> + s5p_mipi_dsi_clear_all_interrupt(dsim);
> + s5p_mipi_dsi_wr_tx_header(dsim, data_id, data0, data1);
> + /* process response func should be implemented. */
> + return 0;
> +
> + /* long packet type and null packet */
> + case MIPI_DSI_NULL_PACKET:
> + case MIPI_DSI_BLANKING_PACKET:
> + return 0;
> + case MIPI_DSI_GENERIC_LONG_WRITE:
> + case MIPI_DSI_DCS_LONG_WRITE:
> + {
> + unsigned int size, data_cnt = 0, payload = 0;
> +
> + size = data1 * 4;
> +
> + /* if data count is less then 4, then send 3bytes data. */
> + if (data1 < 4) {
> + payload = *(u8 *)(data0) |
> + *(u8 *)(data0 + 1) << 8 |
> + *(u8 *)(data0 + 2) << 16;
> +
> + s5p_mipi_dsi_wr_tx_data(dsim, payload);
> +
> + dev_dbg(dsim->dev, "count = %d payload = %x,%x %x %x\n",
> + data1, payload,
> + *(u8 *)(data0 + data_cnt),
> + *(u8 *)(data0 + (data_cnt + 1)),
> + *(u8 *)(data0 + (data_cnt + 2)));
> + /* in case that data count is more then 4 */
> + } else
> + s5p_mipi_dsi_long_data_wr(dsim, data0, data1);
> +
> + /* put data into header fifo */
> + s5p_mipi_dsi_wr_tx_header(dsim, data_id, data1 & 0xff,
> + (data1 & 0xff00) >> 8);
> +
> + }
> + if (check_rx_ack)
> + /* process response func should be implemented. */
> + return 0;
> + else
> + return -EINVAL;
> +
> + /* packet typo for video data */
> + case MIPI_DSI_PACKED_PIXEL_STREAM_16:
> + case MIPI_DSI_PACKED_PIXEL_STREAM_18:
> + case MIPI_DSI_PIXEL_STREAM_3BYTE_18:
> + case MIPI_DSI_PACKED_PIXEL_STREAM_24:
> + if (check_rx_ack)
> + /* process response func should be implemented. */
> + return 0;
> + else
> + return -EINVAL;
> + default:
> + dev_warn(dsim->dev,
> + "data id %x is not supported current DSI spec.\n",
> + data_id);
> +
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
> +int s5p_mipi_dsi_pll_on(struct mipi_dsim_device *dsim, unsigned int enable)
> +{
> + int sw_timeout;
> +
> + if (enable) {
> + sw_timeout = 1000;
> +
> + s5p_mipi_dsi_clear_interrupt(dsim);
> + s5p_mipi_dsi_enable_pll(dsim, 1);
> + while (1) {
> + sw_timeout--;
> + if (s5p_mipi_dsi_is_pll_stable(dsim))
> + return 0;
> + if (sw_timeout = 0)
> + return -EINVAL;
> + }
> + } else
> + s5p_mipi_dsi_enable_pll(dsim, 0);
> +
> + return 0;
> +}
> +
> +unsigned long s5p_mipi_dsi_change_pll(struct mipi_dsim_device *dsim,
> + unsigned int pre_divider, unsigned int main_divider,
> + unsigned int scaler)
> +{
> + unsigned long dfin_pll, dfvco, dpll_out;
> + unsigned int i, freq_band = 0xf;
> +
> + dfin_pll = (FIN_HZ / pre_divider);
> +
> + /******************************************************
> + * Serial Clock(=ByteClk X 8) FreqBand[3:0] *
> + ******************************************************
> + * ~ 99.99 MHz 0000
> + * 100 ~ 119.99 MHz 0001
> + * 120 ~ 159.99 MHz 0010
> + * 160 ~ 199.99 MHz 0011
> + * 200 ~ 239.99 MHz 0100
> + * 140 ~ 319.99 MHz 0101
> + * 320 ~ 389.99 MHz 0110
> + * 390 ~ 449.99 MHz 0111
> + * 450 ~ 509.99 MHz 1000
> + * 510 ~ 559.99 MHz 1001
> + * 560 ~ 639.99 MHz 1010
> + * 640 ~ 689.99 MHz 1011
> + * 690 ~ 769.99 MHz 1100
> + * 770 ~ 869.99 MHz 1101
> + * 870 ~ 949.99 MHz 1110
> + * 950 ~ 1000 MHz 1111
> + ******************************************************/
> + if (dfin_pll < DFIN_PLL_MIN_HZ || dfin_pll > DFIN_PLL_MAX_HZ) {
> + dev_warn(dsim->dev, "fin_pll range should be 6MHz ~ 12MHz\n");
> + s5p_mipi_dsi_enable_afc(dsim, 0, 0);
> + } else {
> + if (dfin_pll < 7 * MHZ)
> + s5p_mipi_dsi_enable_afc(dsim, 1, 0x1);
> + else if (dfin_pll < 8 * MHZ)
> + s5p_mipi_dsi_enable_afc(dsim, 1, 0x0);
> + else if (dfin_pll < 9 * MHZ)
> + s5p_mipi_dsi_enable_afc(dsim, 1, 0x3);
> + else if (dfin_pll < 10 * MHZ)
> + s5p_mipi_dsi_enable_afc(dsim, 1, 0x2);
> + else if (dfin_pll < 11 * MHZ)
> + s5p_mipi_dsi_enable_afc(dsim, 1, 0x5);
> + else
> + s5p_mipi_dsi_enable_afc(dsim, 1, 0x4);
> + }
> +
> + dfvco = dfin_pll * main_divider;
> + dev_dbg(dsim->dev, "dfvco = %lu, dfin_pll = %lu, main_divider = %d\n",
> + dfvco, dfin_pll, main_divider);
> + if (dfvco < DFVCO_MIN_HZ || dfvco > DFVCO_MAX_HZ)
> + dev_warn(dsim->dev, "fvco range should be 500MHz ~ 1000MHz\n");
> +
> + dpll_out = dfvco / (1 << scaler);
> + dev_dbg(dsim->dev, "dpll_out = %lu, dfvco = %lu, scaler = %d\n",
> + dpll_out, dfvco, scaler);
> +
> + for (i = 0; i < ARRAY_SIZE(dpll_table); i++) {
> + if (dpll_out < dpll_table[i] * MHZ) {
> + freq_band = i;
> + break;
> + }
> + }
> +
> + dev_dbg(dsim->dev, "freq_band = %d\n", freq_band);
> +
> + s5p_mipi_dsi_pll_freq(dsim, pre_divider, main_divider, scaler);
> +
> + s5p_mipi_dsi_hs_zero_ctrl(dsim, 0);
> + s5p_mipi_dsi_prep_ctrl(dsim, 0);
> +
> + /* Freq Band */
> + s5p_mipi_dsi_pll_freq_band(dsim, freq_band);
> +
> + /* Stable time */
> + s5p_mipi_dsi_pll_stable_time(dsim, dsim->dsim_config->pll_stable_time);
> +
> + /* Enable PLL */
> + dev_dbg(dsim->dev, "FOUT of mipi dphy pll is %luMHz\n",
> + (dpll_out / MHZ));
> +
> + return dpll_out;
> +}
> +
> +int s5p_mipi_dsi_set_clock(struct mipi_dsim_device *dsim,
> + unsigned int byte_clk_sel, unsigned int enable)
> +{
> + unsigned int esc_div;
> + unsigned long esc_clk_error_rate;
> + unsigned long hs_clk = 0, byte_clk = 0, escape_clk = 0;
> +
> + if (enable) {
> + dsim->e_clk_src = byte_clk_sel;
> +
> + /* Escape mode clock and byte clock source */
> + s5p_mipi_dsi_set_byte_clock_src(dsim, byte_clk_sel);
> +
> + /* DPHY, DSIM Link : D-PHY clock out */
> + if (byte_clk_sel = DSIM_PLL_OUT_DIV8) {
> + hs_clk = s5p_mipi_dsi_change_pll(dsim,
> + dsim->dsim_config->p, dsim->dsim_config->m,
> + dsim->dsim_config->s);
> + if (hs_clk = 0) {
> + dev_err(dsim->dev,
> + "failed to get hs clock.\n");
> + return -EINVAL;
> + }
> +
> + byte_clk = hs_clk / 8;
> + s5p_mipi_dsi_enable_pll_bypass(dsim, 0);
> + s5p_mipi_dsi_pll_on(dsim, 1);
> + /* DPHY : D-PHY clock out, DSIM link : external clock out */
> + } else if (byte_clk_sel = DSIM_EXT_CLK_DIV8)
> + dev_warn(dsim->dev,
> + "this project is not support \
> + external clock source for MIPI DSIM\n");
> + else if (byte_clk_sel = DSIM_EXT_CLK_BYPASS)
> + dev_warn(dsim->dev,
> + "this project is not support \
> + external clock source for MIPI DSIM\n");
> +
> + /* escape clock divider */
> + esc_div = byte_clk / (dsim->dsim_config->esc_clk);
> + dev_dbg(dsim->dev,
> + "esc_div = %d, byte_clk = %lu, esc_clk = %lu\n",
> + esc_div, byte_clk, dsim->dsim_config->esc_clk);
> + if ((byte_clk / esc_div) >= (20 * MHZ) ||
> + (byte_clk / esc_div) >
> + dsim->dsim_config->esc_clk)
> + esc_div += 1;
> +
> + escape_clk = byte_clk / esc_div;
> + dev_dbg(dsim->dev,
> + "escape_clk = %lu, byte_clk = %lu, esc_div = %d\n",
> + escape_clk, byte_clk, esc_div);
> +
> + /* enable escape clock. */
> + s5p_mipi_dsi_enable_byte_clock(dsim, DSIM_ESCCLK_ON);
> +
> + /* enable byte clk and escape clock */
> + s5p_mipi_dsi_set_esc_clk_prs(dsim, 1, esc_div);
> + /* escape clock on lane */
> + s5p_mipi_dsi_enable_esc_clk_on_lane(dsim,
> + (DSIM_LANE_CLOCK | dsim->data_lane), 1);
> +
> + dev_dbg(dsim->dev, "byte clock is %luMHz\n",
> + (byte_clk / MHZ));
> + dev_dbg(dsim->dev, "escape clock that user's need is %lu\n",
> + (dsim->dsim_config->esc_clk / MHZ));
> + dev_dbg(dsim->dev, "escape clock divider is %x\n", esc_div);
> + dev_dbg(dsim->dev, "escape clock is %luMHz\n",
> + ((byte_clk / esc_div) / MHZ));
> +
> + if ((byte_clk / esc_div) > escape_clk) {
> + esc_clk_error_rate = escape_clk /
> + (byte_clk / esc_div);
> + dev_warn(dsim->dev, "error rate is %lu over.\n",
> + (esc_clk_error_rate / 100));
> + } else if ((byte_clk / esc_div) < (escape_clk)) {
> + esc_clk_error_rate = (byte_clk / esc_div) /
> + escape_clk;
> + dev_warn(dsim->dev, "error rate is %lu under.\n",
> + (esc_clk_error_rate / 100));
> + }
> + } else {
> + s5p_mipi_dsi_enable_esc_clk_on_lane(dsim,
> + (DSIM_LANE_CLOCK | dsim->data_lane), 0);
> + s5p_mipi_dsi_set_esc_clk_prs(dsim, 0, 0);
> +
> + /* disable escape clock. */
> + s5p_mipi_dsi_enable_byte_clock(dsim, DSIM_ESCCLK_OFF);
> +
> + if (byte_clk_sel = DSIM_PLL_OUT_DIV8)
> + s5p_mipi_dsi_pll_on(dsim, 0);
> + }
> +
> + return 0;
> +}
> +
> +int s5p_mipi_dsi_init_dsim(struct mipi_dsim_device *dsim)
> +{
> + dsim->state = DSIM_STATE_INIT;
> +
> + switch (dsim->dsim_config->e_no_data_lane) {
> + case DSIM_DATA_LANE_1:
> + dsim->data_lane = DSIM_LANE_DATA0;
> + break;
> + case DSIM_DATA_LANE_2:
> + dsim->data_lane = DSIM_LANE_DATA0 | DSIM_LANE_DATA1;
> + break;
> + case DSIM_DATA_LANE_3:
> + dsim->data_lane = DSIM_LANE_DATA0 | DSIM_LANE_DATA1 |
> + DSIM_LANE_DATA2;
> + break;
> + case DSIM_DATA_LANE_4:
> + dsim->data_lane = DSIM_LANE_DATA0 | DSIM_LANE_DATA1 |
> + DSIM_LANE_DATA2 | DSIM_LANE_DATA3;
> + break;
> + default:
> + dev_info(dsim->dev, "data lane is invalid.\n");
> + return -EINVAL;
> + };
> +
> + s5p_mipi_dsi_sw_reset(dsim);
> + s5p_mipi_dsi_dp_dn_swap(dsim, 0);
> +
> + return 0;
> +}
> +
> +int s5p_mipi_dsi_enable_frame_done_int(struct mipi_dsim_device *dsim,
> + unsigned int enable)
> +{
> + /* enable only frame done interrupt */
> + s5p_mipi_dsi_set_interrupt_mask(dsim, INTMSK_FRAME_DONE, enable);
> +
> + return 0;
> +}
> +
> +int s5p_mipi_dsi_set_display_mode(struct mipi_dsim_device *dsim,
> + struct mipi_dsim_config *dsim_config)
> +{
> + struct s5p_platform_mipi_dsim *dsim_pd;
> + struct fb_videomode *lcd_video = NULL;
> +
> + dsim_pd = (struct s5p_platform_mipi_dsim *)dsim->pd;
> + lcd_video = (struct fb_videomode *)dsim_pd->lcd_panel_info;
> +
> + /* in case of VIDEO MODE (RGB INTERFACE), it sets polarities. */
> + if (dsim->dsim_config->e_interface = (u32) DSIM_VIDEO) {
> + if (dsim->dsim_config->auto_vertical_cnt = 0) {
> + s5p_mipi_dsi_set_main_disp_vporch(dsim,
> + lcd_video->upper_margin,
> + lcd_video->lower_margin, 0);
> + s5p_mipi_dsi_set_main_disp_hporch(dsim,
> + lcd_video->left_margin,
> + lcd_video->right_margin);
> + s5p_mipi_dsi_set_main_disp_sync_area(dsim,
> + lcd_video->vsync_len,
> + lcd_video->hsync_len);
> + }
> + }
> +
> + s5p_mipi_dsi_set_main_disp_resol(dsim, lcd_video->xres,
> + lcd_video->yres);
> +
> + s5p_mipi_dsi_display_config(dsim, dsim->dsim_config);
> +
> + dev_dbg(dsim->dev, "lcd panel => width = %d, height = %d\n",
> + lcd_video->xres, lcd_video->yres);
> +
> + return 0;
> +}
> +
> +int s5p_mipi_dsi_init_link(struct mipi_dsim_device *dsim)
> +{
> + unsigned int time_out = 100;
> +
> + switch (dsim->state) {
> + case DSIM_STATE_INIT:
> + s5p_mipi_dsi_sw_reset(dsim);
> +
> + s5p_mipi_dsi_init_fifo_pointer(dsim, 0x1f);
> +
> + /* dsi configuration */
> + s5p_mipi_dsi_init_config(dsim);
> + s5p_mipi_dsi_enable_lane(dsim, DSIM_LANE_CLOCK, 1);
> + s5p_mipi_dsi_enable_lane(dsim, dsim->data_lane, 1);
> +
> + /* set clock configuration */
> + s5p_mipi_dsi_set_clock(dsim, dsim->dsim_config->e_byte_clk, 1);
> +
> + /* check clock and data lane state are stop state */
> + while (!(s5p_mipi_dsi_is_lane_state(dsim))) {
> + time_out--;
> + if (time_out = 0) {
> + dev_err(dsim->dev,
> + "DSI Master is not stop state.\n");
> + dev_err(dsim->dev,
> + "Check initialization process\n");
> +
> + return -EINVAL;
> + }
> + }
> +
> + if (time_out != 0) {
> + dev_info(dsim->dev,
> + "DSI Master driver has been completed.\n");
> + dev_info(dsim->dev, "DSI Master state is stop state\n");
> + }
> +
> + dsim->state = DSIM_STATE_STOP;
> +
> + /* BTA sequence counters */
> + s5p_mipi_dsi_set_stop_state_counter(dsim,
> + dsim->dsim_config->stop_holding_cnt);
> + s5p_mipi_dsi_set_bta_timeout(dsim,
> + dsim->dsim_config->bta_timeout);
> + s5p_mipi_dsi_set_lpdr_timeout(dsim,
> + dsim->dsim_config->rx_timeout);
> +
> + return 0;
> + default:
> + dev_info(dsim->dev, "DSI Master is already init.\n");
> + return 0;
> + }
> +
> + return 0;
> +}
> +
> +int s5p_mipi_dsi_set_hs_enable(struct mipi_dsim_device *dsim)
> +{
> + if (dsim->state = DSIM_STATE_STOP) {
> + if (dsim->e_clk_src != DSIM_EXT_CLK_BYPASS) {
> + dsim->state = DSIM_STATE_HSCLKEN;
> +
> + /* set LCDC and CPU transfer mode to HS. */
> + s5p_mipi_dsi_set_lcdc_transfer_mode(dsim, 0);
> + s5p_mipi_dsi_set_cpu_transfer_mode(dsim, 0);
> +
> + s5p_mipi_dsi_enable_hs_clock(dsim, 1);
> +
> + return 0;
> + } else
> + dev_warn(dsim->dev,
> + "clock source is external bypass.\n");
> + } else
> + dev_warn(dsim->dev, "DSIM is not stop state.\n");
> +
> + return 0;
> +}
> +
> +int s5p_mipi_dsi_set_data_transfer_mode(struct mipi_dsim_device *dsim,
> + unsigned int mode)
> +{
> + if (mode) {
> + if (dsim->state != DSIM_STATE_HSCLKEN) {
> + dev_err(dsim->dev, "HS Clock lane is not enabled.\n");
> + return -EINVAL;
> + }
> +
> + s5p_mipi_dsi_set_lcdc_transfer_mode(dsim, 0);
> + } else {
> + if (dsim->state = DSIM_STATE_INIT || dsim->state =
> + DSIM_STATE_ULPS) {
> + dev_err(dsim->dev,
> + "DSI Master is not STOP or HSDT state.\n");
> + return -EINVAL;
> + }
> +
> + s5p_mipi_dsi_set_cpu_transfer_mode(dsim, 0);
> + }
> +
> + return 0;
> +}
> +
> +int s5p_mipi_dsi_get_frame_done_status(struct mipi_dsim_device *dsim)
> +{
> + return _s5p_mipi_dsi_get_frame_done_status(dsim);
> +}
> +
> +int s5p_mipi_dsi_clear_frame_done(struct mipi_dsim_device *dsim)
> +{
> + _s5p_mipi_dsi_clear_frame_done(dsim);
> +
> + return 0;
> +}
> +
> +MODULE_AUTHOR("InKi Dae <inki.dae@samsung.com>");
> +MODULE_DESCRIPTION("Samusung MIPI-DSIM common driver");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/video/s5p_mipi_dsi_common.h b/drivers/video/s5p_mipi_dsi_common.h
> new file mode 100644
> index 0000000..5ade1d6
> --- /dev/null
> +++ b/drivers/video/s5p_mipi_dsi_common.h
> @@ -0,0 +1,39 @@
> +/* linux/drivers/video/s5p_mipi_dsi_common.h
> + *
> + * Header file for Samsung SoC MIPI-DSI common driver.
> + *
> + * Copyright (c) 2011 Samsung Electronics Co., Ltd
> + *
> + * InKi Dae <inki.dae@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.
> +*/
> +
> +#ifndef _S5P_MIPI_DSI_COMMON_H
> +#define _S5P_MIPI_DSI_COMMON_H
> +
> +int s5p_mipi_dsi_wr_data(struct mipi_dsim_device *dsim, unsigned int data_id,
> + unsigned int data0, unsigned int data1);
> +int s5p_mipi_dsi_pll_on(struct mipi_dsim_device *dsim, unsigned int enable);
> +unsigned long s5p_mipi_dsi_change_pll(struct mipi_dsim_device *dsim,
> + unsigned int pre_divider, unsigned int main_divider,
> + unsigned int scaler);
> +int s5p_mipi_dsi_set_clock(struct mipi_dsim_device *dsim,
> + unsigned int byte_clk_sel, unsigned int enable);
> +int s5p_mipi_dsi_init_dsim(struct mipi_dsim_device *dsim);
> +int s5p_mipi_dsi_set_display_mode(struct mipi_dsim_device *dsim,
> + struct mipi_dsim_config *dsim_info);
> +int s5p_mipi_dsi_init_link(struct mipi_dsim_device *dsim);
> +int s5p_mipi_dsi_set_hs_enable(struct mipi_dsim_device *dsim);
> +int s5p_mipi_dsi_set_data_transfer_mode(struct mipi_dsim_device *dsim,
> + unsigned int mode);
> +int s5p_mipi_dsi_enable_frame_done_int(struct mipi_dsim_device *dsim,
> + unsigned int enable);
> +int s5p_mipi_dsi_get_frame_done_status(struct mipi_dsim_device *dsim);
> +int s5p_mipi_dsi_clear_frame_done(struct mipi_dsim_device *dsim);
> +
> +extern struct fb_info *registered_fb[FB_MAX] __read_mostly;
> +
> +#endif /* _S5P_MIPI_DSI_COMMON_H */
> diff --git a/drivers/video/s5p_mipi_dsi_lowlevel.c b/drivers/video/s5p_mipi_dsi_lowlevel.c
> new file mode 100644
> index 0000000..86d2881
> --- /dev/null
> +++ b/drivers/video/s5p_mipi_dsi_lowlevel.c
> @@ -0,0 +1,558 @@
> +/* linux/drivers/video/s5p_mipi_dsi_lowlevel.c
> + *
> + * Samsung SoC MIPI-DSI lowlevel driver.
> + *
> + * Copyright (c) 2011 Samsung Electronics Co., Ltd
> + *
> + * InKi Dae, <inki.dae@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/delay.h>
> +#include <linux/fs.h>
> +#include <linux/mm.h>
> +#include <linux/ctype.h>
> +#include <linux/io.h>
> +
> +#include <mach/map.h>
> +
> +#include <plat/mipi_dsim.h>
> +#include <plat/regs-dsim.h>
> +
> +void s5p_mipi_dsi_func_reset(struct mipi_dsim_device *dsim)
> +{
> + unsigned int reg;
> +
> + reg = readl(dsim->reg_base + S5P_DSIM_SWRST);
> +
> + reg |= DSIM_FUNCRST;
> +
> + writel(reg, dsim->reg_base + S5P_DSIM_SWRST);
> +}
> +
> +void s5p_mipi_dsi_sw_reset(struct mipi_dsim_device *dsim)
> +{
> + unsigned int reg;
> +
> + reg = readl(dsim->reg_base + S5P_DSIM_SWRST);
> +
> + reg |= DSIM_SWRST;
> +
> + writel(reg, dsim->reg_base + S5P_DSIM_SWRST);
> +}
> +
> +void s5p_mipi_dsi_set_interrupt_mask(struct mipi_dsim_device *dsim,
> + unsigned int mode, unsigned int mask)
> +{
> + unsigned int reg = readl(dsim->reg_base + S5P_DSIM_INTMSK);
> +
> + if (mask)
> + reg |= mode;
> + else
> + reg &= ~mode;
> +
> + writel(reg, dsim->reg_base + S5P_DSIM_INTMSK);
> +}
> +
> +void s5p_mipi_dsi_init_fifo_pointer(struct mipi_dsim_device *dsim,
> + unsigned int cfg)
> +{
> + unsigned int reg;
> +
> + reg = readl(dsim->reg_base + S5P_DSIM_FIFOCTRL);
> +
> + writel(reg & ~(cfg), dsim->reg_base + S5P_DSIM_FIFOCTRL);
> + mdelay(10);
> + reg |= cfg;
> +
> + writel(reg, dsim->reg_base + S5P_DSIM_FIFOCTRL);
> +}
> +
> +/*
> + * this function set PLL P, M and S value in D-PHY
> + */
> +void s5p_mipi_dsi_set_phy_tunning(struct mipi_dsim_device *dsim,
> + unsigned int value)
> +{
> + writel(DSIM_AFC_CTL(value), dsim->reg_base + S5P_DSIM_PHYACCHR);
> +}
> +
> +void s5p_mipi_dsi_set_main_disp_resol(struct mipi_dsim_device *dsim,
> + unsigned int width_resol, unsigned int height_resol)
> +{
> + unsigned int reg;
> +
> + /* standby should be set after configuration so set to not ready*/
> + reg = (readl(dsim->reg_base + S5P_DSIM_MDRESOL)) &
> + ~(DSIM_MAIN_STAND_BY);
> + writel(reg, dsim->reg_base + S5P_DSIM_MDRESOL);
> +
> + reg &= ~(0x7ff << 16) & ~(0x7ff << 0);
> + reg |= DSIM_MAIN_VRESOL(height_resol) | DSIM_MAIN_HRESOL(width_resol);
> +
> + reg |= DSIM_MAIN_STAND_BY;
> + writel(reg, dsim->reg_base + S5P_DSIM_MDRESOL);
> +}
> +
> +void s5p_mipi_dsi_set_main_disp_vporch(struct mipi_dsim_device *dsim,
> + unsigned int cmd_allow, unsigned int vfront, unsigned int vback)
> +{
> + unsigned int reg;
> +
> + reg = (readl(dsim->reg_base + S5P_DSIM_MVPORCH)) &
> + ~(DSIM_CMD_ALLOW_MASK) & ~(DSIM_STABLE_VFP_MASK) &
> + ~(DSIM_MAIN_VBP_MASK);
> +
> + reg |= ((cmd_allow & 0xf) << DSIM_CMD_ALLOW_SHIFT) |
> + ((vfront & 0x7ff) << DSIM_STABLE_VFP_SHIFT) |
> + ((vback & 0x7ff) << DSIM_MAIN_VBP_SHIFT);
> +
> + writel(reg, dsim->reg_base + S5P_DSIM_MVPORCH);
> +}
> +
> +void s5p_mipi_dsi_set_main_disp_hporch(struct mipi_dsim_device *dsim,
> + unsigned int front, unsigned int back)
> +{
> + unsigned int reg;
> +
> + reg = (readl(dsim->reg_base + S5P_DSIM_MHPORCH)) &
> + ~(DSIM_MAIN_HFP_MASK) & ~(DSIM_MAIN_HBP_MASK);
> +
> + reg |= (front << DSIM_MAIN_HFP_SHIFT) | (back << DSIM_MAIN_HBP_SHIFT);
> +
> + writel(reg, dsim->reg_base + S5P_DSIM_MHPORCH);
> +}
> +
> +void s5p_mipi_dsi_set_main_disp_sync_area(struct mipi_dsim_device *dsim,
> + unsigned int vert, unsigned int hori)
> +{
> + unsigned int reg;
> +
> + reg = (readl(dsim->reg_base + S5P_DSIM_MSYNC)) &
> + ~(DSIM_MAIN_VSA_MASK) & ~(DSIM_MAIN_HSA_MASK);
> +
> + reg |= ((vert & 0x3ff) << DSIM_MAIN_VSA_SHIFT) |
> + (hori << DSIM_MAIN_HSA_SHIFT);
> +
> + writel(reg, dsim->reg_base + S5P_DSIM_MSYNC);
> +}
> +
> +void s5p_mipi_dsi_set_sub_disp_resol(struct mipi_dsim_device *dsim,
> + unsigned int vert, unsigned int hori)
> +{
> + unsigned int reg;
> +
> + reg = (readl(dsim->reg_base + S5P_DSIM_SDRESOL)) &
> + ~(DSIM_SUB_STANDY_MASK);
> +
> + writel(reg, dsim->reg_base + S5P_DSIM_SDRESOL);
> +
> + reg &= ~(DSIM_SUB_VRESOL_MASK) | ~(DSIM_SUB_HRESOL_MASK);
> + reg |= ((vert & 0x7ff) << DSIM_SUB_VRESOL_SHIFT) |
> + ((hori & 0x7ff) << DSIM_SUB_HRESOL_SHIFT);
> + writel(reg, dsim->reg_base + S5P_DSIM_SDRESOL);
> +
> + reg |= (1 << DSIM_SUB_STANDY_SHIFT);
> + writel(reg, dsim->reg_base + S5P_DSIM_SDRESOL);
> +}
> +
> +void s5p_mipi_dsi_init_config(struct mipi_dsim_device *dsim)
> +{
> + struct mipi_dsim_config *dsim_config = dsim->dsim_config;
> +
> + unsigned int cfg = (readl(dsim->reg_base + S5P_DSIM_CONFIG)) &
> + ~(1 << 28) & ~(0x1f << 20) & ~(0x3 << 5);
> +
> + cfg = (dsim_config->auto_flush << 29) |
> + (dsim_config->eot_disable << 28) |
> + (dsim_config->auto_vertical_cnt << DSIM_AUTO_MODE_SHIFT) |
> + (dsim_config->hse << DSIM_HSE_MODE_SHIFT) |
> + (dsim_config->hfp << DSIM_HFP_MODE_SHIFT) |
> + (dsim_config->hbp << DSIM_HBP_MODE_SHIFT) |
> + (dsim_config->hsa << DSIM_HSA_MODE_SHIFT) |
> + (dsim_config->e_no_data_lane << DSIM_NUM_OF_DATALANE_SHIFT);
> +
> + writel(cfg, dsim->reg_base + S5P_DSIM_CONFIG);
> +}
> +
> +void s5p_mipi_dsi_display_config(struct mipi_dsim_device *dsim,
> + struct mipi_dsim_config *dsim_config)
> +{
> + u32 reg = (readl(dsim->reg_base + S5P_DSIM_CONFIG)) &
> + ~(0x3 << 26) & ~(1 << 25) & ~(0x3 << 18) & ~(0x7 << 12) &
> + ~(0x3 << 16) & ~(0x7 << 8);
> +
> + if (dsim_config->e_interface = DSIM_VIDEO)
> + reg |= (1 << 25);
> + else if (dsim_config->e_interface = DSIM_COMMAND)
> + reg &= ~(1 << 25);
> + else {
> + dev_err(dsim->dev, "this ddi is not MIPI interface.\n");
> + return;
> + }
> +
> + /* main lcd */
> + reg |= ((u8) (dsim_config->e_burst_mode) & 0x3) << 26 |
> + ((u8) (dsim_config->e_virtual_ch) & 0x3) << 18 |
> + ((u8) (dsim_config->e_pixel_format) & 0x7) << 12;
> +
> + writel(reg, dsim->reg_base + S5P_DSIM_CONFIG);
> +}
> +
> +void s5p_mipi_dsi_enable_lane(struct mipi_dsim_device *dsim, unsigned int lane,
> + unsigned int enable)
> +{
> + unsigned int reg;
> +
> + reg = readl(dsim->reg_base + S5P_DSIM_CONFIG);
> +
> + if (enable)
> + reg |= DSIM_LANE_ENx(lane);
> + else
> + reg &= ~DSIM_LANE_ENx(lane);
> +
> + writel(reg, dsim->reg_base + S5P_DSIM_CONFIG);
> +}
> +
> +
> +void s5p_mipi_dsi_set_data_lane_number(struct mipi_dsim_device *dsim,
> + unsigned int count)
> +{
> + unsigned int cfg;
> +
> + /* get the data lane number. */
> + cfg = DSIM_NUM_OF_DATA_LANE(count);
> +
> + writel(cfg, dsim->reg_base + S5P_DSIM_CONFIG);
> +}
> +
> +void s5p_mipi_dsi_enable_afc(struct mipi_dsim_device *dsim, unsigned int enable,
> + unsigned int afc_code)
> +{
> + unsigned int reg = readl(dsim->reg_base + S5P_DSIM_PHYACCHR);
> +
> + if (enable) {
> + reg |= (1 << 14);
> + reg &= ~(0x7 << 5);
> + reg |= (afc_code & 0x7) << 5;
> + } else
> + reg &= ~(1 << 14);
> +
> + writel(reg, dsim->reg_base + S5P_DSIM_PHYACCHR);
> +}
> +
> +void s5p_mipi_dsi_enable_pll_bypass(struct mipi_dsim_device *dsim,
> + unsigned int enable)
> +{
> + unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_CLKCTRL)) &
> + ~(DSIM_PLL_BYPASS_EXTERNAL);
> +
> + reg |= enable << DSIM_PLL_BYPASS_SHIFT;
> +
> + writel(reg, dsim->reg_base + S5P_DSIM_CLKCTRL);
> +}
> +
> +void s5p_mipi_dsi_set_pll_pms(struct mipi_dsim_device *dsim, unsigned int p,
> + unsigned int m, unsigned int s)
> +{
> + unsigned int reg = readl(dsim->reg_base + S5P_DSIM_PLLCTRL);
> +
> + reg |= ((p & 0x3f) << 13) | ((m & 0x1ff) << 4) | ((s & 0x7) << 1);
> +
> + writel(reg, dsim->reg_base + S5P_DSIM_PLLCTRL);
> +}
> +
> +void s5p_mipi_dsi_pll_freq_band(struct mipi_dsim_device *dsim,
> + unsigned int freq_band)
> +{
> + unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_PLLCTRL)) &
> + ~(0x1f << DSIM_FREQ_BAND_SHIFT);
> +
> + reg |= ((freq_band & 0x1f) << DSIM_FREQ_BAND_SHIFT);
> +
> + writel(reg, dsim->reg_base + S5P_DSIM_PLLCTRL);
> +}
> +
> +void s5p_mipi_dsi_pll_freq(struct mipi_dsim_device *dsim,
> + unsigned int pre_divider, unsigned int main_divider,
> + unsigned int scaler)
> +{
> + unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_PLLCTRL)) &
> + ~(0x7ffff << 1);
> +
> + reg |= (pre_divider & 0x3f) << 13 | (main_divider & 0x1ff) << 4 |
> + (scaler & 0x7) << 1;
> +
> + writel(reg, dsim->reg_base + S5P_DSIM_PLLCTRL);
> +}
> +
> +void s5p_mipi_dsi_pll_stable_time(struct mipi_dsim_device *dsim,
> + unsigned int lock_time)
> +{
> + writel(lock_time, dsim->reg_base + S5P_DSIM_PLLTMR);
> +}
> +
> +void s5p_mipi_dsi_enable_pll(struct mipi_dsim_device *dsim, unsigned int enable)
> +{
> + unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_PLLCTRL)) &
> + ~(0x1 << DSIM_PLL_EN_SHIFT);
> +
> + reg |= ((enable & 0x1) << DSIM_PLL_EN_SHIFT);
> +
> + writel(reg, dsim->reg_base + S5P_DSIM_PLLCTRL);
> +}
> +
> +void s5p_mipi_dsi_set_byte_clock_src(struct mipi_dsim_device *dsim,
> + unsigned int src)
> +{
> + unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_CLKCTRL)) &
> + ~(0x3 << DSIM_BYTE_CLK_SRC_SHIFT);
> +
> + reg |= ((unsigned int) src) << DSIM_BYTE_CLK_SRC_SHIFT;
> +
> + writel(reg, dsim->reg_base + S5P_DSIM_CLKCTRL);
> +}
> +
> +void s5p_mipi_dsi_enable_byte_clock(struct mipi_dsim_device *dsim,
> + unsigned int enable)
> +{
> + unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_CLKCTRL)) &
> + ~(1 << DSIM_BYTE_CLKEN_SHIFT);
> +
> + reg |= enable << DSIM_BYTE_CLKEN_SHIFT;
> +
> + writel(reg, dsim->reg_base + S5P_DSIM_CLKCTRL);
> +}
> +
> +void s5p_mipi_dsi_set_esc_clk_prs(struct mipi_dsim_device *dsim,
> + unsigned int enable, unsigned int prs_val)
> +{
> + unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_CLKCTRL)) &
> + ~(1 << DSIM_ESC_CLKEN_SHIFT) & ~(0xffff);
> +
> + reg |= enable << DSIM_ESC_CLKEN_SHIFT;
> + if (enable)
> + reg |= prs_val;
> +
> + writel(reg, dsim->reg_base + S5P_DSIM_CLKCTRL);
> +}
> +
> +void s5p_mipi_dsi_enable_esc_clk_on_lane(struct mipi_dsim_device *dsim,
> + unsigned int lane_sel, unsigned int enable)
> +{
> + unsigned int reg = readl(dsim->reg_base + S5P_DSIM_CLKCTRL);
> +
> + if (enable)
> + reg |= DSIM_LANE_ESC_CLKEN(lane_sel);
> + else
> +
> + reg &= ~DSIM_LANE_ESC_CLKEN(lane_sel);
> +
> + writel(reg, dsim->reg_base + S5P_DSIM_CLKCTRL);
> +}
> +
> +void s5p_mipi_dsi_force_dphy_stop_state(struct mipi_dsim_device *dsim,
> + unsigned int enable)
> +{
> + unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_ESCMODE)) &
> + ~(0x1 << DSIM_FORCE_STOP_STATE_SHIFT);
> +
> + reg |= ((enable & 0x1) << DSIM_FORCE_STOP_STATE_SHIFT);
> +
> + writel(reg, dsim->reg_base + S5P_DSIM_ESCMODE);
> +}
> +
> +unsigned int s5p_mipi_dsi_is_lane_state(struct mipi_dsim_device *dsim)
> +{
> + unsigned int reg = readl(dsim->reg_base + S5P_DSIM_STATUS);
> +
> + /**
> + * check clock and data lane states.
> + * if MIPI-DSI controller was enabled at bootloader then
> + * TX_READY_HS_CLK is enabled otherwise STOP_STATE_CLK.
> + * so it should be checked for two case.
> + */
> + if ((reg & DSIM_STOP_STATE_DAT(0xf)) &&
> + ((reg & DSIM_STOP_STATE_CLK) ||
> + (reg & DSIM_TX_READY_HS_CLK)))
> + return 1;
> + else
> + return 0;
> +
> + return 0;
> +}
> +
> +void s5p_mipi_dsi_set_stop_state_counter(struct mipi_dsim_device *dsim,
> + unsigned int cnt_val)
> +{
> + unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_ESCMODE)) &
> + ~(0x7ff << DSIM_STOP_STATE_CNT_SHIFT);
> +
> + reg |= ((cnt_val & 0x7ff) << DSIM_STOP_STATE_CNT_SHIFT);
> +
> + writel(reg, dsim->reg_base + S5P_DSIM_ESCMODE);
> +}
> +
> +void s5p_mipi_dsi_set_bta_timeout(struct mipi_dsim_device *dsim,
> + unsigned int timeout)
> +{
> + unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_TIMEOUT)) &
> + ~(0xff << DSIM_BTA_TOUT_SHIFT);
> +
> + reg |= (timeout << DSIM_BTA_TOUT_SHIFT);
> +
> + writel(reg, dsim->reg_base + S5P_DSIM_TIMEOUT);
> +}
> +
> +void s5p_mipi_dsi_set_lpdr_timeout(struct mipi_dsim_device *dsim,
> + unsigned int timeout)
> +{
> + unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_TIMEOUT)) &
> + ~(0xffff << DSIM_LPDR_TOUT_SHIFT);
> +
> + reg |= (timeout << DSIM_LPDR_TOUT_SHIFT);
> +
> + writel(reg, dsim->reg_base + S5P_DSIM_TIMEOUT);
> +}
> +
> +void s5p_mipi_dsi_set_cpu_transfer_mode(struct mipi_dsim_device *dsim,
> + unsigned int lp)
> +{
> + unsigned int reg = readl(dsim->reg_base + S5P_DSIM_ESCMODE);
> +
> + reg &= ~DSIM_CMD_LPDT_LP;
> +
> + if (lp)
> + reg |= DSIM_CMD_LPDT_LP;
> +
> + writel(reg, dsim->reg_base + S5P_DSIM_ESCMODE);
> +}
> +
> +void s5p_mipi_dsi_set_lcdc_transfer_mode(struct mipi_dsim_device *dsim,
> + unsigned int lp)
> +{
> + unsigned int reg = readl(dsim->reg_base + S5P_DSIM_ESCMODE);
> +
> + reg &= ~DSIM_TX_LPDT_LP;
> +
> + if (lp)
> + reg |= DSIM_TX_LPDT_LP;
> +
> + writel(reg, dsim->reg_base + S5P_DSIM_ESCMODE);
> +}
> +
> +void s5p_mipi_dsi_enable_hs_clock(struct mipi_dsim_device *dsim,
> + unsigned int enable)
> +{
> + unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_CLKCTRL)) &
> + ~(1 << DSIM_TX_REQUEST_HSCLK_SHIFT);
> +
> + reg |= enable << DSIM_TX_REQUEST_HSCLK_SHIFT;
> +
> + writel(reg, dsim->reg_base + S5P_DSIM_CLKCTRL);
> +}
> +
> +void s5p_mipi_dsi_dp_dn_swap(struct mipi_dsim_device *dsim,
> + unsigned int swap_en)
> +{
> + unsigned int reg = readl(dsim->reg_base + S5P_DSIM_PHYACCHR1);
> +
> + reg &= ~(0x3 << 0);
> + reg |= (swap_en & 0x3) << 0;
> +
> + writel(reg, dsim->reg_base + S5P_DSIM_PHYACCHR1);
> +}
> +
> +void s5p_mipi_dsi_hs_zero_ctrl(struct mipi_dsim_device *dsim,
> + unsigned int hs_zero)
> +{
> + unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_PLLCTRL)) &
> + ~(0xf << 28);
> +
> + reg |= ((hs_zero & 0xf) << 28);
> +
> + writel(reg, dsim->reg_base + S5P_DSIM_PLLCTRL);
> +}
> +
> +void s5p_mipi_dsi_prep_ctrl(struct mipi_dsim_device *dsim, unsigned int prep)
> +{
> + unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_PLLCTRL)) &
> + ~(0x7 << 20);
> +
> + reg |= ((prep & 0x7) << 20);
> +
> + writel(reg, dsim->reg_base + S5P_DSIM_PLLCTRL);
> +}
> +
> +void s5p_mipi_dsi_clear_interrupt(struct mipi_dsim_device *dsim)
> +{
> + unsigned int reg = readl(dsim->reg_base + S5P_DSIM_INTSRC);
> +
> + reg |= INTSRC_PLL_STABLE;
> +
> + writel(reg, dsim->reg_base + S5P_DSIM_INTSRC);
> +}
> +
> +void s5p_mipi_dsi_clear_all_interrupt(struct mipi_dsim_device *dsim)
> +{
> + unsigned int reg = readl(dsim->reg_base + S5P_DSIM_INTSRC);
> +
> + reg |= 0xffffffff;
> +
> + writel(reg, dsim->reg_base + S5P_DSIM_INTSRC);
> +}
> +
> +unsigned int s5p_mipi_dsi_is_pll_stable(struct mipi_dsim_device *dsim)
> +{
> + unsigned int reg;
> +
> + reg = readl(dsim->reg_base + S5P_DSIM_STATUS);
> +
> + return reg & (1 << 31) ? 1 : 0;
> +}
> +
> +unsigned int s5p_mipi_dsi_get_fifo_state(struct mipi_dsim_device *dsim)
> +{
> + unsigned int ret;
> +
> + ret = readl(dsim->reg_base + S5P_DSIM_FIFOCTRL) & ~(0x1f);
> +
> + return ret;
> +}
> +
> +void s5p_mipi_dsi_wr_tx_header(struct mipi_dsim_device *dsim,
> + unsigned int di, unsigned int data0, unsigned int data1)
> +{
> + unsigned int reg = (data1 << 16) | (data0 << 8) | ((di & 0x3f) << 0);
> +
> + writel(reg, dsim->reg_base + S5P_DSIM_PKTHDR);
> +}
> +
> +unsigned int _s5p_mipi_dsi_get_frame_done_status(struct mipi_dsim_device *dsim)
> +{
> + unsigned int reg = readl(dsim->reg_base + S5P_DSIM_INTSRC);
> +
> + return (reg & INTSRC_FRAME_DONE) ? 1 : 0;
> +}
> +
> +void _s5p_mipi_dsi_clear_frame_done(struct mipi_dsim_device *dsim)
> +{
> + unsigned int reg = readl(dsim->reg_base + S5P_DSIM_INTSRC);
> +
> + writel(reg | INTSRC_FRAME_DONE, dsim->reg_base +
> + S5P_DSIM_INTSRC);
> +}
> +
> +void s5p_mipi_dsi_wr_tx_data(struct mipi_dsim_device *dsim,
> + unsigned int tx_data)
> +{
> + writel(tx_data, dsim->reg_base + S5P_DSIM_PAYLOAD);
> +}
> diff --git a/drivers/video/s5p_mipi_dsi_lowlevel.h b/drivers/video/s5p_mipi_dsi_lowlevel.h
> new file mode 100644
> index 0000000..ca9dc56
> --- /dev/null
> +++ b/drivers/video/s5p_mipi_dsi_lowlevel.h
> @@ -0,0 +1,100 @@
> +/* linux/drivers/video/s5p_mipi_dsi_lowlevel.h
> + *
> + * Header file for Samsung SoC MIPI-DSI lowlevel driver.
> + *
> + * Copyright (c) 2011 Samsung Electronics Co., Ltd
> + *
> + * InKi Dae <inki.dae@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.
> +*/
> +
> +#ifndef _S5P_MIPI_DSI_LOWLEVEL_H
> +#define _S5P_MIPI_DSI_LOWLEVEL_H
> +
> +void s5p_mipi_dsi_func_reset(struct mipi_dsim_device *dsim);
> +void s5p_mipi_dsi_sw_reset(struct mipi_dsim_device *dsim);
> +void s5p_mipi_dsi_set_interrupt_mask(struct mipi_dsim_device *dsim,
> + unsigned int mode, unsigned int mask);
> +void s5p_mipi_dsi_set_data_lane_number(struct mipi_dsim_device *dsim,
> + unsigned int count);
> +void s5p_mipi_dsi_init_fifo_pointer(struct mipi_dsim_device *dsim,
> + unsigned int cfg);
> +void s5p_mipi_dsi_set_phy_tunning(struct mipi_dsim_device *dsim,
> + unsigned int value);
> +void s5p_mipi_dsi_set_phy_tunning(struct mipi_dsim_device *dsim,
> + unsigned int value);
> +void s5p_mipi_dsi_set_main_disp_resol(struct mipi_dsim_device *dsim,
> + unsigned int width_resol, unsigned int height_resol);
> +void s5p_mipi_dsi_set_main_disp_vporch(struct mipi_dsim_device *dsim,
> + unsigned int cmd_allow, unsigned int vfront, unsigned int vback);
> +void s5p_mipi_dsi_set_main_disp_hporch(struct mipi_dsim_device *dsim,
> + unsigned int front, unsigned int back);
> +void s5p_mipi_dsi_set_main_disp_sync_area(struct mipi_dsim_device *dsim,
> + unsigned int vert, unsigned int hori);
> +void s5p_mipi_dsi_set_sub_disp_resol(struct mipi_dsim_device *dsim,
> + unsigned int vert, unsigned int hori);
> +void s5p_mipi_dsi_init_config(struct mipi_dsim_device *dsim);
> +void s5p_mipi_dsi_display_config(struct mipi_dsim_device *dsim,
> + struct mipi_dsim_config *dsim_config);
> +void s5p_mipi_dsi_set_data_lane_number(struct mipi_dsim_device *dsim,
> + unsigned int count);
> +void s5p_mipi_dsi_enable_lane(struct mipi_dsim_device *dsim, unsigned int lane,
> + unsigned int enable);
> +void s5p_mipi_dsi_enable_afc(struct mipi_dsim_device *dsim, unsigned int enable,
> + unsigned int afc_code);
> +void s5p_mipi_dsi_enable_pll_bypass(struct mipi_dsim_device *dsim,
> + unsigned int enable);
> +void s5p_mipi_dsi_set_pll_pms(struct mipi_dsim_device *dsim, unsigned int p,
> + unsigned int m, unsigned int s);
> +void s5p_mipi_dsi_pll_freq_band(struct mipi_dsim_device *dsim,
> + unsigned int freq_band);
> +void s5p_mipi_dsi_pll_freq(struct mipi_dsim_device *dsim,
> + unsigned int pre_divider, unsigned int main_divider,
> + unsigned int scaler);
> +void s5p_mipi_dsi_pll_stable_time(struct mipi_dsim_device *dsim,
> + unsigned int lock_time);
> +void s5p_mipi_dsi_enable_pll(struct mipi_dsim_device *dsim,
> + unsigned int enable);
> +void s5p_mipi_dsi_set_byte_clock_src(struct mipi_dsim_device *dsim,
> + unsigned int src);
> +void s5p_mipi_dsi_enable_byte_clock(struct mipi_dsim_device *dsim,
> + unsigned int enable);
> +void s5p_mipi_dsi_set_esc_clk_prs(struct mipi_dsim_device *dsim,
> + unsigned int enable, unsigned int prs_val);
> +void s5p_mipi_dsi_enable_esc_clk_on_lane(struct mipi_dsim_device *dsim,
> + unsigned int lane_sel, unsigned int enable);
> +void s5p_mipi_dsi_force_dphy_stop_state(struct mipi_dsim_device *dsim,
> + unsigned int enable);
> +unsigned int s5p_mipi_dsi_is_lane_state(struct mipi_dsim_device *dsim);
> +void s5p_mipi_dsi_set_stop_state_counter(struct mipi_dsim_device *dsim,
> + unsigned int cnt_val);
> +void s5p_mipi_dsi_set_bta_timeout(struct mipi_dsim_device *dsim,
> + unsigned int timeout);
> +void s5p_mipi_dsi_set_lpdr_timeout(struct mipi_dsim_device *dsim,
> + unsigned int timeout);
> +void s5p_mipi_dsi_set_lcdc_transfer_mode(struct mipi_dsim_device *dsim,
> + unsigned int lp);
> +void s5p_mipi_dsi_set_cpu_transfer_mode(struct mipi_dsim_device *dsim,
> + unsigned int lp);
> +void s5p_mipi_dsi_enable_hs_clock(struct mipi_dsim_device *dsim,
> + unsigned int enable);
> +void s5p_mipi_dsi_dp_dn_swap(struct mipi_dsim_device *dsim,
> + unsigned int swap_en);
> +void s5p_mipi_dsi_hs_zero_ctrl(struct mipi_dsim_device *dsim,
> + unsigned int hs_zero);
> +void s5p_mipi_dsi_prep_ctrl(struct mipi_dsim_device *dsim, unsigned int prep);
> +void s5p_mipi_dsi_clear_interrupt(struct mipi_dsim_device *dsim);
> +void s5p_mipi_dsi_clear_all_interrupt(struct mipi_dsim_device *dsim);
> +unsigned int s5p_mipi_dsi_is_pll_stable(struct mipi_dsim_device *dsim);
> +unsigned int s5p_mipi_dsi_get_fifo_state(struct mipi_dsim_device *dsim);
> +unsigned int _s5p_mipi_dsi_get_frame_done_status(struct mipi_dsim_device *dsim);
> +void _s5p_mipi_dsi_clear_frame_done(struct mipi_dsim_device *dsim);
> +void s5p_mipi_dsi_wr_tx_header(struct mipi_dsim_device *dsim, unsigned int di,
> + unsigned int data0, unsigned int data1);
> +void s5p_mipi_dsi_wr_tx_data(struct mipi_dsim_device *dsim,
> + unsigned int tx_data);
> +
> +#endif /* _S5P_MIPI_DSI_LOWLEVEL_H */
> --
> 1.7.0.4
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
^ permalink raw reply
* [PATCH 2/2] video: Samsung SoC MIPI-DSI based sample lcd panel driver.
From: Inki Dae @ 2011-04-14 12:15 UTC (permalink / raw)
To: linux-arm-kernel
this driver provides an example for implementing MIPI-DSI based lcd panel
driver and includes most features for LCD Panel driver so just implement
lcd register setting functions using sample functions.
Signed-off-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
Documentation/s5p_mipi_dsim/dsim_sample_lcd.c | 244 +++++++++++++++++++++++++
1 files changed, 244 insertions(+), 0 deletions(-)
create mode 100644 Documentation/s5p_mipi_dsim/dsim_sample_lcd.c
diff --git a/Documentation/s5p_mipi_dsim/dsim_sample_lcd.c b/Documentation/s5p_mipi_dsim/dsim_sample_lcd.c
new file mode 100644
index 0000000..7f38c84
--- /dev/null
+++ b/Documentation/s5p_mipi_dsim/dsim_sample_lcd.c
@@ -0,0 +1,244 @@
+/*
+ * Samsung SoC MIPI-DSI based sample lcd panel driver.
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * Inki Dae, <inki.dae@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/ctype.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/lcd.h>
+#include <linux/backlight.h>
+
+#include <video/mipi_display.h>
+
+#include <plat/mipi_dsim.h>
+
+#define MIN_BRIGHTNESS (0)
+#define MAX_BRIGHTNESS (10)
+
+#define lcd_to_master(a) (a->dsim_dev->master)
+#define lcd_to_master_ops(a) ((lcd_to_master(a))->master_ops)
+
+struct dsim_lcd {
+ struct device *dev;
+
+ struct lcd_device *ld;
+ struct backlight_device *bd;
+
+ struct mipi_dsim_lcd_device *dsim_dev;
+ struct lcd_platform_data *ddi_pd;
+};
+
+static void dsim_lcd_short_write(struct dsim_lcd *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_SHORT_WRITE_PARAM,
+ 0x00, 0x00);
+}
+
+static void dsim_lcd_long_write(struct dsim_lcd *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ unsigned char data_to_send[8] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ (unsigned int) data_to_send, sizeof(data_to_send));
+}
+
+static int dsim_lcd_panel_init(struct dsim_lcd *lcd)
+{
+
+ dsim_lcd_short_write(lcd);
+ dsim_lcd_long_write(lcd);
+
+ return 0;
+}
+
+static int dsim_lcd_gamma_ctrl(struct dsim_lcd *lcd, int gamma)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+
+ /* update gamma value at here. */
+
+ return 0;
+}
+
+static int dsim_lcd_set_power(struct lcd_device *ld, int power)
+{
+ return 0;
+}
+
+static int dsim_lcd_get_power(struct lcd_device *ld)
+{
+ return 0;
+}
+
+static int dsim_lcd_get_brightness(struct backlight_device *bd)
+{
+ return bd->props.brightness;
+}
+
+static int dsim_lcd_set_brightness(struct backlight_device *bd)
+{
+ int ret = 0, brightness = bd->props.brightness;
+ struct dsim_lcd *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 = dsim_lcd_gamma_ctrl(lcd, bd->props.brightness);
+ if (ret) {
+ dev_err(&bd->dev, "lcd brightness setting failed.\n");
+ return -EIO;
+ }
+
+ return ret;
+}
+
+static const struct lcd_ops dsim_lcd_lcd_ops = {
+ .set_power = dsim_lcd_set_power,
+ .get_power = dsim_lcd_get_power,
+};
+
+static const struct backlight_ops dsim_lcd_backlight_ops = {
+ .get_brightness = dsim_lcd_get_brightness,
+ .update_status = dsim_lcd_set_brightness,
+};
+
+static int dsim_lcd_probe(struct mipi_dsim_lcd_device *dsim_dev)
+{
+ struct dsim_lcd *lcd = NULL;
+ int ret;
+
+ lcd = kzalloc(sizeof(struct dsim_lcd), GFP_KERNEL);
+ if (!lcd) {
+ dev_err(&dsim_dev->dev, "failed to allocate dsim_lcd structure.\n");
+ return -ENOMEM;
+ }
+
+ lcd->dsim_dev = dsim_dev;
+ lcd->ddi_pd = (struct lcd_platform_data *)dsim_dev->platform_data;
+ lcd->dev = &dsim_dev->dev;
+
+ dev_set_drvdata(&dsim_dev->dev, lcd);
+
+ lcd->ld = lcd_device_register("dsim_lcd", lcd->dev, lcd,
+ &dsim_lcd_lcd_ops);
+ if (IS_ERR(lcd->ld)) {
+ dev_err(lcd->dev, "failed to register lcd ops.\n");
+ ret = PTR_ERR(lcd->ld);
+
+ goto err1;
+ }
+
+ lcd->bd = backlight_device_register("dsim_lcd-bl", lcd->dev, lcd,
+ &dsim_lcd_backlight_ops, NULL);
+ if (IS_ERR(lcd->bd)) {
+ dev_err(lcd->dev, "failed to register backlight ops.\n");
+ ret = PTR_ERR(lcd->bd);
+
+ goto err1;
+ }
+
+ lcd->bd->props.max_brightness = MAX_BRIGHTNESS;
+ lcd->bd->props.brightness = MAX_BRIGHTNESS;
+
+ /* lcd power on */
+ if (lcd->ddi_pd->power_on)
+ lcd->ddi_pd->power_on(lcd->ld, 1);
+ else
+ dev_warn(lcd->dev, "lcd_power_on func is null.\n");
+
+ mdelay(lcd->ddi_pd->reset_delay);
+
+ /* lcd reset */
+ if (lcd->ddi_pd->reset)
+ lcd->ddi_pd->reset(lcd->ld);
+ else
+ dev_warn(lcd->dev, "lcd_reset func is null.\n");
+
+ dsim_lcd_panel_init(lcd);
+
+ dev_dbg(lcd->dev, "dsim_lcd panel driver has been probed.\n");
+
+ return 0;
+
+err1:
+ kfree(lcd);
+
+ return ret;
+}
+
+static int __devexit dsim_lcd_remove(struct mipi_dsim_lcd_device *dsim_dev)
+{
+ struct dsim_lcd *lcd = dev_get_drvdata(&dsim_dev->dev);
+
+ kfree(lcd);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int dsim_lcd_suspend(struct mipi_dsim_lcd_device *dsim_dev)
+{
+ struct dsim_lcd *lcd = dev_get_drvdata(&dsim_dev->dev);
+
+ return 0;
+}
+
+static int dsim_lcd_resume(struct mipi_dsim_lcd_device *dsim_dev)
+{
+ struct dsim_lcd *lcd = dev_get_drvdata(&dsim_dev->dev);
+
+ return 0;
+}
+#else
+#define dsim_lcd_suspend NULL
+#define dsim_lcd_resume NULL
+#endif
+
+static struct mipi_dsim_lcd_driver dsim_lcd_dsim_ddi_driver = {
+ .name = "dsim_lcd",
+ .id = -1,
+
+ .probe = dsim_lcd_probe,
+ .remove = __devexit_p(dsim_lcd_remove),
+ .suspend = dsim_lcd_suspend,
+ .resume = dsim_lcd_resume,
+};
+
+static int dsim_lcd_init(void)
+{
+ s5p_mipi_dsi_register_lcd_driver(&dsim_lcd_dsim_ddi_driver);
+
+ return 0;
+}
+
+static void dsim_lcd_exit(void)
+{
+}
+
+module_init(dsim_lcd_init);
+module_exit(dsim_lcd_exit);
+
+MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
+MODULE_DESCRIPTION("Samsung SoC MIPI-DSI based sample lcd panel driver");
+MODULE_LICENSE("GPL");
--
1.7.0.4
^ permalink raw reply related
* [PATCH 1/2] video: add Samsung SoC MIPI-DSI controller driver.
From: Inki Dae @ 2011-04-14 12:15 UTC (permalink / raw)
To: linux-arm-kernel
Samsung S5PV210 and EXYNOS4 SoC platform have one or two MIPI-DSI controller.
MIPI-DSI based LCD Panel could be used with MIPI-DSI controller driver.
this patch adds the MIPI-DSI controller driver and also this driver would
support both platforms.
to use MIPI-DSI based LCD Panel driver, mipi_dsim_lcd_device should be
registered to MIPI-DSI Driver through s5p_mipi_dsi_register_lcd_device() call
in machine code or machine specific somewhere first, and mipi_dsim_lcd_driver
should be registered when s5p_mipi_dsi_register_lcd_driver() is called at init
function of lcd driver, and then probe() of that driver would be called by
MIPI-DSI controller driver if lcd panel name and id of mipi_dsim_lcd_device
are same as ones of mipi_dsim_lcd_driver.
for this, you can refer to sample lcd panel driver.
please see "Documentation/s5p_mipi_dsim/dsim_sample_lcd.c"
Signed-off-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
arch/arm/plat-s5p/include/plat/mipi_dsim.h | 345 +++++++++++++++
arch/arm/plat-s5p/include/plat/regs-dsim.h | 143 ++++++
drivers/video/Kconfig | 7 +
drivers/video/Makefile | 2 +
drivers/video/s5p_mipi_dsi.c | 481 ++++++++++++++++++++
drivers/video/s5p_mipi_dsi_common.c | 655 ++++++++++++++++++++++++++++
drivers/video/s5p_mipi_dsi_common.h | 39 ++
drivers/video/s5p_mipi_dsi_lowlevel.c | 558 +++++++++++++++++++++++
drivers/video/s5p_mipi_dsi_lowlevel.h | 100 +++++
9 files changed, 2330 insertions(+), 0 deletions(-)
create mode 100644 arch/arm/plat-s5p/include/plat/mipi_dsim.h
create mode 100644 arch/arm/plat-s5p/include/plat/regs-dsim.h
create mode 100644 drivers/video/s5p_mipi_dsi.c
create mode 100644 drivers/video/s5p_mipi_dsi_common.c
create mode 100644 drivers/video/s5p_mipi_dsi_common.h
create mode 100644 drivers/video/s5p_mipi_dsi_lowlevel.c
create mode 100644 drivers/video/s5p_mipi_dsi_lowlevel.h
diff --git a/arch/arm/plat-s5p/include/plat/mipi_dsim.h b/arch/arm/plat-s5p/include/plat/mipi_dsim.h
new file mode 100644
index 0000000..0fa2d7e
--- /dev/null
+++ b/arch/arm/plat-s5p/include/plat/mipi_dsim.h
@@ -0,0 +1,345 @@
+/* linux/arm/arch/plat-s5p/include/plat/mipi_dsim.h
+ *
+ * Platform data header for Samsung SoC MIPI-DSIM.
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * InKi Dae <inki.dae@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.
+*/
+
+#ifndef _DSIM_H
+#define _DSIM_H
+
+#include <linux/device.h>
+#include <linux/fb.h>
+
+#define PANEL_NAME_SIZE (32)
+
+enum mipi_dsim_interface_type {
+ DSIM_COMMAND,
+ DSIM_VIDEO
+};
+
+enum mipi_dsim_virtual_ch_no {
+ DSIM_VIRTUAL_CH_0,
+ DSIM_VIRTUAL_CH_1,
+ DSIM_VIRTUAL_CH_2,
+ DSIM_VIRTUAL_CH_3
+};
+
+enum mipi_dsim_burst_mode_type {
+ DSIM_NON_BURST_SYNC_EVENT,
+ DSIM_NON_BURST_SYNC_PULSE = 2,
+ DSIM_BURST,
+ DSIM_NON_VIDEO_MODE
+};
+
+enum mipi_dsim_no_of_data_lane {
+ DSIM_DATA_LANE_1,
+ DSIM_DATA_LANE_2,
+ DSIM_DATA_LANE_3,
+ DSIM_DATA_LANE_4
+};
+
+enum mipi_dsim_byte_clk_src {
+ DSIM_PLL_OUT_DIV8,
+ DSIM_EXT_CLK_DIV8,
+ DSIM_EXT_CLK_BYPASS
+};
+
+enum mipi_dsim_pixel_format {
+ DSIM_CMD_3BPP,
+ DSIM_CMD_8BPP,
+ DSIM_CMD_12BPP,
+ DSIM_CMD_16BPP,
+ DSIM_VID_16BPP_565,
+ DSIM_VID_18BPP_666PACKED,
+ DSIM_18BPP_666LOOSELYPACKED,
+ DSIM_24BPP_888
+};
+
+/**
+ * struct mipi_dsim_config - interface for configuring mipi-dsi controller.
+ *
+ * @auto_flush: enable or disable Auto flush of MD FIFO using VSYNC pulse.
+ * @eot_disable: enable or disable EoT packet in HS mode.
+ * @auto_vertical_cnt: specifies auto vertical count mode.
+ * in Video mode, the vertical line transition uses line counter
+ * configured by VSA, VBP, and Vertical resolution.
+ * If this bit is set to '1', the line counter does not use VSA and VBP
+ * registers.(in command mode, this variable is ignored)
+ * @hse: set horizontal sync event mode.
+ * In VSYNC pulse and Vporch area, MIPI DSI master transfers only HSYNC
+ * start packet to MIPI DSI slave at MIPI DSI spec1.1r02.
+ * this bit transfers HSYNC end packet in VSYNC pulse and Vporch area
+ * (in mommand mode, this variable is ignored)
+ * @hfp: specifies HFP disable mode.
+ * if this variable is set, DSI master ignores HFP area in VIDEO mode.
+ * (in command mode, this variable is ignored)
+ * @hbp: specifies HBP disable mode.
+ * if this variable is set, DSI master ignores HBP area in VIDEO mode.
+ * (in command mode, this variable is ignored)
+ * @hsa: specifies HSA disable mode.
+ * if this variable is set, DSI master ignores HSA area in VIDEO mode.
+ * (in command mode, this variable is ignored)
+ * @e_interface: specifies interface to be used.(CPU or RGB interface)
+ * @e_virtual_ch: specifies virtual channel number that main or
+ * sub diaplsy uses.
+ * @e_pixel_format: specifies pixel stream format for main or sub display.
+ * @e_burst_mode: selects Burst mode in Video mode.
+ * in Non-burst mode, RGB data area is filled with RGB data and NULL
+ * packets, according to input bandwidth of RGB interface.
+ * In Burst mode, RGB data area is filled with RGB data only.
+ * @e_no_data_lane: specifies data lane count to be used by Master.
+ * @e_byte_clk: select byte clock source. (it must be DSIM_PLL_OUT_DIV8)
+ * DSIM_EXT_CLK_DIV8 and DSIM_EXT_CLK_BYPASSS are not supported.
+ * @pll_stable_time: specifies the PLL Timer for stability of the ganerated
+ * clock(System clock cycle base)
+ * if the timer value goes to 0x00000000, the clock stable bit of status
+ * and interrupt register is set.
+ * @esc_clk: specifies escape clock frequency for getting the escape clock
+ * prescaler value.
+ * @stop_holding_cnt: specifies the interval value between transmitting
+ * read packet(or write "set_tear_on" command) and BTA request.
+ * after transmitting read packet or write "set_tear_on" command,
+ * BTA requests to D-PHY automatically. this counter value specifies
+ * the interval between them.
+ * @bta_timeout: specifies the timer for BTA.
+ * this register specifies time out from BTA request to change
+ * the direction with respect to Tx escape clock.
+ * @rx_timeout: specifies the timer for LP Rx mode timeout.
+ * this register specifies time out on how long RxValid deasserts,
+ * after RxLpdt asserts with respect to Tx escape clock.
+ * - RxValid specifies Rx data valid indicator.
+ * - RxLpdt specifies an indicator that D-PHY is under RxLpdt mode.
+ * - RxValid and RxLpdt specifies signal from D-PHY.
+ */
+struct mipi_dsim_config {
+ unsigned char auto_flush;
+ unsigned char eot_disable;
+
+ unsigned char auto_vertical_cnt;
+ unsigned char hse;
+ unsigned char hfp;
+ unsigned char hbp;
+ unsigned char hsa;
+
+ enum mipi_dsim_interface_type e_interface;
+ enum mipi_dsim_virtual_ch_no e_virtual_ch;
+ enum mipi_dsim_pixel_format e_pixel_format;
+ enum mipi_dsim_burst_mode_type e_burst_mode;
+ enum mipi_dsim_no_of_data_lane e_no_data_lane;
+ enum mipi_dsim_byte_clk_src e_byte_clk;
+
+ /*
+ * =====================+ * | P | M | S | MHz |
+ * -------------------------------------------
+ * | 3 | 100 | 3 | 100 |
+ * | 3 | 100 | 2 | 200 |
+ * | 3 | 63 | 1 | 252 |
+ * | 4 | 100 | 1 | 300 |
+ * | 4 | 110 | 1 | 330 |
+ * | 12 | 350 | 1 | 350 |
+ * | 3 | 100 | 1 | 400 |
+ * | 4 | 150 | 1 | 450 |
+ * | 3 | 118 | 1 | 472 |
+ * | 12 | 250 | 0 | 500 |
+ * | 4 | 100 | 0 | 600 |
+ * | 3 | 81 | 0 | 648 |
+ * | 3 | 88 | 0 | 704 |
+ * | 3 | 90 | 0 | 720 |
+ * | 3 | 100 | 0 | 800 |
+ * | 12 | 425 | 0 | 850 |
+ * | 4 | 150 | 0 | 900 |
+ * | 12 | 475 | 0 | 950 |
+ * | 6 | 250 | 0 | 1000 |
+ * -------------------------------------------
+ */
+ unsigned char p;
+ unsigned short m;
+ unsigned char s;
+
+ unsigned int pll_stable_time;
+ unsigned long esc_clk;
+
+ unsigned short stop_holding_cnt;
+ unsigned char bta_timeout;
+ unsigned short rx_timeout;
+};
+
+/**
+ * struct mipi_dsim_device - global interface for mipi-dsi driver.
+ *
+ * @dev: driver model representation of the device.
+ * @id: unique device id.
+ * @clock: pointer to MIPI-DSI clock of clock framework.
+ * @irq: interrupt number to MIPI-DSI controller.
+ * @reg_base: base address to memory mapped SRF of MIPI-DSI controller.
+ * (virtual address)
+ * @lock: the mutex protecting this data structure.
+ * @dsim_info: infomation for configuring mipi-dsi controller.
+ * @master_ops: callbacks to mipi-dsi operations.
+ * @dsim_lcd_dev: pointer to activated ddi device.
+ * (it would be registered by mipi-dsi driver.)
+ * @dsim_lcd_drv: pointer to activated_ddi driver.
+ * (it would be registered by mipi-dsi driver.)
+ * @lcd_info: pointer to mipi_lcd_info structure.
+ * @state: specifies status of MIPI-DSI controller.
+ * the status could be RESET, INIT, STOP, HSCLKEN and ULPS.
+ * @resume_complete: indicates whether resume operation is completed or not.
+ * @data_lane: specifiec enabled data lane number.
+ * this variable would be set by driver according to e_no_data_lane
+ * automatically.
+ * @e_clk_src: select byte clock source.
+ * @pd: pointer to MIPI-DSI driver platform data.
+ */
+struct mipi_dsim_device {
+ struct device *dev;
+ int id;
+ struct resource *res;
+ struct clk *clock;
+ unsigned int irq;
+ void __iomem *reg_base;
+ struct mutex lock;
+
+ struct mipi_dsim_config *dsim_config;
+ struct mipi_dsim_master_ops *master_ops;
+ struct mipi_dsim_lcd_device *dsim_lcd_dev;
+ struct mipi_dsim_lcd_driver *dsim_lcd_drv;
+
+ unsigned int state;
+ unsigned int resume_complete;
+ unsigned int data_lane;
+ enum mipi_dsim_byte_clk_src e_clk_src;
+
+ struct s5p_platform_mipi_dsim *pd;
+};
+
+/**
+ * struct s5p_platform_mipi_dsim - interface to platform data
+ * for mipi-dsi driver.
+ *
+ * @lcd_panel_name: specifies lcd panel name registered to mipi-dsi driver.
+ * lcd panel driver searched would be actived.
+ * @dsim_config: pointer of structure for configuring mipi-dsi controller.
+ * @lcd_panel_info: pointer for lcd panel specific structure.
+ * this structure specifies width, height, timing and polarity and so on.
+ * @mipi_power: callback pointer for enabling or disabling mipi power.
+ * @phy_enable: pointer to a callback controlling D-PHY enable/reset
+ */
+struct s5p_platform_mipi_dsim {
+ char lcd_panel_name[PANEL_NAME_SIZE];
+
+ struct mipi_dsim_config *dsim_config;
+ void *lcd_panel_info;
+
+ int (*mipi_power)(struct platform_device *pdev, unsigned int enable);
+ int (*phy_enable)(struct platform_device *pdev, bool on);
+};
+/**
+ * struct mipi_dsim_master_ops - callbacks to mipi-dsi operations.
+ *
+ * @cmd_write: transfer command to lcd panel at LP mode.
+ * @cmd_read: read command from rx register.
+ * @get_dsim_frame_done: get the status that all screen data have been
+ * transferred to mipi-dsi.
+ * @clear_dsim_frame_done: clear frame done status.
+ * @get_fb_frame_done: get frame done status of display controller.
+ * @trigger: trigger display controller.
+ * - this one would be used only in case of CPU mode.
+ */
+
+struct mipi_dsim_master_ops {
+ int (*cmd_write)(struct mipi_dsim_device *dsim, unsigned int data_id,
+ unsigned int data0, unsigned int data1);
+ int (*cmd_read)(struct mipi_dsim_device *dsim, unsigned int data_id,
+ unsigned int data0, unsigned int data1);
+ int (*get_dsim_frame_done)(struct mipi_dsim_device *dsim);
+ int (*clear_dsim_frame_done)(struct mipi_dsim_device *dsim);
+
+ int (*get_fb_frame_done)(struct fb_info *info);
+ void (*trigger)(struct fb_info *info);
+};
+
+/**
+ * device structure for mipi-dsi based lcd panel.
+ *
+ * @name: name of the device to use with this device, or an
+ * alias for that name.
+ * @dev: driver model representation of the device.
+ * @id: id of device to be registered.
+ * @bus_id: bus id for identifing connected bus
+ * and this bus id should be same as id of mipi_dsim_device.
+ * @irq: irq number for signaling when framebuffer transfer of
+ * lcd panel module is completed.
+ * this irq would be used only for MIPI-DSI based CPU mode lcd panel.
+ * @master: pointer to mipi-dsi master device object.
+ * @platform_data: lcd panel specific platform data.
+ */
+struct mipi_dsim_lcd_device {
+ char *name;
+ struct device dev;
+ int id;
+ int bus_id;
+ int irq;
+
+ struct mipi_dsim_device *master;
+ void *platform_data;
+};
+
+/**
+ * driver structure for mipi-dsi based lcd panel.
+ *
+ * this structure should be registered by lcd panel driver.
+ * mipi-dsi driver seeks lcd panel registered through name field
+ * and calls these callback functions in appropriate time.
+ *
+ * @name: name of the driver to use with this device, or an
+ * alias for that name.
+ * @id: id of driver to be registered.
+ * this id would be used for finding device object registered.
+ */
+struct mipi_dsim_lcd_driver {
+ char *name;
+ int id;
+
+ int (*probe)(struct mipi_dsim_lcd_device *dsim_dev);
+ int (*remove)(struct mipi_dsim_lcd_device *dsim_dev);
+ void (*shutdown)(struct mipi_dsim_lcd_device *dsim_dev);
+ int (*suspend)(struct mipi_dsim_lcd_device *dsim_dev);
+ int (*resume)(struct mipi_dsim_lcd_device *dsim_dev);
+};
+
+/**
+ * register mipi_dsim_lcd_driver object defined by lcd panel driver
+ * to mipi-dsi driver.
+ */
+int s5p_mipi_dsi_register_lcd_driver(struct mipi_dsim_lcd_driver
+ *lcd_drv);
+
+/**
+ * register mipi_dsim_lcd_device to mipi-dsi master.
+ */
+int s5p_mipi_dsi_register_lcd_device(struct mipi_dsim_lcd_device
+ *lcd_dev);
+
+/**
+ * enable regulators to MIPI-DSI power.
+ */
+int s5p_mipi_dsi_dphy_power(struct mipi_dsim_device *dsim,
+ unsigned int enable);
+
+/**
+ * s5p_dsim_phy_enable - global MIPI-DSI receiver D-PHY control
+ * @pdev: MIPI-DSIM platform device
+ * @on: true to enable D-PHY and deassert its reset
+ * false to disable D-PHY
+ */
+int s5p_dsim_phy_enable(struct platform_device *pdev, bool on);
+
+#endif /* _DSIM_H */
diff --git a/arch/arm/plat-s5p/include/plat/regs-dsim.h b/arch/arm/plat-s5p/include/plat/regs-dsim.h
new file mode 100644
index 0000000..5f0e4fa
--- /dev/null
+++ b/arch/arm/plat-s5p/include/plat/regs-dsim.h
@@ -0,0 +1,143 @@
+/* linux/arch/arm/plat-s5p/include/plat/regs-dsim.h
+ *
+ * Register definition file for Samsung MIPI-DSIM driver
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * InKi Dae <inki.dae@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.
+*/
+
+#ifndef _REGS_DSIM_H
+#define _REGS_DSIM_H
+
+#define S5P_DSIM_STATUS (0x0) /* Status register */
+#define S5P_DSIM_SWRST (0x4) /* Software reset register */
+#define S5P_DSIM_CLKCTRL (0x8) /* Clock control register */
+#define S5P_DSIM_TIMEOUT (0xc) /* Time out register */
+#define S5P_DSIM_CONFIG (0x10) /* Configuration register */
+#define S5P_DSIM_ESCMODE (0x14) /* Escape mode register */
+
+/* Main display image resolution register */
+#define S5P_DSIM_MDRESOL (0x18)
+#define S5P_DSIM_MVPORCH (0x1c) /* Main display Vporch register */
+#define S5P_DSIM_MHPORCH (0x20) /* Main display Hporch register */
+#define S5P_DSIM_MSYNC (0x24) /* Main display sync area register */
+
+/* Sub display image resolution register */
+#define S5P_DSIM_SDRESOL (0x28)
+#define S5P_DSIM_INTSRC (0x2c) /* Interrupt source register */
+#define S5P_DSIM_INTMSK (0x30) /* Interrupt mask register */
+#define S5P_DSIM_PKTHDR (0x34) /* Packet Header FIFO register */
+#define S5P_DSIM_PAYLOAD (0x38) /* Payload FIFO register */
+#define S5P_DSIM_RXFIFO (0x3c) /* Read FIFO register */
+#define S5P_DSIM_FIFOTHLD (0x40) /* FIFO threshold level register */
+#define S5P_DSIM_FIFOCTRL (0x44) /* FIFO status and control register */
+
+/* FIFO memory AC characteristic register */
+#define S5P_DSIM_PLLCTRL (0x4c) /* PLL control register */
+#define S5P_DSIM_PLLTMR (0x50) /* PLL timer register */
+#define S5P_DSIM_PHYACCHR (0x54) /* D-PHY AC characteristic register */
+#define S5P_DSIM_PHYACCHR1 (0x58) /* D-PHY AC characteristic register1 */
+
+/* DSIM_STATUS */
+#define DSIM_STOP_STATE_DAT(x) (((x) & 0xf) << 0)
+#define DSIM_STOP_STATE_CLK (1 << 8)
+#define DSIM_TX_READY_HS_CLK (1 << 10)
+
+/* DSIM_SWRST */
+#define DSIM_FUNCRST (1 << 16)
+#define DSIM_SWRST (1 << 0)
+
+/* S5P_DSIM_TIMEOUT */
+#define DSIM_LPDR_TOUT_SHIFT (0)
+#define DSIM_BTA_TOUT_SHIFT (16)
+
+/* S5P_DSIM_CLKCTRL */
+#define DSIM_LANE_ESC_CLKEN_SHIFT (19)
+#define DSIM_BYTE_CLKEN_SHIFT (24)
+#define DSIM_BYTE_CLK_SRC_SHIFT (25)
+#define DSIM_PLL_BYPASS_SHIFT (27)
+#define DSIM_ESC_CLKEN_SHIFT (28)
+#define DSIM_TX_REQUEST_HSCLK_SHIFT (31)
+#define DSIM_LANE_ESC_CLKEN(x) (((x) & 0x1f) << \
+ DSIM_LANE_ESC_CLKEN_SHIFT)
+#define DSIM_BYTE_CLK_ENABLE (1 << DSIM_BYTE_CLKEN_SHIFT)
+#define DSIM_BYTE_CLK_DISABLE (0 << DSIM_BYTE_CLKEN_SHIFT)
+#define DSIM_PLL_BYPASS_EXTERNAL (1 << DSIM_PLL_BYPASS_SHIFT)
+#define DSIM_ESC_CLKEN_ENABLE (1 << DSIM_ESC_CLKEN_SHIFT)
+#define DSIM_ESC_CLKEN_DISABLE (0 << DSIM_ESC_CLKEN_SHIFT)
+
+/* S5P_DSIM_CONFIG */
+#define DSIM_NUM_OF_DATALANE_SHIFT (5)
+#define DSIM_HSA_MODE_SHIFT (20)
+#define DSIM_HBP_MODE_SHIFT (21)
+#define DSIM_HFP_MODE_SHIFT (22)
+#define DSIM_HSE_MODE_SHIFT (23)
+#define DSIM_AUTO_MODE_SHIFT (24)
+#define DSIM_LANE_ENx(x) (((x) & 0x1f) << 0)
+
+#define DSIM_NUM_OF_DATA_LANE(x) ((x) << DSIM_NUM_OF_DATALANE_SHIFT)
+
+/* S5P_DSIM_ESCMODE */
+#define DSIM_TX_LPDT_SHIFT (6)
+#define DSIM_CMD_LPDT_SHIFT (7)
+#define DSIM_TX_LPDT_LP (1 << DSIM_TX_LPDT_SHIFT)
+#define DSIM_CMD_LPDT_LP (1 << DSIM_CMD_LPDT_SHIFT)
+#define DSIM_STOP_STATE_CNT_SHIFT (21)
+#define DSIM_FORCE_STOP_STATE_SHIFT (20)
+
+/* S5P_DSIM_MDRESOL */
+#define DSIM_MAIN_STAND_BY (1 << 31)
+#define DSIM_MAIN_VRESOL(x) (((x) & 0x7ff) << 16)
+#define DSIM_MAIN_HRESOL(x) (((x) & 0X7ff) << 0)
+
+/* S5P_DSIM_MVPORCH */
+#define DSIM_CMD_ALLOW_SHIFT (28)
+#define DSIM_STABLE_VFP_SHIFT (16)
+#define DSIM_MAIN_VBP_SHIFT (0)
+#define DSIM_CMD_ALLOW_MASK (0xf << DSIM_CMD_ALLOW_SHIFT)
+#define DSIM_STABLE_VFP_MASK (0x7ff << DSIM_STABLE_VFP_SHIFT)
+#define DSIM_MAIN_VBP_MASK (0x7ff << DSIM_MAIN_VBP_SHIFT)
+
+/* S5P_DSIM_MHPORCH */
+#define DSIM_MAIN_HFP_SHIFT (16)
+#define DSIM_MAIN_HBP_SHIFT (0)
+#define DSIM_MAIN_HFP_MASK ((0xffff) << DSIM_MAIN_HFP_SHIFT)
+#define DSIM_MAIN_HBP_MASK ((0xffff) << DSIM_MAIN_HBP_SHIFT)
+
+/* S5P_DSIM_MSYNC */
+#define DSIM_MAIN_VSA_SHIFT (22)
+#define DSIM_MAIN_HSA_SHIFT (0)
+#define DSIM_MAIN_VSA_MASK ((0x3ff) << DSIM_MAIN_VSA_SHIFT)
+#define DSIM_MAIN_HSA_MASK ((0xffff) << DSIM_MAIN_HSA_SHIFT)
+
+/* S5P_DSIM_SDRESOL */
+#define DSIM_SUB_STANDY_SHIFT (31)
+#define DSIM_SUB_VRESOL_SHIFT (16)
+#define DSIM_SUB_HRESOL_SHIFT (0)
+#define DSIM_SUB_STANDY_MASK ((0x1) << DSIM_SUB_STANDY_SHIFT)
+#define DSIM_SUB_VRESOL_MASK ((0x7ff) << DSIM_SUB_VRESOL_SHIFT)
+#define DSIM_SUB_HRESOL_MASK ((0x7ff) << DSIM_SUB_HRESOL_SHIFT)
+
+/* S5P_DSIM_INTSRC */
+#define INTSRC_FRAME_DONE (1 << 24)
+#define INTSRC_PLL_STABLE (1 << 31)
+
+/* S5P_DSIM_INTMSK */
+#define INTMSK_FRAME_DONE (1 << 24)
+
+/* S5P_DSIM_FIFOCTRL */
+#define SFR_HEADER_EMPTY (1 << 22)
+
+/* S5P_DSIM_PHYACCHR */
+#define DSIM_AFC_CTL(x) (((x) & 0x7) << 5)
+
+/* S5P_DSIM_PLLCTRL */
+#define DSIM_PLL_EN_SHIFT (23)
+#define DSIM_FREQ_BAND_SHIFT (24)
+
+#endif /* _REGS_DSIM_H */
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index e6a8d8c..1e71a54 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -2044,6 +2044,13 @@ config FB_S3C2410_DEBUG
Turn on debugging messages. Note that you can set/unset at run time
through sysfs
+config S5P_MIPI_DSI
+ tristate "Samsung SoC MIPI-DSI support."
+ depends on FB_S3C && (ARCH_S5PV210 || ARCH_EXYNOS4)
+ default n
+ ---help---
+ This enables support for MIPI-DSI device.
+
config FB_NUC900
bool "NUC900 LCD framebuffer support"
depends on FB && ARCH_W90X900
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 2ea44b6..ee5a1d5 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -119,6 +119,8 @@ obj-$(CONFIG_FB_SH7760) += sh7760fb.o
obj-$(CONFIG_FB_IMX) += imxfb.o
obj-$(CONFIG_FB_S3C) += s3c-fb.o
obj-$(CONFIG_FB_S3C2410) += s3c2410fb.o
+obj-$(CONFIG_S5P_MIPI_DSI) += s5p_mipi_dsi.o s5p_mipi_dsi_common.o \
+ s5p_mipi_dsi_lowlevel.o
obj-$(CONFIG_FB_FSL_DIU) += fsl-diu-fb.o
obj-$(CONFIG_FB_COBALT) += cobalt_lcdfb.o
obj-$(CONFIG_FB_PNX4008_DUM) += pnx4008/
diff --git a/drivers/video/s5p_mipi_dsi.c b/drivers/video/s5p_mipi_dsi.c
new file mode 100644
index 0000000..50fc00e
--- /dev/null
+++ b/drivers/video/s5p_mipi_dsi.c
@@ -0,0 +1,481 @@
+/* linux/drivers/video/s5p_mipi_dsi.c
+ *
+ * Samsung SoC MIPI-DSIM driver.
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * InKi Dae, <inki.dae@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/clk.h>
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/fb.h>
+#include <linux/ctype.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/memory.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/kthread.h>
+#include <linux/notifier.h>
+
+#include <plat/fb.h>
+#include <plat/mipi_dsim.h>
+
+#include "s5p_mipi_dsi_common.h"
+
+#define master_to_driver(a) (a->dsim_lcd_drv)
+#define master_to_device(a) (a->dsim_lcd_dev)
+
+struct mipi_dsim_ddi {
+ int bus_id;
+ struct list_head list;
+ struct mipi_dsim_lcd_device *dsim_lcd_dev;
+ struct mipi_dsim_lcd_driver *dsim_lcd_drv;
+};
+
+static LIST_HEAD(dsim_ddi_list);
+static LIST_HEAD(dsim_lcd_dev_list);
+
+static DEFINE_MUTEX(mipi_dsim_lock);
+
+static struct s5p_platform_mipi_dsim *to_dsim_plat(struct platform_device *pdev)
+{
+ return (struct s5p_platform_mipi_dsim *)pdev->dev.platform_data;
+}
+
+static irqreturn_t s5p_mipi_dsi_interrupt_handler(int irq, void *dev_id)
+{
+ return IRQ_HANDLED;
+}
+
+int s5p_mipi_dsi_register_lcd_device(struct mipi_dsim_lcd_device *lcd_dev)
+{
+ struct mipi_dsim_ddi *dsim_ddi;
+
+ if (!lcd_dev) {
+ printk(KERN_ERR "mipi_dsim_lcd_device is NULL.\n");
+ return -EFAULT;
+ }
+
+ if (!lcd_dev->name) {
+ printk(KERN_ERR "dsim_lcd_device name is NULL.\n");
+ return -EFAULT;
+ }
+
+ dsim_ddi = kzalloc(sizeof(struct mipi_dsim_ddi), GFP_KERNEL);
+ if (!dsim_ddi) {
+ printk(KERN_ERR "failed to allocate dsim_ddi object.\n");
+ return -EFAULT;
+ }
+
+ dsim_ddi->dsim_lcd_dev = lcd_dev;
+
+ mutex_lock(&mipi_dsim_lock);
+ list_add_tail(&dsim_ddi->list, &dsim_ddi_list);
+ mutex_unlock(&mipi_dsim_lock);
+
+ return 0;
+}
+
+struct mipi_dsim_ddi
+ *s5p_mipi_dsi_find_lcd_device(struct mipi_dsim_lcd_driver *lcd_drv)
+{
+ struct mipi_dsim_ddi *dsim_ddi;
+ struct mipi_dsim_lcd_device *lcd_dev;
+
+ mutex_lock(&mipi_dsim_lock);
+
+ list_for_each_entry(dsim_ddi, &dsim_ddi_list, list) {
+ lcd_dev = dsim_ddi->dsim_lcd_dev;
+ if (!lcd_dev)
+ continue;
+
+ if (lcd_drv->id >= 0) {
+ if ((strcmp(lcd_drv->name, lcd_dev->name)) = 0 &&
+ lcd_drv->id = lcd_dev->id) {
+ /**
+ * bus_id would be used to identify
+ * connected bus.
+ */
+ dsim_ddi->bus_id = lcd_dev->bus_id;
+ mutex_unlock(&mipi_dsim_lock);
+
+ return dsim_ddi;
+ }
+ } else {
+ if ((strcmp(lcd_drv->name, lcd_dev->name)) = 0) {
+ /**
+ * bus_id would be used to identify
+ * connected bus.
+ */
+ dsim_ddi->bus_id = lcd_dev->bus_id;
+ mutex_unlock(&mipi_dsim_lock);
+
+ return dsim_ddi;
+ }
+ }
+
+ kfree(dsim_ddi);
+ list_del(&dsim_ddi_list);
+ }
+
+ mutex_unlock(&mipi_dsim_lock);
+
+ return NULL;
+}
+
+int s5p_mipi_dsi_register_lcd_driver(struct mipi_dsim_lcd_driver *lcd_drv)
+{
+ struct mipi_dsim_ddi *dsim_ddi;
+
+ if (!lcd_drv) {
+ printk(KERN_ERR "mipi_dsim_lcd_driver is NULL.\n");
+ return -EFAULT;
+ }
+
+ if (!lcd_drv->name) {
+ printk(KERN_ERR "dsim_lcd_driver name is NULL.\n");
+ return -EFAULT;
+ }
+
+ dsim_ddi = s5p_mipi_dsi_find_lcd_device(lcd_drv);
+ if (!dsim_ddi) {
+ printk(KERN_ERR "mipi_dsim_ddi object not found.\n");
+ return -EFAULT;
+ }
+
+ dsim_ddi->dsim_lcd_drv = lcd_drv;
+
+ printk(KERN_INFO "registered panel driver(%s) to mipi-dsi driver.\n",
+ lcd_drv->name);
+
+ return 0;
+
+}
+
+struct mipi_dsim_ddi
+ *s5p_mipi_dsi_bind_lcd_ddi(struct mipi_dsim_device *dsim,
+ const char *name)
+{
+ struct mipi_dsim_ddi *dsim_ddi;
+ struct mipi_dsim_lcd_driver *lcd_drv;
+ struct mipi_dsim_lcd_device *lcd_dev;
+ int ret;
+
+ mutex_lock(&dsim->lock);
+
+ list_for_each_entry(dsim_ddi, &dsim_ddi_list, list) {
+ lcd_drv = dsim_ddi->dsim_lcd_drv;
+ lcd_dev = dsim_ddi->dsim_lcd_dev;
+ if (!lcd_drv || !lcd_dev ||
+ (dsim->id != dsim_ddi->bus_id))
+ continue;
+
+ dev_dbg(dsim->dev, "lcd_drv->id = %d, lcd_dev->id = %d\n",
+ lcd_drv->id, lcd_dev->id);
+ dev_dbg(dsim->dev, "lcd_dev->bus_id = %d, dsim->id = %d\n",
+ lcd_dev->bus_id, dsim->id);
+
+ if ((strcmp(lcd_drv->name, name) = 0)) {
+ lcd_dev->master = dsim;
+
+ lcd_dev->dev.parent = dsim->dev;
+ dev_set_name(&lcd_dev->dev, "%s", lcd_drv->name);
+
+ ret = device_register(&lcd_dev->dev);
+ if (ret < 0) {
+ dev_err(dsim->dev,
+ "can't register %s, status %d\n",
+ dev_name(&lcd_dev->dev), ret);
+ mutex_unlock(&dsim->lock);
+
+ return NULL;
+ }
+
+ dsim->dsim_lcd_dev = lcd_dev;
+ dsim->dsim_lcd_drv = lcd_drv;
+
+ mutex_unlock(&dsim->lock);
+
+ return dsim_ddi;
+ }
+ }
+
+ mutex_unlock(&dsim->lock);
+
+ return NULL;
+}
+
+/* define MIPI-DSI Master operations. */
+static struct mipi_dsim_master_ops master_ops = {
+ .cmd_write = s5p_mipi_dsi_wr_data,
+ .get_dsim_frame_done = s5p_mipi_dsi_get_frame_done_status,
+ .clear_dsim_frame_done = s5p_mipi_dsi_clear_frame_done,
+};
+
+static int s5p_mipi_dsi_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct mipi_dsim_device *dsim;
+ struct mipi_dsim_config *dsim_config;
+ struct s5p_platform_mipi_dsim *dsim_pd;
+ struct mipi_dsim_ddi *dsim_ddi;
+ int ret = -1;
+
+ dsim = kzalloc(sizeof(struct mipi_dsim_device), GFP_KERNEL);
+ if (!dsim) {
+ dev_err(&pdev->dev, "failed to allocate dsim object.\n");
+ return -EFAULT;
+ }
+
+ dsim->pd = to_dsim_plat(pdev);
+ dsim->dev = &pdev->dev;
+ dsim->id = pdev->id;
+ dsim->resume_complete = 0;
+
+ /* get s5p_platform_mipi_dsim. */
+ dsim_pd = (struct s5p_platform_mipi_dsim *)dsim->pd;
+ if (dsim_pd = NULL) {
+ dev_err(&pdev->dev, "failed to get platform data for dsim.\n");
+ return -EFAULT;
+ }
+ /* get mipi_dsim_config. */
+ dsim_config = dsim_pd->dsim_config;
+ if (dsim_config = NULL) {
+ dev_err(&pdev->dev, "failed to get dsim config data.\n");
+ return -EFAULT;
+ }
+
+ dsim->dsim_config = dsim_config;
+ dsim->master_ops = &master_ops;
+
+ dsim->clock = clk_get(&pdev->dev, "dsim");
+ if (IS_ERR(dsim->clock)) {
+ dev_err(&pdev->dev, "failed to get dsim clock source\n");
+ goto err_clock_get;
+ }
+
+ clk_enable(dsim->clock);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "failed to get io memory region\n");
+ ret = -EINVAL;
+ goto err_platform_get;
+ }
+
+ res = request_mem_region(res->start, resource_size(res),
+ dev_name(&pdev->dev));
+ if (!res) {
+ dev_err(&pdev->dev, "failed to request io memory region\n");
+ ret = -EINVAL;
+ goto err_mem_region;
+ }
+
+ dsim->res = res;
+
+ dsim->reg_base = ioremap(res->start, resource_size(res));
+ if (!dsim->reg_base) {
+ dev_err(&pdev->dev, "failed to remap io region\n");
+ ret = -EINVAL;
+ goto err_mem_region;
+ }
+
+ /*
+ * in case of MIPI Video mode,
+ * frame done interrupt handler would be used.
+ */
+ if (dsim_config->e_interface = DSIM_VIDEO) {
+ dsim->irq = platform_get_irq(pdev, 0);
+ if (request_irq(dsim->irq, s5p_mipi_dsi_interrupt_handler,
+ IRQF_DISABLED, "mipi-dsi", dsim)) {
+ dev_err(&pdev->dev, "request_irq failed.\n");
+ goto err_request_irq;
+ }
+ }
+
+ mutex_init(&dsim->lock);
+
+ if (dsim->pd->mipi_power)
+ dsim->pd->mipi_power(pdev, 1);
+ else {
+ dev_err(&pdev->dev, "mipi_power is NULL.\n");
+ goto err_request_irq;
+ }
+
+ /* bind lcd ddi matched with panel name. */
+ dsim_ddi = s5p_mipi_dsi_bind_lcd_ddi(dsim, dsim_pd->lcd_panel_name);
+ if (!dsim_ddi) {
+ dev_err(&pdev->dev, "mipi_dsim_ddi object not found.\n");
+ goto err_bind;
+ }
+
+ /* enable MIPI-DSI PHY. */
+ if (dsim->pd->phy_enable)
+ dsim->pd->phy_enable(pdev, true);
+
+ s5p_mipi_dsi_init_dsim(dsim);
+ s5p_mipi_dsi_init_link(dsim);
+
+ s5p_mipi_dsi_set_hs_enable(dsim);
+
+ /* set display timing. */
+ s5p_mipi_dsi_set_display_mode(dsim, dsim->dsim_config);
+
+ platform_set_drvdata(pdev, dsim);
+
+ /* initialize mipi-dsi client(lcd panel). */
+ if (dsim_ddi->dsim_lcd_drv && dsim_ddi->dsim_lcd_drv->probe)
+ dsim_ddi->dsim_lcd_drv->probe(dsim_ddi->dsim_lcd_dev);
+
+ dev_dbg(&pdev->dev, "mipi-dsi driver(%s mode) has been probed.\n",
+ (dsim_config->e_interface = DSIM_COMMAND) ?
+ "CPU" : "RGB");
+
+ return 0;
+
+err_bind:
+ dsim->pd->mipi_power(pdev, 0);
+
+err_request_irq:
+ release_resource(dsim->res);
+ kfree(dsim->res);
+
+ iounmap((void __iomem *) dsim->reg_base);
+
+err_mem_region:
+err_platform_get:
+ clk_disable(dsim->clock);
+
+err_clock_get:
+ clk_put(dsim->clock);
+ kfree(dsim);
+
+ return ret;
+
+}
+
+static int __devexit s5p_mipi_dsi_remove(struct platform_device *pdev)
+{
+ struct mipi_dsim_device *dsim = platform_get_drvdata(pdev);
+ struct mipi_dsim_ddi *dsim_ddi = NULL;
+
+ if (dsim->dsim_config->e_interface = DSIM_VIDEO)
+ free_irq(dsim->irq, dsim);
+
+ iounmap(dsim->reg_base);
+
+ clk_disable(dsim->clock);
+ clk_put(dsim->clock);
+
+ release_resource(dsim->res);
+ kfree(dsim->res);
+
+ list_for_each_entry(dsim_ddi, &dsim_ddi_list, list) {
+ if (dsim_ddi) {
+ if (dsim->id = dsim_ddi->bus_id) {
+ kfree(dsim_ddi);
+ dsim_ddi = NULL;
+ }
+ }
+ }
+
+ kfree(dsim);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int s5p_mipi_dsi_suspend(struct platform_device *pdev,
+ pm_message_t state)
+{
+ struct mipi_dsim_device *dsim = platform_get_drvdata(pdev);
+
+ dsim->resume_complete = 0;
+
+ if (master_to_driver(dsim) && (master_to_driver(dsim))->suspend)
+ (master_to_driver(dsim))->suspend(master_to_device(dsim));
+
+ clk_disable(dsim->clock);
+
+ if (dsim->pd->mipi_power)
+ dsim->pd->mipi_power(pdev, 0);
+
+ return 0;
+}
+
+static int s5p_mipi_dsi_resume(struct platform_device *pdev)
+{
+ struct mipi_dsim_device *dsim = platform_get_drvdata(pdev);
+
+ if (dsim->pd->mipi_power)
+ dsim->pd->mipi_power(pdev, 1);
+
+ clk_enable(dsim->clock);
+
+ s5p_mipi_dsi_init_dsim(dsim);
+ s5p_mipi_dsi_init_link(dsim);
+
+ s5p_mipi_dsi_set_hs_enable(dsim);
+
+ /* change cpu command transfer mode to hs. */
+ s5p_mipi_dsi_set_data_transfer_mode(dsim, 0);
+
+ if (master_to_driver(dsim) && (master_to_driver(dsim))->resume)
+ (master_to_driver(dsim))->resume(master_to_device(dsim));
+
+ s5p_mipi_dsi_set_display_mode(dsim, dsim->dsim_config);
+
+ /* change lcdc data transfer mode to hs. */
+ s5p_mipi_dsi_set_data_transfer_mode(dsim, 1);
+
+ dsim->resume_complete = 1;
+
+ return 0;
+}
+#else
+#define s5p_mipi_dsi_suspend NULL
+#define s5p_mipi_dsi_resume NULL
+#endif
+
+static struct platform_driver s5p_mipi_dsi_driver = {
+ .probe = s5p_mipi_dsi_probe,
+ .remove = __devexit_p(s5p_mipi_dsi_remove),
+ .suspend = s5p_mipi_dsi_suspend,
+ .resume = s5p_mipi_dsi_resume,
+ .driver = {
+ .name = "s5p-mipi-dsim",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int s5p_mipi_dsi_register(void)
+{
+ platform_driver_register(&s5p_mipi_dsi_driver);
+
+ return 0;
+}
+
+static void s5p_mipi_dsi_unregister(void)
+{
+ platform_driver_unregister(&s5p_mipi_dsi_driver);
+}
+
+module_init(s5p_mipi_dsi_register);
+module_exit(s5p_mipi_dsi_unregister);
+
+MODULE_AUTHOR("InKi Dae <inki.dae@samsung.com>");
+MODULE_DESCRIPTION("Samusung SoC MIPI-DSI driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/s5p_mipi_dsi_common.c b/drivers/video/s5p_mipi_dsi_common.c
new file mode 100644
index 0000000..51ee4ed
--- /dev/null
+++ b/drivers/video/s5p_mipi_dsi_common.c
@@ -0,0 +1,655 @@
+/* linux/drivers/video/s5p_mipi_dsi_common.c
+ *
+ * Samsung SoC MIPI-DSI common driver.
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * InKi Dae, <inki.dae@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/fs.h>
+#include <linux/mm.h>
+#include <linux/fb.h>
+#include <linux/ctype.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/memory.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+
+#include <video/mipi_display.h>
+
+#include <plat/fb.h>
+#include <plat/regs-dsim.h>
+
+#include <mach/map.h>
+#include <plat/mipi_dsim.h>
+#include <plat/regs-dsim.h>
+
+#include "s5p_mipi_dsi_lowlevel.h"
+
+#define MHZ (1000 * 1000)
+#define FIN_HZ (24 * MHZ)
+
+#define DFIN_PLL_MIN_HZ (6 * MHZ)
+#define DFIN_PLL_MAX_HZ (12 * MHZ)
+
+#define DFVCO_MIN_HZ (500 * MHZ)
+#define DFVCO_MAX_HZ (1000 * MHZ)
+
+#define TRY_GET_FIFO_TIMEOUT (5000 * 2)
+
+#define DSIM_ESCCLK_ON (0x0)
+#define DSIM_ESCCLK_OFF (0x1)
+
+/* MIPI-DSIM status types. */
+enum {
+ DSIM_STATE_INIT, /* should be initialized. */
+ DSIM_STATE_STOP, /* CPU and LCDC are LP mode. */
+ DSIM_STATE_HSCLKEN, /* HS clock was enabled. */
+ DSIM_STATE_ULPS
+};
+
+/* define DSI lane types. */
+enum {
+ DSIM_LANE_CLOCK = (1 << 0),
+ DSIM_LANE_DATA0 = (1 << 1),
+ DSIM_LANE_DATA1 = (1 << 2),
+ DSIM_LANE_DATA2 = (1 << 3),
+ DSIM_LANE_DATA3 = (1 << 4)
+};
+
+static unsigned int dpll_table[15] = {
+ 100, 120, 170, 220, 270,
+ 320, 390, 450, 510, 560,
+ 640, 690, 770, 870, 950 };
+
+static void s5p_mipi_dsi_long_data_wr(struct mipi_dsim_device *dsim,
+ unsigned int data0, unsigned int data1)
+{
+ unsigned int data_cnt = 0, payload = 0;
+
+ /* in case that data count is more then 4 */
+ for (data_cnt = 0; data_cnt < data1; data_cnt += 4) {
+ /*
+ * after sending 4bytes per one time,
+ * send remainder data less then 4.
+ */
+ if ((data1 - data_cnt) < 4) {
+ if ((data1 - data_cnt) = 3) {
+ payload = *(u8 *)(data0 + data_cnt) |
+ (*(u8 *)(data0 + (data_cnt + 1))) << 8 |
+ (*(u8 *)(data0 + (data_cnt + 2))) << 16;
+ dev_dbg(dsim->dev, "count = 3 payload = %x, %x %x %x\n",
+ payload, *(u8 *)(data0 + data_cnt),
+ *(u8 *)(data0 + (data_cnt + 1)),
+ *(u8 *)(data0 + (data_cnt + 2)));
+ } else if ((data1 - data_cnt) = 2) {
+ payload = *(u8 *)(data0 + data_cnt) |
+ (*(u8 *)(data0 + (data_cnt + 1))) << 8;
+ dev_dbg(dsim->dev,
+ "count = 2 payload = %x, %x %x\n", payload,
+ *(u8 *)(data0 + data_cnt),
+ *(u8 *)(data0 + (data_cnt + 1)));
+ } else if ((data1 - data_cnt) = 1) {
+ payload = *(u8 *)(data0 + data_cnt);
+ }
+
+ s5p_mipi_dsi_wr_tx_data(dsim, payload);
+ /* send 4bytes per one time. */
+ } else {
+ payload = *(u8 *)(data0 + data_cnt) |
+ (*(u8 *)(data0 + (data_cnt + 1))) << 8 |
+ (*(u8 *)(data0 + (data_cnt + 2))) << 16 |
+ (*(u8 *)(data0 + (data_cnt + 3))) << 24;
+
+ dev_dbg(dsim->dev,
+ "count = 4 payload = %x, %x %x %x %x\n",
+ payload, *(u8 *)(data0 + data_cnt),
+ *(u8 *)(data0 + (data_cnt + 1)),
+ *(u8 *)(data0 + (data_cnt + 2)),
+ *(u8 *)(data0 + (data_cnt + 3)));
+
+ s5p_mipi_dsi_wr_tx_data(dsim, payload);
+ }
+ }
+}
+
+int s5p_mipi_dsi_wr_data(struct mipi_dsim_device *dsim, unsigned int data_id,
+ unsigned int data0, unsigned int data1)
+{
+ unsigned int timeout = TRY_GET_FIFO_TIMEOUT;
+ unsigned long delay_val, udelay;
+ unsigned int check_rx_ack = 0;
+
+ if (dsim->state = DSIM_STATE_ULPS) {
+ dev_err(dsim->dev, "state is ULPS.\n");
+
+ return -EINVAL;
+ }
+
+ delay_val = MHZ / dsim->dsim_config->esc_clk;
+ udelay = 10 * delay_val;
+
+ mdelay(udelay);
+
+ /* only if transfer mode is LPDT, wait SFR becomes empty. */
+ if (dsim->state = DSIM_STATE_STOP) {
+ while (!(s5p_mipi_dsi_get_fifo_state(dsim) &
+ SFR_HEADER_EMPTY)) {
+ if ((timeout--) > 0)
+ mdelay(1);
+ else {
+ dev_err(dsim->dev,
+ "SRF header fifo is not empty.\n");
+ return -EINVAL;
+ }
+ }
+ }
+
+ switch (data_id) {
+ /* short packet types of packet types for command. */
+ case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM:
+ case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM:
+ case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM:
+ case MIPI_DSI_DCS_SHORT_WRITE:
+ case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
+ case MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE:
+ s5p_mipi_dsi_wr_tx_header(dsim, data_id, data0, data1);
+ if (check_rx_ack)
+ /* process response func should be implemented */
+ return 0;
+ else
+ return -EINVAL;
+
+ /* general command */
+ case MIPI_DSI_COLOR_MODE_OFF:
+ case MIPI_DSI_COLOR_MODE_ON:
+ case MIPI_DSI_SHUTDOWN_PERIPHERAL:
+ case MIPI_DSI_TURN_ON_PERIPHERAL:
+ s5p_mipi_dsi_wr_tx_header(dsim, data_id, data0, data1);
+ if (check_rx_ack)
+ /* process response func should be implemented. */
+ return 0;
+ else
+ return -EINVAL;
+
+ /* packet types for video data */
+ case MIPI_DSI_V_SYNC_START:
+ case MIPI_DSI_V_SYNC_END:
+ case MIPI_DSI_H_SYNC_START:
+ case MIPI_DSI_H_SYNC_END:
+ case MIPI_DSI_END_OF_TRANSMISSION:
+ return 0;
+
+ /* short and response packet types for command */
+ case MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM:
+ case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM:
+ case MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM:
+ case MIPI_DSI_DCS_READ:
+ s5p_mipi_dsi_clear_all_interrupt(dsim);
+ s5p_mipi_dsi_wr_tx_header(dsim, data_id, data0, data1);
+ /* process response func should be implemented. */
+ return 0;
+
+ /* long packet type and null packet */
+ case MIPI_DSI_NULL_PACKET:
+ case MIPI_DSI_BLANKING_PACKET:
+ return 0;
+ case MIPI_DSI_GENERIC_LONG_WRITE:
+ case MIPI_DSI_DCS_LONG_WRITE:
+ {
+ unsigned int size, data_cnt = 0, payload = 0;
+
+ size = data1 * 4;
+
+ /* if data count is less then 4, then send 3bytes data. */
+ if (data1 < 4) {
+ payload = *(u8 *)(data0) |
+ *(u8 *)(data0 + 1) << 8 |
+ *(u8 *)(data0 + 2) << 16;
+
+ s5p_mipi_dsi_wr_tx_data(dsim, payload);
+
+ dev_dbg(dsim->dev, "count = %d payload = %x,%x %x %x\n",
+ data1, payload,
+ *(u8 *)(data0 + data_cnt),
+ *(u8 *)(data0 + (data_cnt + 1)),
+ *(u8 *)(data0 + (data_cnt + 2)));
+ /* in case that data count is more then 4 */
+ } else
+ s5p_mipi_dsi_long_data_wr(dsim, data0, data1);
+
+ /* put data into header fifo */
+ s5p_mipi_dsi_wr_tx_header(dsim, data_id, data1 & 0xff,
+ (data1 & 0xff00) >> 8);
+
+ }
+ if (check_rx_ack)
+ /* process response func should be implemented. */
+ return 0;
+ else
+ return -EINVAL;
+
+ /* packet typo for video data */
+ case MIPI_DSI_PACKED_PIXEL_STREAM_16:
+ case MIPI_DSI_PACKED_PIXEL_STREAM_18:
+ case MIPI_DSI_PIXEL_STREAM_3BYTE_18:
+ case MIPI_DSI_PACKED_PIXEL_STREAM_24:
+ if (check_rx_ack)
+ /* process response func should be implemented. */
+ return 0;
+ else
+ return -EINVAL;
+ default:
+ dev_warn(dsim->dev,
+ "data id %x is not supported current DSI spec.\n",
+ data_id);
+
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int s5p_mipi_dsi_pll_on(struct mipi_dsim_device *dsim, unsigned int enable)
+{
+ int sw_timeout;
+
+ if (enable) {
+ sw_timeout = 1000;
+
+ s5p_mipi_dsi_clear_interrupt(dsim);
+ s5p_mipi_dsi_enable_pll(dsim, 1);
+ while (1) {
+ sw_timeout--;
+ if (s5p_mipi_dsi_is_pll_stable(dsim))
+ return 0;
+ if (sw_timeout = 0)
+ return -EINVAL;
+ }
+ } else
+ s5p_mipi_dsi_enable_pll(dsim, 0);
+
+ return 0;
+}
+
+unsigned long s5p_mipi_dsi_change_pll(struct mipi_dsim_device *dsim,
+ unsigned int pre_divider, unsigned int main_divider,
+ unsigned int scaler)
+{
+ unsigned long dfin_pll, dfvco, dpll_out;
+ unsigned int i, freq_band = 0xf;
+
+ dfin_pll = (FIN_HZ / pre_divider);
+
+ /******************************************************
+ * Serial Clock(=ByteClk X 8) FreqBand[3:0] *
+ ******************************************************
+ * ~ 99.99 MHz 0000
+ * 100 ~ 119.99 MHz 0001
+ * 120 ~ 159.99 MHz 0010
+ * 160 ~ 199.99 MHz 0011
+ * 200 ~ 239.99 MHz 0100
+ * 140 ~ 319.99 MHz 0101
+ * 320 ~ 389.99 MHz 0110
+ * 390 ~ 449.99 MHz 0111
+ * 450 ~ 509.99 MHz 1000
+ * 510 ~ 559.99 MHz 1001
+ * 560 ~ 639.99 MHz 1010
+ * 640 ~ 689.99 MHz 1011
+ * 690 ~ 769.99 MHz 1100
+ * 770 ~ 869.99 MHz 1101
+ * 870 ~ 949.99 MHz 1110
+ * 950 ~ 1000 MHz 1111
+ ******************************************************/
+ if (dfin_pll < DFIN_PLL_MIN_HZ || dfin_pll > DFIN_PLL_MAX_HZ) {
+ dev_warn(dsim->dev, "fin_pll range should be 6MHz ~ 12MHz\n");
+ s5p_mipi_dsi_enable_afc(dsim, 0, 0);
+ } else {
+ if (dfin_pll < 7 * MHZ)
+ s5p_mipi_dsi_enable_afc(dsim, 1, 0x1);
+ else if (dfin_pll < 8 * MHZ)
+ s5p_mipi_dsi_enable_afc(dsim, 1, 0x0);
+ else if (dfin_pll < 9 * MHZ)
+ s5p_mipi_dsi_enable_afc(dsim, 1, 0x3);
+ else if (dfin_pll < 10 * MHZ)
+ s5p_mipi_dsi_enable_afc(dsim, 1, 0x2);
+ else if (dfin_pll < 11 * MHZ)
+ s5p_mipi_dsi_enable_afc(dsim, 1, 0x5);
+ else
+ s5p_mipi_dsi_enable_afc(dsim, 1, 0x4);
+ }
+
+ dfvco = dfin_pll * main_divider;
+ dev_dbg(dsim->dev, "dfvco = %lu, dfin_pll = %lu, main_divider = %d\n",
+ dfvco, dfin_pll, main_divider);
+ if (dfvco < DFVCO_MIN_HZ || dfvco > DFVCO_MAX_HZ)
+ dev_warn(dsim->dev, "fvco range should be 500MHz ~ 1000MHz\n");
+
+ dpll_out = dfvco / (1 << scaler);
+ dev_dbg(dsim->dev, "dpll_out = %lu, dfvco = %lu, scaler = %d\n",
+ dpll_out, dfvco, scaler);
+
+ for (i = 0; i < ARRAY_SIZE(dpll_table); i++) {
+ if (dpll_out < dpll_table[i] * MHZ) {
+ freq_band = i;
+ break;
+ }
+ }
+
+ dev_dbg(dsim->dev, "freq_band = %d\n", freq_band);
+
+ s5p_mipi_dsi_pll_freq(dsim, pre_divider, main_divider, scaler);
+
+ s5p_mipi_dsi_hs_zero_ctrl(dsim, 0);
+ s5p_mipi_dsi_prep_ctrl(dsim, 0);
+
+ /* Freq Band */
+ s5p_mipi_dsi_pll_freq_band(dsim, freq_band);
+
+ /* Stable time */
+ s5p_mipi_dsi_pll_stable_time(dsim, dsim->dsim_config->pll_stable_time);
+
+ /* Enable PLL */
+ dev_dbg(dsim->dev, "FOUT of mipi dphy pll is %luMHz\n",
+ (dpll_out / MHZ));
+
+ return dpll_out;
+}
+
+int s5p_mipi_dsi_set_clock(struct mipi_dsim_device *dsim,
+ unsigned int byte_clk_sel, unsigned int enable)
+{
+ unsigned int esc_div;
+ unsigned long esc_clk_error_rate;
+ unsigned long hs_clk = 0, byte_clk = 0, escape_clk = 0;
+
+ if (enable) {
+ dsim->e_clk_src = byte_clk_sel;
+
+ /* Escape mode clock and byte clock source */
+ s5p_mipi_dsi_set_byte_clock_src(dsim, byte_clk_sel);
+
+ /* DPHY, DSIM Link : D-PHY clock out */
+ if (byte_clk_sel = DSIM_PLL_OUT_DIV8) {
+ hs_clk = s5p_mipi_dsi_change_pll(dsim,
+ dsim->dsim_config->p, dsim->dsim_config->m,
+ dsim->dsim_config->s);
+ if (hs_clk = 0) {
+ dev_err(dsim->dev,
+ "failed to get hs clock.\n");
+ return -EINVAL;
+ }
+
+ byte_clk = hs_clk / 8;
+ s5p_mipi_dsi_enable_pll_bypass(dsim, 0);
+ s5p_mipi_dsi_pll_on(dsim, 1);
+ /* DPHY : D-PHY clock out, DSIM link : external clock out */
+ } else if (byte_clk_sel = DSIM_EXT_CLK_DIV8)
+ dev_warn(dsim->dev,
+ "this project is not support \
+ external clock source for MIPI DSIM\n");
+ else if (byte_clk_sel = DSIM_EXT_CLK_BYPASS)
+ dev_warn(dsim->dev,
+ "this project is not support \
+ external clock source for MIPI DSIM\n");
+
+ /* escape clock divider */
+ esc_div = byte_clk / (dsim->dsim_config->esc_clk);
+ dev_dbg(dsim->dev,
+ "esc_div = %d, byte_clk = %lu, esc_clk = %lu\n",
+ esc_div, byte_clk, dsim->dsim_config->esc_clk);
+ if ((byte_clk / esc_div) >= (20 * MHZ) ||
+ (byte_clk / esc_div) >
+ dsim->dsim_config->esc_clk)
+ esc_div += 1;
+
+ escape_clk = byte_clk / esc_div;
+ dev_dbg(dsim->dev,
+ "escape_clk = %lu, byte_clk = %lu, esc_div = %d\n",
+ escape_clk, byte_clk, esc_div);
+
+ /* enable escape clock. */
+ s5p_mipi_dsi_enable_byte_clock(dsim, DSIM_ESCCLK_ON);
+
+ /* enable byte clk and escape clock */
+ s5p_mipi_dsi_set_esc_clk_prs(dsim, 1, esc_div);
+ /* escape clock on lane */
+ s5p_mipi_dsi_enable_esc_clk_on_lane(dsim,
+ (DSIM_LANE_CLOCK | dsim->data_lane), 1);
+
+ dev_dbg(dsim->dev, "byte clock is %luMHz\n",
+ (byte_clk / MHZ));
+ dev_dbg(dsim->dev, "escape clock that user's need is %lu\n",
+ (dsim->dsim_config->esc_clk / MHZ));
+ dev_dbg(dsim->dev, "escape clock divider is %x\n", esc_div);
+ dev_dbg(dsim->dev, "escape clock is %luMHz\n",
+ ((byte_clk / esc_div) / MHZ));
+
+ if ((byte_clk / esc_div) > escape_clk) {
+ esc_clk_error_rate = escape_clk /
+ (byte_clk / esc_div);
+ dev_warn(dsim->dev, "error rate is %lu over.\n",
+ (esc_clk_error_rate / 100));
+ } else if ((byte_clk / esc_div) < (escape_clk)) {
+ esc_clk_error_rate = (byte_clk / esc_div) /
+ escape_clk;
+ dev_warn(dsim->dev, "error rate is %lu under.\n",
+ (esc_clk_error_rate / 100));
+ }
+ } else {
+ s5p_mipi_dsi_enable_esc_clk_on_lane(dsim,
+ (DSIM_LANE_CLOCK | dsim->data_lane), 0);
+ s5p_mipi_dsi_set_esc_clk_prs(dsim, 0, 0);
+
+ /* disable escape clock. */
+ s5p_mipi_dsi_enable_byte_clock(dsim, DSIM_ESCCLK_OFF);
+
+ if (byte_clk_sel = DSIM_PLL_OUT_DIV8)
+ s5p_mipi_dsi_pll_on(dsim, 0);
+ }
+
+ return 0;
+}
+
+int s5p_mipi_dsi_init_dsim(struct mipi_dsim_device *dsim)
+{
+ dsim->state = DSIM_STATE_INIT;
+
+ switch (dsim->dsim_config->e_no_data_lane) {
+ case DSIM_DATA_LANE_1:
+ dsim->data_lane = DSIM_LANE_DATA0;
+ break;
+ case DSIM_DATA_LANE_2:
+ dsim->data_lane = DSIM_LANE_DATA0 | DSIM_LANE_DATA1;
+ break;
+ case DSIM_DATA_LANE_3:
+ dsim->data_lane = DSIM_LANE_DATA0 | DSIM_LANE_DATA1 |
+ DSIM_LANE_DATA2;
+ break;
+ case DSIM_DATA_LANE_4:
+ dsim->data_lane = DSIM_LANE_DATA0 | DSIM_LANE_DATA1 |
+ DSIM_LANE_DATA2 | DSIM_LANE_DATA3;
+ break;
+ default:
+ dev_info(dsim->dev, "data lane is invalid.\n");
+ return -EINVAL;
+ };
+
+ s5p_mipi_dsi_sw_reset(dsim);
+ s5p_mipi_dsi_dp_dn_swap(dsim, 0);
+
+ return 0;
+}
+
+int s5p_mipi_dsi_enable_frame_done_int(struct mipi_dsim_device *dsim,
+ unsigned int enable)
+{
+ /* enable only frame done interrupt */
+ s5p_mipi_dsi_set_interrupt_mask(dsim, INTMSK_FRAME_DONE, enable);
+
+ return 0;
+}
+
+int s5p_mipi_dsi_set_display_mode(struct mipi_dsim_device *dsim,
+ struct mipi_dsim_config *dsim_config)
+{
+ struct s5p_platform_mipi_dsim *dsim_pd;
+ struct fb_videomode *lcd_video = NULL;
+
+ dsim_pd = (struct s5p_platform_mipi_dsim *)dsim->pd;
+ lcd_video = (struct fb_videomode *)dsim_pd->lcd_panel_info;
+
+ /* in case of VIDEO MODE (RGB INTERFACE), it sets polarities. */
+ if (dsim->dsim_config->e_interface = (u32) DSIM_VIDEO) {
+ if (dsim->dsim_config->auto_vertical_cnt = 0) {
+ s5p_mipi_dsi_set_main_disp_vporch(dsim,
+ lcd_video->upper_margin,
+ lcd_video->lower_margin, 0);
+ s5p_mipi_dsi_set_main_disp_hporch(dsim,
+ lcd_video->left_margin,
+ lcd_video->right_margin);
+ s5p_mipi_dsi_set_main_disp_sync_area(dsim,
+ lcd_video->vsync_len,
+ lcd_video->hsync_len);
+ }
+ }
+
+ s5p_mipi_dsi_set_main_disp_resol(dsim, lcd_video->xres,
+ lcd_video->yres);
+
+ s5p_mipi_dsi_display_config(dsim, dsim->dsim_config);
+
+ dev_dbg(dsim->dev, "lcd panel => width = %d, height = %d\n",
+ lcd_video->xres, lcd_video->yres);
+
+ return 0;
+}
+
+int s5p_mipi_dsi_init_link(struct mipi_dsim_device *dsim)
+{
+ unsigned int time_out = 100;
+
+ switch (dsim->state) {
+ case DSIM_STATE_INIT:
+ s5p_mipi_dsi_sw_reset(dsim);
+
+ s5p_mipi_dsi_init_fifo_pointer(dsim, 0x1f);
+
+ /* dsi configuration */
+ s5p_mipi_dsi_init_config(dsim);
+ s5p_mipi_dsi_enable_lane(dsim, DSIM_LANE_CLOCK, 1);
+ s5p_mipi_dsi_enable_lane(dsim, dsim->data_lane, 1);
+
+ /* set clock configuration */
+ s5p_mipi_dsi_set_clock(dsim, dsim->dsim_config->e_byte_clk, 1);
+
+ /* check clock and data lane state are stop state */
+ while (!(s5p_mipi_dsi_is_lane_state(dsim))) {
+ time_out--;
+ if (time_out = 0) {
+ dev_err(dsim->dev,
+ "DSI Master is not stop state.\n");
+ dev_err(dsim->dev,
+ "Check initialization process\n");
+
+ return -EINVAL;
+ }
+ }
+
+ if (time_out != 0) {
+ dev_info(dsim->dev,
+ "DSI Master driver has been completed.\n");
+ dev_info(dsim->dev, "DSI Master state is stop state\n");
+ }
+
+ dsim->state = DSIM_STATE_STOP;
+
+ /* BTA sequence counters */
+ s5p_mipi_dsi_set_stop_state_counter(dsim,
+ dsim->dsim_config->stop_holding_cnt);
+ s5p_mipi_dsi_set_bta_timeout(dsim,
+ dsim->dsim_config->bta_timeout);
+ s5p_mipi_dsi_set_lpdr_timeout(dsim,
+ dsim->dsim_config->rx_timeout);
+
+ return 0;
+ default:
+ dev_info(dsim->dev, "DSI Master is already init.\n");
+ return 0;
+ }
+
+ return 0;
+}
+
+int s5p_mipi_dsi_set_hs_enable(struct mipi_dsim_device *dsim)
+{
+ if (dsim->state = DSIM_STATE_STOP) {
+ if (dsim->e_clk_src != DSIM_EXT_CLK_BYPASS) {
+ dsim->state = DSIM_STATE_HSCLKEN;
+
+ /* set LCDC and CPU transfer mode to HS. */
+ s5p_mipi_dsi_set_lcdc_transfer_mode(dsim, 0);
+ s5p_mipi_dsi_set_cpu_transfer_mode(dsim, 0);
+
+ s5p_mipi_dsi_enable_hs_clock(dsim, 1);
+
+ return 0;
+ } else
+ dev_warn(dsim->dev,
+ "clock source is external bypass.\n");
+ } else
+ dev_warn(dsim->dev, "DSIM is not stop state.\n");
+
+ return 0;
+}
+
+int s5p_mipi_dsi_set_data_transfer_mode(struct mipi_dsim_device *dsim,
+ unsigned int mode)
+{
+ if (mode) {
+ if (dsim->state != DSIM_STATE_HSCLKEN) {
+ dev_err(dsim->dev, "HS Clock lane is not enabled.\n");
+ return -EINVAL;
+ }
+
+ s5p_mipi_dsi_set_lcdc_transfer_mode(dsim, 0);
+ } else {
+ if (dsim->state = DSIM_STATE_INIT || dsim->state =
+ DSIM_STATE_ULPS) {
+ dev_err(dsim->dev,
+ "DSI Master is not STOP or HSDT state.\n");
+ return -EINVAL;
+ }
+
+ s5p_mipi_dsi_set_cpu_transfer_mode(dsim, 0);
+ }
+
+ return 0;
+}
+
+int s5p_mipi_dsi_get_frame_done_status(struct mipi_dsim_device *dsim)
+{
+ return _s5p_mipi_dsi_get_frame_done_status(dsim);
+}
+
+int s5p_mipi_dsi_clear_frame_done(struct mipi_dsim_device *dsim)
+{
+ _s5p_mipi_dsi_clear_frame_done(dsim);
+
+ return 0;
+}
+
+MODULE_AUTHOR("InKi Dae <inki.dae@samsung.com>");
+MODULE_DESCRIPTION("Samusung MIPI-DSIM common driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/s5p_mipi_dsi_common.h b/drivers/video/s5p_mipi_dsi_common.h
new file mode 100644
index 0000000..5ade1d6
--- /dev/null
+++ b/drivers/video/s5p_mipi_dsi_common.h
@@ -0,0 +1,39 @@
+/* linux/drivers/video/s5p_mipi_dsi_common.h
+ *
+ * Header file for Samsung SoC MIPI-DSI common driver.
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * InKi Dae <inki.dae@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.
+*/
+
+#ifndef _S5P_MIPI_DSI_COMMON_H
+#define _S5P_MIPI_DSI_COMMON_H
+
+int s5p_mipi_dsi_wr_data(struct mipi_dsim_device *dsim, unsigned int data_id,
+ unsigned int data0, unsigned int data1);
+int s5p_mipi_dsi_pll_on(struct mipi_dsim_device *dsim, unsigned int enable);
+unsigned long s5p_mipi_dsi_change_pll(struct mipi_dsim_device *dsim,
+ unsigned int pre_divider, unsigned int main_divider,
+ unsigned int scaler);
+int s5p_mipi_dsi_set_clock(struct mipi_dsim_device *dsim,
+ unsigned int byte_clk_sel, unsigned int enable);
+int s5p_mipi_dsi_init_dsim(struct mipi_dsim_device *dsim);
+int s5p_mipi_dsi_set_display_mode(struct mipi_dsim_device *dsim,
+ struct mipi_dsim_config *dsim_info);
+int s5p_mipi_dsi_init_link(struct mipi_dsim_device *dsim);
+int s5p_mipi_dsi_set_hs_enable(struct mipi_dsim_device *dsim);
+int s5p_mipi_dsi_set_data_transfer_mode(struct mipi_dsim_device *dsim,
+ unsigned int mode);
+int s5p_mipi_dsi_enable_frame_done_int(struct mipi_dsim_device *dsim,
+ unsigned int enable);
+int s5p_mipi_dsi_get_frame_done_status(struct mipi_dsim_device *dsim);
+int s5p_mipi_dsi_clear_frame_done(struct mipi_dsim_device *dsim);
+
+extern struct fb_info *registered_fb[FB_MAX] __read_mostly;
+
+#endif /* _S5P_MIPI_DSI_COMMON_H */
diff --git a/drivers/video/s5p_mipi_dsi_lowlevel.c b/drivers/video/s5p_mipi_dsi_lowlevel.c
new file mode 100644
index 0000000..86d2881
--- /dev/null
+++ b/drivers/video/s5p_mipi_dsi_lowlevel.c
@@ -0,0 +1,558 @@
+/* linux/drivers/video/s5p_mipi_dsi_lowlevel.c
+ *
+ * Samsung SoC MIPI-DSI lowlevel driver.
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * InKi Dae, <inki.dae@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/delay.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/ctype.h>
+#include <linux/io.h>
+
+#include <mach/map.h>
+
+#include <plat/mipi_dsim.h>
+#include <plat/regs-dsim.h>
+
+void s5p_mipi_dsi_func_reset(struct mipi_dsim_device *dsim)
+{
+ unsigned int reg;
+
+ reg = readl(dsim->reg_base + S5P_DSIM_SWRST);
+
+ reg |= DSIM_FUNCRST;
+
+ writel(reg, dsim->reg_base + S5P_DSIM_SWRST);
+}
+
+void s5p_mipi_dsi_sw_reset(struct mipi_dsim_device *dsim)
+{
+ unsigned int reg;
+
+ reg = readl(dsim->reg_base + S5P_DSIM_SWRST);
+
+ reg |= DSIM_SWRST;
+
+ writel(reg, dsim->reg_base + S5P_DSIM_SWRST);
+}
+
+void s5p_mipi_dsi_set_interrupt_mask(struct mipi_dsim_device *dsim,
+ unsigned int mode, unsigned int mask)
+{
+ unsigned int reg = readl(dsim->reg_base + S5P_DSIM_INTMSK);
+
+ if (mask)
+ reg |= mode;
+ else
+ reg &= ~mode;
+
+ writel(reg, dsim->reg_base + S5P_DSIM_INTMSK);
+}
+
+void s5p_mipi_dsi_init_fifo_pointer(struct mipi_dsim_device *dsim,
+ unsigned int cfg)
+{
+ unsigned int reg;
+
+ reg = readl(dsim->reg_base + S5P_DSIM_FIFOCTRL);
+
+ writel(reg & ~(cfg), dsim->reg_base + S5P_DSIM_FIFOCTRL);
+ mdelay(10);
+ reg |= cfg;
+
+ writel(reg, dsim->reg_base + S5P_DSIM_FIFOCTRL);
+}
+
+/*
+ * this function set PLL P, M and S value in D-PHY
+ */
+void s5p_mipi_dsi_set_phy_tunning(struct mipi_dsim_device *dsim,
+ unsigned int value)
+{
+ writel(DSIM_AFC_CTL(value), dsim->reg_base + S5P_DSIM_PHYACCHR);
+}
+
+void s5p_mipi_dsi_set_main_disp_resol(struct mipi_dsim_device *dsim,
+ unsigned int width_resol, unsigned int height_resol)
+{
+ unsigned int reg;
+
+ /* standby should be set after configuration so set to not ready*/
+ reg = (readl(dsim->reg_base + S5P_DSIM_MDRESOL)) &
+ ~(DSIM_MAIN_STAND_BY);
+ writel(reg, dsim->reg_base + S5P_DSIM_MDRESOL);
+
+ reg &= ~(0x7ff << 16) & ~(0x7ff << 0);
+ reg |= DSIM_MAIN_VRESOL(height_resol) | DSIM_MAIN_HRESOL(width_resol);
+
+ reg |= DSIM_MAIN_STAND_BY;
+ writel(reg, dsim->reg_base + S5P_DSIM_MDRESOL);
+}
+
+void s5p_mipi_dsi_set_main_disp_vporch(struct mipi_dsim_device *dsim,
+ unsigned int cmd_allow, unsigned int vfront, unsigned int vback)
+{
+ unsigned int reg;
+
+ reg = (readl(dsim->reg_base + S5P_DSIM_MVPORCH)) &
+ ~(DSIM_CMD_ALLOW_MASK) & ~(DSIM_STABLE_VFP_MASK) &
+ ~(DSIM_MAIN_VBP_MASK);
+
+ reg |= ((cmd_allow & 0xf) << DSIM_CMD_ALLOW_SHIFT) |
+ ((vfront & 0x7ff) << DSIM_STABLE_VFP_SHIFT) |
+ ((vback & 0x7ff) << DSIM_MAIN_VBP_SHIFT);
+
+ writel(reg, dsim->reg_base + S5P_DSIM_MVPORCH);
+}
+
+void s5p_mipi_dsi_set_main_disp_hporch(struct mipi_dsim_device *dsim,
+ unsigned int front, unsigned int back)
+{
+ unsigned int reg;
+
+ reg = (readl(dsim->reg_base + S5P_DSIM_MHPORCH)) &
+ ~(DSIM_MAIN_HFP_MASK) & ~(DSIM_MAIN_HBP_MASK);
+
+ reg |= (front << DSIM_MAIN_HFP_SHIFT) | (back << DSIM_MAIN_HBP_SHIFT);
+
+ writel(reg, dsim->reg_base + S5P_DSIM_MHPORCH);
+}
+
+void s5p_mipi_dsi_set_main_disp_sync_area(struct mipi_dsim_device *dsim,
+ unsigned int vert, unsigned int hori)
+{
+ unsigned int reg;
+
+ reg = (readl(dsim->reg_base + S5P_DSIM_MSYNC)) &
+ ~(DSIM_MAIN_VSA_MASK) & ~(DSIM_MAIN_HSA_MASK);
+
+ reg |= ((vert & 0x3ff) << DSIM_MAIN_VSA_SHIFT) |
+ (hori << DSIM_MAIN_HSA_SHIFT);
+
+ writel(reg, dsim->reg_base + S5P_DSIM_MSYNC);
+}
+
+void s5p_mipi_dsi_set_sub_disp_resol(struct mipi_dsim_device *dsim,
+ unsigned int vert, unsigned int hori)
+{
+ unsigned int reg;
+
+ reg = (readl(dsim->reg_base + S5P_DSIM_SDRESOL)) &
+ ~(DSIM_SUB_STANDY_MASK);
+
+ writel(reg, dsim->reg_base + S5P_DSIM_SDRESOL);
+
+ reg &= ~(DSIM_SUB_VRESOL_MASK) | ~(DSIM_SUB_HRESOL_MASK);
+ reg |= ((vert & 0x7ff) << DSIM_SUB_VRESOL_SHIFT) |
+ ((hori & 0x7ff) << DSIM_SUB_HRESOL_SHIFT);
+ writel(reg, dsim->reg_base + S5P_DSIM_SDRESOL);
+
+ reg |= (1 << DSIM_SUB_STANDY_SHIFT);
+ writel(reg, dsim->reg_base + S5P_DSIM_SDRESOL);
+}
+
+void s5p_mipi_dsi_init_config(struct mipi_dsim_device *dsim)
+{
+ struct mipi_dsim_config *dsim_config = dsim->dsim_config;
+
+ unsigned int cfg = (readl(dsim->reg_base + S5P_DSIM_CONFIG)) &
+ ~(1 << 28) & ~(0x1f << 20) & ~(0x3 << 5);
+
+ cfg = (dsim_config->auto_flush << 29) |
+ (dsim_config->eot_disable << 28) |
+ (dsim_config->auto_vertical_cnt << DSIM_AUTO_MODE_SHIFT) |
+ (dsim_config->hse << DSIM_HSE_MODE_SHIFT) |
+ (dsim_config->hfp << DSIM_HFP_MODE_SHIFT) |
+ (dsim_config->hbp << DSIM_HBP_MODE_SHIFT) |
+ (dsim_config->hsa << DSIM_HSA_MODE_SHIFT) |
+ (dsim_config->e_no_data_lane << DSIM_NUM_OF_DATALANE_SHIFT);
+
+ writel(cfg, dsim->reg_base + S5P_DSIM_CONFIG);
+}
+
+void s5p_mipi_dsi_display_config(struct mipi_dsim_device *dsim,
+ struct mipi_dsim_config *dsim_config)
+{
+ u32 reg = (readl(dsim->reg_base + S5P_DSIM_CONFIG)) &
+ ~(0x3 << 26) & ~(1 << 25) & ~(0x3 << 18) & ~(0x7 << 12) &
+ ~(0x3 << 16) & ~(0x7 << 8);
+
+ if (dsim_config->e_interface = DSIM_VIDEO)
+ reg |= (1 << 25);
+ else if (dsim_config->e_interface = DSIM_COMMAND)
+ reg &= ~(1 << 25);
+ else {
+ dev_err(dsim->dev, "this ddi is not MIPI interface.\n");
+ return;
+ }
+
+ /* main lcd */
+ reg |= ((u8) (dsim_config->e_burst_mode) & 0x3) << 26 |
+ ((u8) (dsim_config->e_virtual_ch) & 0x3) << 18 |
+ ((u8) (dsim_config->e_pixel_format) & 0x7) << 12;
+
+ writel(reg, dsim->reg_base + S5P_DSIM_CONFIG);
+}
+
+void s5p_mipi_dsi_enable_lane(struct mipi_dsim_device *dsim, unsigned int lane,
+ unsigned int enable)
+{
+ unsigned int reg;
+
+ reg = readl(dsim->reg_base + S5P_DSIM_CONFIG);
+
+ if (enable)
+ reg |= DSIM_LANE_ENx(lane);
+ else
+ reg &= ~DSIM_LANE_ENx(lane);
+
+ writel(reg, dsim->reg_base + S5P_DSIM_CONFIG);
+}
+
+
+void s5p_mipi_dsi_set_data_lane_number(struct mipi_dsim_device *dsim,
+ unsigned int count)
+{
+ unsigned int cfg;
+
+ /* get the data lane number. */
+ cfg = DSIM_NUM_OF_DATA_LANE(count);
+
+ writel(cfg, dsim->reg_base + S5P_DSIM_CONFIG);
+}
+
+void s5p_mipi_dsi_enable_afc(struct mipi_dsim_device *dsim, unsigned int enable,
+ unsigned int afc_code)
+{
+ unsigned int reg = readl(dsim->reg_base + S5P_DSIM_PHYACCHR);
+
+ if (enable) {
+ reg |= (1 << 14);
+ reg &= ~(0x7 << 5);
+ reg |= (afc_code & 0x7) << 5;
+ } else
+ reg &= ~(1 << 14);
+
+ writel(reg, dsim->reg_base + S5P_DSIM_PHYACCHR);
+}
+
+void s5p_mipi_dsi_enable_pll_bypass(struct mipi_dsim_device *dsim,
+ unsigned int enable)
+{
+ unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_CLKCTRL)) &
+ ~(DSIM_PLL_BYPASS_EXTERNAL);
+
+ reg |= enable << DSIM_PLL_BYPASS_SHIFT;
+
+ writel(reg, dsim->reg_base + S5P_DSIM_CLKCTRL);
+}
+
+void s5p_mipi_dsi_set_pll_pms(struct mipi_dsim_device *dsim, unsigned int p,
+ unsigned int m, unsigned int s)
+{
+ unsigned int reg = readl(dsim->reg_base + S5P_DSIM_PLLCTRL);
+
+ reg |= ((p & 0x3f) << 13) | ((m & 0x1ff) << 4) | ((s & 0x7) << 1);
+
+ writel(reg, dsim->reg_base + S5P_DSIM_PLLCTRL);
+}
+
+void s5p_mipi_dsi_pll_freq_band(struct mipi_dsim_device *dsim,
+ unsigned int freq_band)
+{
+ unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_PLLCTRL)) &
+ ~(0x1f << DSIM_FREQ_BAND_SHIFT);
+
+ reg |= ((freq_band & 0x1f) << DSIM_FREQ_BAND_SHIFT);
+
+ writel(reg, dsim->reg_base + S5P_DSIM_PLLCTRL);
+}
+
+void s5p_mipi_dsi_pll_freq(struct mipi_dsim_device *dsim,
+ unsigned int pre_divider, unsigned int main_divider,
+ unsigned int scaler)
+{
+ unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_PLLCTRL)) &
+ ~(0x7ffff << 1);
+
+ reg |= (pre_divider & 0x3f) << 13 | (main_divider & 0x1ff) << 4 |
+ (scaler & 0x7) << 1;
+
+ writel(reg, dsim->reg_base + S5P_DSIM_PLLCTRL);
+}
+
+void s5p_mipi_dsi_pll_stable_time(struct mipi_dsim_device *dsim,
+ unsigned int lock_time)
+{
+ writel(lock_time, dsim->reg_base + S5P_DSIM_PLLTMR);
+}
+
+void s5p_mipi_dsi_enable_pll(struct mipi_dsim_device *dsim, unsigned int enable)
+{
+ unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_PLLCTRL)) &
+ ~(0x1 << DSIM_PLL_EN_SHIFT);
+
+ reg |= ((enable & 0x1) << DSIM_PLL_EN_SHIFT);
+
+ writel(reg, dsim->reg_base + S5P_DSIM_PLLCTRL);
+}
+
+void s5p_mipi_dsi_set_byte_clock_src(struct mipi_dsim_device *dsim,
+ unsigned int src)
+{
+ unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_CLKCTRL)) &
+ ~(0x3 << DSIM_BYTE_CLK_SRC_SHIFT);
+
+ reg |= ((unsigned int) src) << DSIM_BYTE_CLK_SRC_SHIFT;
+
+ writel(reg, dsim->reg_base + S5P_DSIM_CLKCTRL);
+}
+
+void s5p_mipi_dsi_enable_byte_clock(struct mipi_dsim_device *dsim,
+ unsigned int enable)
+{
+ unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_CLKCTRL)) &
+ ~(1 << DSIM_BYTE_CLKEN_SHIFT);
+
+ reg |= enable << DSIM_BYTE_CLKEN_SHIFT;
+
+ writel(reg, dsim->reg_base + S5P_DSIM_CLKCTRL);
+}
+
+void s5p_mipi_dsi_set_esc_clk_prs(struct mipi_dsim_device *dsim,
+ unsigned int enable, unsigned int prs_val)
+{
+ unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_CLKCTRL)) &
+ ~(1 << DSIM_ESC_CLKEN_SHIFT) & ~(0xffff);
+
+ reg |= enable << DSIM_ESC_CLKEN_SHIFT;
+ if (enable)
+ reg |= prs_val;
+
+ writel(reg, dsim->reg_base + S5P_DSIM_CLKCTRL);
+}
+
+void s5p_mipi_dsi_enable_esc_clk_on_lane(struct mipi_dsim_device *dsim,
+ unsigned int lane_sel, unsigned int enable)
+{
+ unsigned int reg = readl(dsim->reg_base + S5P_DSIM_CLKCTRL);
+
+ if (enable)
+ reg |= DSIM_LANE_ESC_CLKEN(lane_sel);
+ else
+
+ reg &= ~DSIM_LANE_ESC_CLKEN(lane_sel);
+
+ writel(reg, dsim->reg_base + S5P_DSIM_CLKCTRL);
+}
+
+void s5p_mipi_dsi_force_dphy_stop_state(struct mipi_dsim_device *dsim,
+ unsigned int enable)
+{
+ unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_ESCMODE)) &
+ ~(0x1 << DSIM_FORCE_STOP_STATE_SHIFT);
+
+ reg |= ((enable & 0x1) << DSIM_FORCE_STOP_STATE_SHIFT);
+
+ writel(reg, dsim->reg_base + S5P_DSIM_ESCMODE);
+}
+
+unsigned int s5p_mipi_dsi_is_lane_state(struct mipi_dsim_device *dsim)
+{
+ unsigned int reg = readl(dsim->reg_base + S5P_DSIM_STATUS);
+
+ /**
+ * check clock and data lane states.
+ * if MIPI-DSI controller was enabled at bootloader then
+ * TX_READY_HS_CLK is enabled otherwise STOP_STATE_CLK.
+ * so it should be checked for two case.
+ */
+ if ((reg & DSIM_STOP_STATE_DAT(0xf)) &&
+ ((reg & DSIM_STOP_STATE_CLK) ||
+ (reg & DSIM_TX_READY_HS_CLK)))
+ return 1;
+ else
+ return 0;
+
+ return 0;
+}
+
+void s5p_mipi_dsi_set_stop_state_counter(struct mipi_dsim_device *dsim,
+ unsigned int cnt_val)
+{
+ unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_ESCMODE)) &
+ ~(0x7ff << DSIM_STOP_STATE_CNT_SHIFT);
+
+ reg |= ((cnt_val & 0x7ff) << DSIM_STOP_STATE_CNT_SHIFT);
+
+ writel(reg, dsim->reg_base + S5P_DSIM_ESCMODE);
+}
+
+void s5p_mipi_dsi_set_bta_timeout(struct mipi_dsim_device *dsim,
+ unsigned int timeout)
+{
+ unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_TIMEOUT)) &
+ ~(0xff << DSIM_BTA_TOUT_SHIFT);
+
+ reg |= (timeout << DSIM_BTA_TOUT_SHIFT);
+
+ writel(reg, dsim->reg_base + S5P_DSIM_TIMEOUT);
+}
+
+void s5p_mipi_dsi_set_lpdr_timeout(struct mipi_dsim_device *dsim,
+ unsigned int timeout)
+{
+ unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_TIMEOUT)) &
+ ~(0xffff << DSIM_LPDR_TOUT_SHIFT);
+
+ reg |= (timeout << DSIM_LPDR_TOUT_SHIFT);
+
+ writel(reg, dsim->reg_base + S5P_DSIM_TIMEOUT);
+}
+
+void s5p_mipi_dsi_set_cpu_transfer_mode(struct mipi_dsim_device *dsim,
+ unsigned int lp)
+{
+ unsigned int reg = readl(dsim->reg_base + S5P_DSIM_ESCMODE);
+
+ reg &= ~DSIM_CMD_LPDT_LP;
+
+ if (lp)
+ reg |= DSIM_CMD_LPDT_LP;
+
+ writel(reg, dsim->reg_base + S5P_DSIM_ESCMODE);
+}
+
+void s5p_mipi_dsi_set_lcdc_transfer_mode(struct mipi_dsim_device *dsim,
+ unsigned int lp)
+{
+ unsigned int reg = readl(dsim->reg_base + S5P_DSIM_ESCMODE);
+
+ reg &= ~DSIM_TX_LPDT_LP;
+
+ if (lp)
+ reg |= DSIM_TX_LPDT_LP;
+
+ writel(reg, dsim->reg_base + S5P_DSIM_ESCMODE);
+}
+
+void s5p_mipi_dsi_enable_hs_clock(struct mipi_dsim_device *dsim,
+ unsigned int enable)
+{
+ unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_CLKCTRL)) &
+ ~(1 << DSIM_TX_REQUEST_HSCLK_SHIFT);
+
+ reg |= enable << DSIM_TX_REQUEST_HSCLK_SHIFT;
+
+ writel(reg, dsim->reg_base + S5P_DSIM_CLKCTRL);
+}
+
+void s5p_mipi_dsi_dp_dn_swap(struct mipi_dsim_device *dsim,
+ unsigned int swap_en)
+{
+ unsigned int reg = readl(dsim->reg_base + S5P_DSIM_PHYACCHR1);
+
+ reg &= ~(0x3 << 0);
+ reg |= (swap_en & 0x3) << 0;
+
+ writel(reg, dsim->reg_base + S5P_DSIM_PHYACCHR1);
+}
+
+void s5p_mipi_dsi_hs_zero_ctrl(struct mipi_dsim_device *dsim,
+ unsigned int hs_zero)
+{
+ unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_PLLCTRL)) &
+ ~(0xf << 28);
+
+ reg |= ((hs_zero & 0xf) << 28);
+
+ writel(reg, dsim->reg_base + S5P_DSIM_PLLCTRL);
+}
+
+void s5p_mipi_dsi_prep_ctrl(struct mipi_dsim_device *dsim, unsigned int prep)
+{
+ unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_PLLCTRL)) &
+ ~(0x7 << 20);
+
+ reg |= ((prep & 0x7) << 20);
+
+ writel(reg, dsim->reg_base + S5P_DSIM_PLLCTRL);
+}
+
+void s5p_mipi_dsi_clear_interrupt(struct mipi_dsim_device *dsim)
+{
+ unsigned int reg = readl(dsim->reg_base + S5P_DSIM_INTSRC);
+
+ reg |= INTSRC_PLL_STABLE;
+
+ writel(reg, dsim->reg_base + S5P_DSIM_INTSRC);
+}
+
+void s5p_mipi_dsi_clear_all_interrupt(struct mipi_dsim_device *dsim)
+{
+ unsigned int reg = readl(dsim->reg_base + S5P_DSIM_INTSRC);
+
+ reg |= 0xffffffff;
+
+ writel(reg, dsim->reg_base + S5P_DSIM_INTSRC);
+}
+
+unsigned int s5p_mipi_dsi_is_pll_stable(struct mipi_dsim_device *dsim)
+{
+ unsigned int reg;
+
+ reg = readl(dsim->reg_base + S5P_DSIM_STATUS);
+
+ return reg & (1 << 31) ? 1 : 0;
+}
+
+unsigned int s5p_mipi_dsi_get_fifo_state(struct mipi_dsim_device *dsim)
+{
+ unsigned int ret;
+
+ ret = readl(dsim->reg_base + S5P_DSIM_FIFOCTRL) & ~(0x1f);
+
+ return ret;
+}
+
+void s5p_mipi_dsi_wr_tx_header(struct mipi_dsim_device *dsim,
+ unsigned int di, unsigned int data0, unsigned int data1)
+{
+ unsigned int reg = (data1 << 16) | (data0 << 8) | ((di & 0x3f) << 0);
+
+ writel(reg, dsim->reg_base + S5P_DSIM_PKTHDR);
+}
+
+unsigned int _s5p_mipi_dsi_get_frame_done_status(struct mipi_dsim_device *dsim)
+{
+ unsigned int reg = readl(dsim->reg_base + S5P_DSIM_INTSRC);
+
+ return (reg & INTSRC_FRAME_DONE) ? 1 : 0;
+}
+
+void _s5p_mipi_dsi_clear_frame_done(struct mipi_dsim_device *dsim)
+{
+ unsigned int reg = readl(dsim->reg_base + S5P_DSIM_INTSRC);
+
+ writel(reg | INTSRC_FRAME_DONE, dsim->reg_base +
+ S5P_DSIM_INTSRC);
+}
+
+void s5p_mipi_dsi_wr_tx_data(struct mipi_dsim_device *dsim,
+ unsigned int tx_data)
+{
+ writel(tx_data, dsim->reg_base + S5P_DSIM_PAYLOAD);
+}
diff --git a/drivers/video/s5p_mipi_dsi_lowlevel.h b/drivers/video/s5p_mipi_dsi_lowlevel.h
new file mode 100644
index 0000000..ca9dc56
--- /dev/null
+++ b/drivers/video/s5p_mipi_dsi_lowlevel.h
@@ -0,0 +1,100 @@
+/* linux/drivers/video/s5p_mipi_dsi_lowlevel.h
+ *
+ * Header file for Samsung SoC MIPI-DSI lowlevel driver.
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * InKi Dae <inki.dae@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.
+*/
+
+#ifndef _S5P_MIPI_DSI_LOWLEVEL_H
+#define _S5P_MIPI_DSI_LOWLEVEL_H
+
+void s5p_mipi_dsi_func_reset(struct mipi_dsim_device *dsim);
+void s5p_mipi_dsi_sw_reset(struct mipi_dsim_device *dsim);
+void s5p_mipi_dsi_set_interrupt_mask(struct mipi_dsim_device *dsim,
+ unsigned int mode, unsigned int mask);
+void s5p_mipi_dsi_set_data_lane_number(struct mipi_dsim_device *dsim,
+ unsigned int count);
+void s5p_mipi_dsi_init_fifo_pointer(struct mipi_dsim_device *dsim,
+ unsigned int cfg);
+void s5p_mipi_dsi_set_phy_tunning(struct mipi_dsim_device *dsim,
+ unsigned int value);
+void s5p_mipi_dsi_set_phy_tunning(struct mipi_dsim_device *dsim,
+ unsigned int value);
+void s5p_mipi_dsi_set_main_disp_resol(struct mipi_dsim_device *dsim,
+ unsigned int width_resol, unsigned int height_resol);
+void s5p_mipi_dsi_set_main_disp_vporch(struct mipi_dsim_device *dsim,
+ unsigned int cmd_allow, unsigned int vfront, unsigned int vback);
+void s5p_mipi_dsi_set_main_disp_hporch(struct mipi_dsim_device *dsim,
+ unsigned int front, unsigned int back);
+void s5p_mipi_dsi_set_main_disp_sync_area(struct mipi_dsim_device *dsim,
+ unsigned int vert, unsigned int hori);
+void s5p_mipi_dsi_set_sub_disp_resol(struct mipi_dsim_device *dsim,
+ unsigned int vert, unsigned int hori);
+void s5p_mipi_dsi_init_config(struct mipi_dsim_device *dsim);
+void s5p_mipi_dsi_display_config(struct mipi_dsim_device *dsim,
+ struct mipi_dsim_config *dsim_config);
+void s5p_mipi_dsi_set_data_lane_number(struct mipi_dsim_device *dsim,
+ unsigned int count);
+void s5p_mipi_dsi_enable_lane(struct mipi_dsim_device *dsim, unsigned int lane,
+ unsigned int enable);
+void s5p_mipi_dsi_enable_afc(struct mipi_dsim_device *dsim, unsigned int enable,
+ unsigned int afc_code);
+void s5p_mipi_dsi_enable_pll_bypass(struct mipi_dsim_device *dsim,
+ unsigned int enable);
+void s5p_mipi_dsi_set_pll_pms(struct mipi_dsim_device *dsim, unsigned int p,
+ unsigned int m, unsigned int s);
+void s5p_mipi_dsi_pll_freq_band(struct mipi_dsim_device *dsim,
+ unsigned int freq_band);
+void s5p_mipi_dsi_pll_freq(struct mipi_dsim_device *dsim,
+ unsigned int pre_divider, unsigned int main_divider,
+ unsigned int scaler);
+void s5p_mipi_dsi_pll_stable_time(struct mipi_dsim_device *dsim,
+ unsigned int lock_time);
+void s5p_mipi_dsi_enable_pll(struct mipi_dsim_device *dsim,
+ unsigned int enable);
+void s5p_mipi_dsi_set_byte_clock_src(struct mipi_dsim_device *dsim,
+ unsigned int src);
+void s5p_mipi_dsi_enable_byte_clock(struct mipi_dsim_device *dsim,
+ unsigned int enable);
+void s5p_mipi_dsi_set_esc_clk_prs(struct mipi_dsim_device *dsim,
+ unsigned int enable, unsigned int prs_val);
+void s5p_mipi_dsi_enable_esc_clk_on_lane(struct mipi_dsim_device *dsim,
+ unsigned int lane_sel, unsigned int enable);
+void s5p_mipi_dsi_force_dphy_stop_state(struct mipi_dsim_device *dsim,
+ unsigned int enable);
+unsigned int s5p_mipi_dsi_is_lane_state(struct mipi_dsim_device *dsim);
+void s5p_mipi_dsi_set_stop_state_counter(struct mipi_dsim_device *dsim,
+ unsigned int cnt_val);
+void s5p_mipi_dsi_set_bta_timeout(struct mipi_dsim_device *dsim,
+ unsigned int timeout);
+void s5p_mipi_dsi_set_lpdr_timeout(struct mipi_dsim_device *dsim,
+ unsigned int timeout);
+void s5p_mipi_dsi_set_lcdc_transfer_mode(struct mipi_dsim_device *dsim,
+ unsigned int lp);
+void s5p_mipi_dsi_set_cpu_transfer_mode(struct mipi_dsim_device *dsim,
+ unsigned int lp);
+void s5p_mipi_dsi_enable_hs_clock(struct mipi_dsim_device *dsim,
+ unsigned int enable);
+void s5p_mipi_dsi_dp_dn_swap(struct mipi_dsim_device *dsim,
+ unsigned int swap_en);
+void s5p_mipi_dsi_hs_zero_ctrl(struct mipi_dsim_device *dsim,
+ unsigned int hs_zero);
+void s5p_mipi_dsi_prep_ctrl(struct mipi_dsim_device *dsim, unsigned int prep);
+void s5p_mipi_dsi_clear_interrupt(struct mipi_dsim_device *dsim);
+void s5p_mipi_dsi_clear_all_interrupt(struct mipi_dsim_device *dsim);
+unsigned int s5p_mipi_dsi_is_pll_stable(struct mipi_dsim_device *dsim);
+unsigned int s5p_mipi_dsi_get_fifo_state(struct mipi_dsim_device *dsim);
+unsigned int _s5p_mipi_dsi_get_frame_done_status(struct mipi_dsim_device *dsim);
+void _s5p_mipi_dsi_clear_frame_done(struct mipi_dsim_device *dsim);
+void s5p_mipi_dsi_wr_tx_header(struct mipi_dsim_device *dsim, unsigned int di,
+ unsigned int data0, unsigned int data1);
+void s5p_mipi_dsi_wr_tx_data(struct mipi_dsim_device *dsim,
+ unsigned int tx_data);
+
+#endif /* _S5P_MIPI_DSI_LOWLEVEL_H */
--
1.7.0.4
^ permalink raw reply related
* [PATCH 0/2] video: add Samsung SoC based MIPI-DSI support.
From: daeinki @ 2011-04-14 12:15 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <4CE5D2BB.2060308@samsung.com>
Hello, all.
Samsung S5PV210 and EXYNOS4 SoC platform have one or two MIPI-DSI
controller and MIPI-DSI based LCD Panel could be used with this one.
this patch adds Samsung SoC based MIPI-DSI support.
to use MIPI-DSI based LCD Panel driver, mipi_dsim_lcd_device shoule be
registered to MIPI-DSI driver through s5p_mipi_dsi_register_lcd_device()
at machine code or machine specific somewhere first, and
mipi_dsim_lcd_driver should be registered when
s5p_mipi_dsi_register_driver() is called at init function of lcd driver,
and then probe() of that driver would be called by MIPI-DSI controller
driver if lcd panel name and id of mipi_dsim_lcd_device are same as ones
of mipi_dsim_lcd_driver.
for this, you can refer to sample lcd panel driver.
please see "Documentation/s5p_mipi_dsim/dsim_sample_lcd.c"
this patch series includes the following.
[PATCH 1/2] video: add Samsung SoC MIPI-DSI controller driver.
[PATCH 2/2] video: add Samsung SoC MIPI-DSI based sample lcd panel driver.
^ permalink raw reply
* [PATCH] video, udlfb: Fix two build warning about 'ignoring return value'
From: Liu Yuan @ 2011-04-14 8:17 UTC (permalink / raw)
To: Paul Mundt; +Cc: open list:FRAMEBUFFER LAYER, open list
From: Liu Yuan <tailai.ly@taobao.com>
Build warning:
...
drivers/video/udlfb.c:1590: warning: ignoring return value of ‘device_create_file’, declared with attribute warn_unused_result
drivers/video/udlfb.c:1592: warning: ignoring return value of ‘device_create_bin_file’, declared with attribute warn_unused_result
So add two checks to get rid of 'em.
Signed-off-by: Liu Yuan <tailai.ly@taobao.com>
---
drivers/video/udlfb.c | 15 ++++++++++++---
1 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/drivers/video/udlfb.c b/drivers/video/udlfb.c
index 68041d9..55d6de6 100644
--- a/drivers/video/udlfb.c
+++ b/drivers/video/udlfb.c
@@ -1586,10 +1586,19 @@ static int dlfb_usb_probe(struct usb_interface *interface,
goto error;
}
- for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++)
- device_create_file(info->dev, &fb_device_attrs[i]);
+ for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++) {
+ retval = device_create_file(info->dev, &fb_device_attrs[i]);
+ if (retval) {
+ pr_err("device_create_file failed %d\n", retval);
+ goto error;
+ }
+ }
- device_create_bin_file(info->dev, &edid_attr);
+ retval = device_create_bin_file(info->dev, &edid_attr);
+ if (retval) {
+ pr_err("device_create_bin_file failed %d\n", retval);
+ goto error;
+ }
pr_info("DisplayLink USB device /dev/fb%d attached. %dx%d resolution."
" Using %dK framebuffer memory\n", info->node,
--
1.7.1
^ permalink raw reply related
* Re: viafb: XO-1.5 video broken on 2.6.39
From: Florian Tobias Schandinat @ 2011-04-13 23:05 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <BANLkTimFS0yC2629V0tBQQZG+9hJTkSctw@mail.gmail.com>
Hi Daniel,
Daniel Drake schrieb:
> Hi,
>
> Commit fd3cc69848b7e1873e5f12bbcdd572b20277ecf3 breaks video on the
> XO-1.5 laptop on 2.6.39:
Sorry about that.
> commit fd3cc69848b7e1873e5f12bbcdd572b20277ecf3
> Author: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
> Date: Fri Mar 11 00:04:01 2011 +0000
>
> viafb: remove duplicated clock storage
>
> This is using the 1200x900 mode (DCON1200x900)
>
> In the old code, the clock was hardcoded as value 57275000.
> In the new code, the clock gets calculated as 1264x912x60 = 69166080
Having a closer look at it the entire mode looks suspicious as it is neither CVT
nor GTF compatible. But as it worked I assume the timings are correct and only
the refresh rate is incorrect. If we reduce the refresh rate to 50Hz we get
1264x912x50 = 57638400 which is pretty close to the old value (and the
documentation about DCON I found also suggests that it works at 50Hz). I will
prepare a patch as soon as I have time (the driver tends to assume that 60Gz
mode is always present and working).
> The result is that the screen gets filled with black and grey
> horizontal lines instead of anything readable.
>
> Any ideas?
>
> Thanks,
> Daniel
>
Thanks a lot for your bug report,
Florian Tobias Schandinat
^ permalink raw reply
* viafb: XO-1.5 video broken on 2.6.39
From: Daniel Drake @ 2011-04-13 20:59 UTC (permalink / raw)
To: linux-fbdev
Hi,
Commit fd3cc69848b7e1873e5f12bbcdd572b20277ecf3 breaks video on the
XO-1.5 laptop on 2.6.39:
commit fd3cc69848b7e1873e5f12bbcdd572b20277ecf3
Author: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
Date: Fri Mar 11 00:04:01 2011 +0000
viafb: remove duplicated clock storage
This is using the 1200x900 mode (DCON1200x900)
In the old code, the clock was hardcoded as value 57275000.
In the new code, the clock gets calculated as 1264x912x60 = 69166080
The result is that the screen gets filled with black and grey
horizontal lines instead of anything readable.
Any ideas?
Thanks,
Daniel
^ permalink raw reply
* Re: [PATCH] drivers, video: Add a check for strict_strtoul()
From: Andrew Morton @ 2011-04-12 22:00 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1302167178-9216-1-git-send-email-namei.unix@gmail.com>
On Thu, 7 Apr 2011 17:06:18 +0800
Liu Yuan <namei.unix@gmail.com> wrote:
> From: Liu Yuan <tailai.ly@taobao.com>
>
> It should check if strict_strtoul() succeeds.This
> patch fixes it.
>
> Signed-off-by: Liu Yuan <tailai.ly@taobao.com>
> ---
> drivers/video/backlight/adp5520_bl.c | 4 +++-
> 1 files changed, 3 insertions(+), 1 deletions(-)
>
> diff --git a/drivers/video/backlight/adp5520_bl.c b/drivers/video/backlight/adp5520_bl.c
> index af31197..fdef632 100644
> --- a/drivers/video/backlight/adp5520_bl.c
> +++ b/drivers/video/backlight/adp5520_bl.c
> @@ -212,7 +212,9 @@ static ssize_t adp5520_bl_daylight_max_store(struct device *dev,
> {
> struct adp5520_bl *data = dev_get_drvdata(dev);
>
> - strict_strtoul(buf, 10, &data->cached_daylight_max);
> + if (strict_strtoul(buf, 10, &data->cached_daylight_max) < 0)
> + return -EINVAL;
> +
> return adp5520_store(dev, buf, count, ADP5520_DAYLIGHT_MAX);
> }
It is better to propagate strict_strtoul()'s errno, rather than
overriding it:
--- a/drivers/video/backlight/adp5520_bl.c~drivers-video-backlight-adp5520_blc-check-strict_strtoul-return-value-fix
+++ a/drivers/video/backlight/adp5520_bl.c
@@ -211,9 +211,11 @@ static ssize_t adp5520_bl_daylight_max_s
const char *buf, size_t count)
{
struct adp5520_bl *data = dev_get_drvdata(dev);
+ int ret;
- if (strict_strtoul(buf, 10, &data->cached_daylight_max) < 0)
- return -EINVAL;
+ ret = strict_strtoul(buf, 10, &data->cached_daylight_max);
+ if (ret < 0)
+ return ret;
return adp5520_store(dev, buf, count, ADP5520_DAYLIGHT_MAX);
}
_
^ permalink raw reply
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