* Re: [PATCH] MXSFB: Fix driver registration
From: Shawn Guo @ 2011-12-19 13:51 UTC (permalink / raw)
To: Marek Vasut, Florian Tobias Schandinat
Cc: linux-kernel, Wolfgang Denk, Stefano Babic, Huang Shijie,
Axel Lin, Sascha Hauer, linux-fbdev
In-Reply-To: <1324169888-6687-1-git-send-email-marek.vasut@gmail.com>
Cc-ed Florian and linux-fbdev@vger.kernel.org, as I guess Florian is
the person who will take this patch.
-- Regards,Shawn
On 18 December 2011 08:58, Marek Vasut <marek.vasut@gmail.com> wrote:
> The driver should be registered with mxsfb_driver, not with mxsfb_devtype.
> This caused obvious null pointer dereference and crash.
>
> Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
> Cc: Wolfgang Denk <wd@denx.de>
> Cc: Stefano Babic <sbabic@denx.de>
> Cc: Shawn Guo <shawn.guo@linaro.org>
> Cc: Huang Shijie <b32955@freescale.com>
> Cc: Axel Lin <axel.lin@gmail.com>
> Cc: Sascha Hauer <s.hauer@pengutronix.de>
> ---
> drivers/video/mxsfb.c | 2 +-
> 1 files changed, 1 insertions(+), 1 deletions(-)
>
> diff --git a/drivers/video/mxsfb.c b/drivers/video/mxsfb.c
> index 18742c2..d29c7c0 100644
> --- a/drivers/video/mxsfb.c
> +++ b/drivers/video/mxsfb.c
> @@ -902,7 +902,7 @@ static struct platform_driver mxsfb_driver = {
> },
> };
>
> -module_platform_driver(mxsfb_devtype);
> +module_platform_driver(mxsfb_driver);
>
> MODULE_DESCRIPTION("Freescale mxs framebuffer driver");
> MODULE_AUTHOR("Sascha Hauer, Pengutronix");
> --
> 1.7.6.4
>
^ permalink raw reply
* Re: [PATCH] MXSFB: Fix driver registration
From: Florian Tobias Schandinat @ 2011-12-19 15:18 UTC (permalink / raw)
To: Shawn Guo
Cc: Marek Vasut, linux-kernel, Wolfgang Denk, Stefano Babic,
Huang Shijie, Axel Lin, Sascha Hauer, linux-fbdev
In-Reply-To: <CAAQ0ZWSJ0Yzr2Gk9MBQ0nvVCWxr0yWF_RFTy3isqc0pgEDdRxw@mail.gmail.com>
Hi Marek,
can you please resend the patch to me and the fbdev mailing list, preferably
with all Ack's you received until now included.
On 12/19/2011 01:51 PM, Shawn Guo wrote:
> Cc-ed Florian and linux-fbdev@vger.kernel.org, as I guess Florian is
> the person who will take this patch.
Thanks, I will. I guess you wanted to Ack this patch?
Thanks,
Florian Tobias Schandinat
>
> -- Regards,Shawn
> On 18 December 2011 08:58, Marek Vasut <marek.vasut@gmail.com> wrote:
>> The driver should be registered with mxsfb_driver, not with mxsfb_devtype.
>> This caused obvious null pointer dereference and crash.
>>
>> Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
>> Cc: Wolfgang Denk <wd@denx.de>
>> Cc: Stefano Babic <sbabic@denx.de>
>> Cc: Shawn Guo <shawn.guo@linaro.org>
>> Cc: Huang Shijie <b32955@freescale.com>
>> Cc: Axel Lin <axel.lin@gmail.com>
>> Cc: Sascha Hauer <s.hauer@pengutronix.de>
>> ---
>> drivers/video/mxsfb.c | 2 +-
>> 1 files changed, 1 insertions(+), 1 deletions(-)
>>
>> diff --git a/drivers/video/mxsfb.c b/drivers/video/mxsfb.c
>> index 18742c2..d29c7c0 100644
>> --- a/drivers/video/mxsfb.c
>> +++ b/drivers/video/mxsfb.c
>> @@ -902,7 +902,7 @@ static struct platform_driver mxsfb_driver = {
>> },
>> };
>>
>> -module_platform_driver(mxsfb_devtype);
>> +module_platform_driver(mxsfb_driver);
>>
>> MODULE_DESCRIPTION("Freescale mxs framebuffer driver");
>> MODULE_AUTHOR("Sascha Hauer, Pengutronix");
>> --
>> 1.7.6.4
>>
>
^ permalink raw reply
* [PATCH RESEND] MXSFB: Fix driver registration
From: Marek Vasut @ 2011-12-19 15:37 UTC (permalink / raw)
To: linux-kernel
Cc: linux-fbdev, FlorianSchandinat, Marek Vasut, Wolfgang Denk,
Stefano Babic, Shawn Guo, Huang Shijie, Axel Lin, Sascha Hauer
The driver should be registered with mxsfb_driver, not with mxsfb_devtype.
This caused obvious null pointer dereference and crash.
Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
Cc: Wolfgang Denk <wd@denx.de>
Cc: Stefano Babic <sbabic@denx.de>
Cc: Shawn Guo <shawn.guo@linaro.org>
Cc: Huang Shijie <b32955@freescale.com>
Cc: Axel Lin <axel.lin@gmail.com>
Cc: Sascha Hauer <s.hauer@pengutronix.de>
Acked-by: Axel Lin <axel.lin@gmail.com>
Acked-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/video/mxsfb.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/drivers/video/mxsfb.c b/drivers/video/mxsfb.c
index 18742c2..d29c7c0 100644
--- a/drivers/video/mxsfb.c
+++ b/drivers/video/mxsfb.c
@@ -902,7 +902,7 @@ static struct platform_driver mxsfb_driver = {
},
};
-module_platform_driver(mxsfb_devtype);
+module_platform_driver(mxsfb_driver);
MODULE_DESCRIPTION("Freescale mxs framebuffer driver");
MODULE_AUTHOR("Sascha Hauer, Pengutronix");
--
1.7.6.4
^ permalink raw reply related
* Re: Should I use FBINFO_VIRTFB?
From: Timur Tabi @ 2011-12-19 16:08 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <4EEA5DA7.3010406@freescale.com>
Geert Uytterhoeven wrote:
>> > I'm a little confused about panning support in my driver (which I didn't write -- I'm just cleaning it up). There is .fb_pan_display function, but it only gets called early in the boot process, and only with xoffset=0 and yoffset=0. After that, it never seems to get called again. Under what circumstances is panning really used?
> Is yres_virtual larger than yres? Is the font size a multiple of ypanstep?
> If not, panning is disabled.
I can't seem to get partial panning to "activate", no matter what I do. I set 'flags' to FBINFO_DEFAULT | FBINFO_VIRTFB | FBINFO_PARTIAL_PAN_OK | FBINFO_READS_FAST. I have a 1280x1024 monitor. I set the virtual_size to 1280,1280 via sysfs. Then I set panning to "0,100", and I see the screen scroll. I tried sending a bunch of output to /dev/tty1, but no matter what I do, none of the SCROLL_PAN_REDRAW or SCROLL_PAN_MOVE case statements in fbcon_scroll() get executed.
At this point, should I just FBINFO_VIRTFB | FBINFO_PARTIAL_PAN_OK | FBINFO_READS_FAST and not worry about whether it really makes a difference?
--
Timur Tabi
Linux kernel developer at Freescale
^ permalink raw reply
* Re: [GIT PULL] ARM: amba: Enable module alias autogeneration for
From: Russell King - ARM Linux @ 2011-12-19 21:39 UTC (permalink / raw)
To: Dave Martin
Cc: Alessandro Rubini, patches, linux-kernel, linux-arm-kernel, alan,
a.zummo, alsa-devel, cjb, dan.j.williams, dmitry.torokhov,
grant.likely, perex, jassisinghbrar, julia, linus.walleij,
linux-fbdev, linux-input, linux-mmc, linux-serial, linux-watchdog,
lethal, Pawel.Moll, rtc-linux, spi-devel-general, tiwai,
vinod.koul, wim
In-Reply-To: <20111219132409.GB2031@linaro.org>
On Mon, Dec 19, 2011 at 01:24:09PM +0000, Dave Martin wrote:
> Hi Russell,
>
> This one isn't urgent, but I'm not seeing the amba modalias patches
> anywhere yet. Did you have any outstanding concerns which need to be
> resolved?
>
> If you can suggest when/if these are likely to merge that would be great.
>
> Since Alessandro is now expecting to have to rebase on top of the amba
> additions anyway, we shouldn't need to worry about conflicting with his
> patches.
>
> Of course, if you've already merged these somewhere, then there's no
> problem.
I have pulled it, I just haven't merged it in anywhere yet.
^ permalink raw reply
* [PATCH 1/5] drivers/video: fsl-diu-fb: merge init_fbinfo() into install_fb()
From: Timur Tabi @ 2011-12-19 22:26 UTC (permalink / raw)
To: linux-fbdev
Function init_fbinfo() is called only from install_fb(), and it's only a few
lines long. Plus, it ignores the return code from fb_alloc_cmap(). Merge
its contents into install_fb() and handle errors properly.
Signed-off-by: Timur Tabi <timur@freescale.com>
---
drivers/video/fsl-diu-fb.c | 25 ++++++++-----------------
1 files changed, 8 insertions(+), 17 deletions(-)
diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
index 408272c..411a7b3 100644
--- a/drivers/video/fsl-diu-fb.c
+++ b/drivers/video/fsl-diu-fb.c
@@ -1220,21 +1220,6 @@ static struct fb_ops fsl_diu_ops = {
.fb_release = fsl_diu_release,
};
-static int init_fbinfo(struct fb_info *info)
-{
- struct mfb_info *mfbi = info->par;
-
- info->device = NULL;
- info->var.activate = FB_ACTIVATE_NOW;
- info->fbops = &fsl_diu_ops;
- info->flags = FBINFO_FLAG_DEFAULT;
- info->pseudo_palette = &mfbi->pseudo_palette;
-
- /* Allocate colormap */
- fb_alloc_cmap(&info->cmap, 16, 0);
- return 0;
-}
-
static int __devinit install_fb(struct fb_info *info)
{
int rc;
@@ -1244,8 +1229,14 @@ static int __devinit install_fb(struct fb_info *info)
unsigned int dbsize = ARRAY_SIZE(fsl_diu_mode_db);
int has_default_mode = 1;
- if (init_fbinfo(info))
- return -EINVAL;
+ info->var.activate = FB_ACTIVATE_NOW;
+ info->fbops = &fsl_diu_ops;
+ info->flags = FBINFO_DEFAULT;
+ info->pseudo_palette = mfbi->pseudo_palette;
+
+ rc = fb_alloc_cmap(&info->cmap, 16, 0);
+ if (rc)
+ return rc;
if (mfbi->index = PLANE0) {
if (mfbi->edid_data) {
--
1.7.3.4
^ permalink raw reply related
* [PATCH 2/5] drivers/video: fsl-diu-fb: set correct framebuffer flags
From: Timur Tabi @ 2011-12-19 22:26 UTC (permalink / raw)
To: linux-fbdev
The DIU uses system RAM for the framebuffer, so FBINFO_VIRTFB should be set.
Since the framebuffer is in system RAM, it can be read from more quickly
than written to, so FBINFO_READS_FAST should be set.
We can also set FBINFO_PARTIAL_PAN_OK for the same reasons.
Signed-off-by: Timur Tabi <timur@freescale.com>
---
drivers/video/fsl-diu-fb.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
index 411a7b3..231752e 100644
--- a/drivers/video/fsl-diu-fb.c
+++ b/drivers/video/fsl-diu-fb.c
@@ -1231,7 +1231,8 @@ static int __devinit install_fb(struct fb_info *info)
info->var.activate = FB_ACTIVATE_NOW;
info->fbops = &fsl_diu_ops;
- info->flags = FBINFO_DEFAULT;
+ info->flags = FBINFO_DEFAULT | FBINFO_VIRTFB | FBINFO_PARTIAL_PAN_OK |
+ FBINFO_READS_FAST;
info->pseudo_palette = mfbi->pseudo_palette;
rc = fb_alloc_cmap(&info->cmap, 16, 0);
--
1.7.3.4
^ permalink raw reply related
* [PATCH 3/5] drivers/video: fsl-diu-fb: remove broken reference count enabling the display
From: Timur Tabi @ 2011-12-19 22:26 UTC (permalink / raw)
To: linux-fbdev
The functions enable_lcdc() and disable_lcdc() used the variable fb_enable
to keep a reference count of when the display is enabled, but the code is
broken. The display is always disabled when disable_lcdc(), and it is
always enabled when enable_lcdc() is called, regardless of the value of
fb_enable. Obviously, we don't need to keep a reference count, so just
remove the variable.
Signed-off-by: Timur Tabi <timur@freescale.com>
---
drivers/video/fsl-diu-fb.c | 12 ++----------
1 files changed, 2 insertions(+), 10 deletions(-)
diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
index 231752e..d8d461d 100644
--- a/drivers/video/fsl-diu-fb.c
+++ b/drivers/video/fsl-diu-fb.c
@@ -352,7 +352,6 @@ struct mfb_info {
* @fsl_diu_info: fb_info objects, one per AOI
* @dev_attr: sysfs structure
* @irq: IRQ
- * @fb_enabled: TRUE if the DIU is enabled, FALSE if not
* @monitor_port: the monitor port this DIU is connected to
* @diu_reg: pointer to the DIU hardware registers
* @reg_lock: spinlock for register access
@@ -371,7 +370,6 @@ struct fsl_diu_data {
struct mfb_info mfb[NUM_AOIS];
struct device_attribute dev_attr;
unsigned int irq;
- int fb_enabled;
enum fsl_diu_monitor_port monitor_port;
struct diu __iomem *diu_reg;
spinlock_t reg_lock;
@@ -619,10 +617,7 @@ static void enable_lcdc(struct fb_info *info)
struct fsl_diu_data *data = mfbi->parent;
struct diu __iomem *hw = data->diu_reg;
- if (!data->fb_enabled) {
- out_be32(&hw->diu_mode, MFB_MODE1);
- data->fb_enabled++;
- }
+ out_be32(&hw->diu_mode, MFB_MODE1);
}
static void disable_lcdc(struct fb_info *info)
@@ -631,10 +626,7 @@ static void disable_lcdc(struct fb_info *info)
struct fsl_diu_data *data = mfbi->parent;
struct diu __iomem *hw = data->diu_reg;
- if (data->fb_enabled) {
- out_be32(&hw->diu_mode, 0);
- data->fb_enabled = 0;
- }
+ out_be32(&hw->diu_mode, 0);
}
static void adjust_aoi_size_position(struct fb_var_screeninfo *var,
--
1.7.3.4
^ permalink raw reply related
* [PATCH 4/5] drivers/video: fsl-diu-fb: add default platform ops functions
From: Timur Tabi @ 2011-12-19 22:26 UTC (permalink / raw)
To: linux-fbdev
The DIU driver requires some platform-specific functions to be defined,
but two them can be optional because most platforms implement them the
same way. Functions set_gamma_table() and get_pixel_format() are only
needed because of quirks in the Freescale MPC8610 HPCD reference board.
For other boards, a generic implementation works, so we shouldn't
require the platform code to define them.
Signed-off-by: Timur Tabi <timur@freescale.com>
---
drivers/video/fsl-diu-fb.c | 64 +++++++++++++++++++++++++++++++++++++++++--
1 files changed, 61 insertions(+), 3 deletions(-)
diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
index d8d461d..e2f4f32 100644
--- a/drivers/video/fsl-diu-fb.c
+++ b/drivers/video/fsl-diu-fb.c
@@ -832,7 +832,8 @@ static void update_lcdc(struct fb_info *info)
for (j = 0; j <= 255; j++)
*gamma_table_base++ = j;
- diu_ops.set_gamma_table(data->monitor_port, data->gamma);
+ if (diu_ops.set_gamma_table)
+ diu_ops.set_gamma_table(data->monitor_port, data->gamma);
disable_lcdc(info);
@@ -917,6 +918,59 @@ static int fsl_diu_set_aoi(struct fb_info *info)
return 0;
}
+/**
+ * fsl_diu_get_pixel_format: return the pixel format for a given color depth
+ *
+ * The pixel format is a 32-bit value that determine which bits in each
+ * pixel are to be used for each color. This is the default function used
+ * if the platform does not define its own version.
+ */
+static u32 fsl_diu_get_pixel_format(unsigned int bits_per_pixel)
+{
+#define PF_BYTE_F 0x10000000
+#define PF_ALPHA_C_MASK 0x0E000000
+#define PF_ALPHA_C_SHIFT 25
+#define PF_BLUE_C_MASK 0x01800000
+#define PF_BLUE_C_SHIFT 23
+#define PF_GREEN_C_MASK 0x00600000
+#define PF_GREEN_C_SHIFT 21
+#define PF_RED_C_MASK 0x00180000
+#define PF_RED_C_SHIFT 19
+#define PF_PALETTE 0x00040000
+#define PF_PIXEL_S_MASK 0x00030000
+#define PF_PIXEL_S_SHIFT 16
+#define PF_COMP_3_MASK 0x0000F000
+#define PF_COMP_3_SHIFT 12
+#define PF_COMP_2_MASK 0x00000F00
+#define PF_COMP_2_SHIFT 8
+#define PF_COMP_1_MASK 0x000000F0
+#define PF_COMP_1_SHIFT 4
+#define PF_COMP_0_MASK 0x0000000F
+#define PF_COMP_0_SHIFT 0
+
+#define MAKE_PF(alpha, red, blue, green, size, c0, c1, c2, c3) \
+ cpu_to_le32(PF_BYTE_F | (alpha << PF_ALPHA_C_SHIFT) | \
+ (blue << PF_BLUE_C_SHIFT) | (green << PF_GREEN_C_SHIFT) | \
+ (red << PF_RED_C_SHIFT) | (c3 << PF_COMP_3_SHIFT) | \
+ (c2 << PF_COMP_2_SHIFT) | (c1 << PF_COMP_1_SHIFT) | \
+ (c0 << PF_COMP_0_SHIFT) | (size << PF_PIXEL_S_SHIFT))
+
+ switch (bits_per_pixel) {
+ case 32:
+ /* 0x88883316 */
+ return MAKE_PF(3, 2, 0, 1, 3, 8, 8, 8, 8);
+ case 24:
+ /* 0x88082219 */
+ return MAKE_PF(4, 0, 1, 2, 2, 0, 8, 8, 8);
+ case 16:
+ /* 0x65053118 */
+ return MAKE_PF(4, 2, 1, 0, 1, 5, 6, 5, 0);
+ default:
+ pr_err("fsl-diu: unsupported color depth %u\n", bits_per_pixel);
+ return 0;
+ }
+}
+
/*
* Using the fb_var_screeninfo in fb_info we set the resolution of this
* particular framebuffer. This function alters the fb_fix_screeninfo stored
@@ -952,8 +1006,12 @@ static int fsl_diu_set_par(struct fb_info *info)
}
}
- ad->pix_fmt = diu_ops.get_pixel_format(data->monitor_port,
- var->bits_per_pixel);
+ if (diu_ops.get_pixel_format)
+ ad->pix_fmt = diu_ops.get_pixel_format(data->monitor_port,
+ var->bits_per_pixel);
+ else
+ ad->pix_fmt = fsl_diu_get_pixel_format(var->bits_per_pixel);
+
ad->addr = cpu_to_le32(info->fix.smem_start);
ad->src_size_g_alpha = cpu_to_le32((var->yres_virtual << 12) |
var->xres_virtual) | mfbi->g_alpha;
--
1.7.3.4
^ permalink raw reply related
* [PATCH 5/5] drivers/video: fsl-diu-fb: merge fsl_diu_alloc() into map_video_memory()
From: Timur Tabi @ 2011-12-19 22:26 UTC (permalink / raw)
To: linux-fbdev
Functions fsl_diu_alloc() and fsl_diu_free() were only being called by
map_video_memory() and unmap_video_memory(), respectively.
Signed-off-by: Timur Tabi <timur@freescale.com>
---
drivers/video/fsl-diu-fb.c | 47 ++++++++++---------------------------------
1 files changed, 11 insertions(+), 36 deletions(-)
diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
index e2f4f32..acf292b 100644
--- a/drivers/video/fsl-diu-fb.c
+++ b/drivers/video/fsl-diu-fb.c
@@ -461,37 +461,6 @@ static enum fsl_diu_monitor_port fsl_diu_name_to_port(const char *s)
return diu_ops.valid_monitor_port(port);
}
-/**
- * fsl_diu_alloc - allocate memory for the DIU
- * @size: number of bytes to allocate
- * @param: returned physical address of memory
- *
- * This function allocates a physically-contiguous block of memory.
- */
-static void *fsl_diu_alloc(size_t size, phys_addr_t *phys)
-{
- void *virt;
-
- virt = alloc_pages_exact(size, GFP_DMA | __GFP_ZERO);
- if (virt)
- *phys = virt_to_phys(virt);
-
- return virt;
-}
-
-/**
- * fsl_diu_free - release DIU memory
- * @virt: pointer returned by fsl_diu_alloc()
- * @size: number of bytes allocated by fsl_diu_alloc()
- *
- * This function releases memory allocated by fsl_diu_alloc().
- */
-static void fsl_diu_free(void *virt, size_t size)
-{
- if (virt && size)
- free_pages_exact(virt, size);
-}
-
/*
* Workaround for failed writing desc register of planes.
* Needed with MPC5121 DIU rev 2.0 silicon.
@@ -875,16 +844,17 @@ static void update_lcdc(struct fb_info *info)
static int map_video_memory(struct fb_info *info)
{
- phys_addr_t phys;
u32 smem_len = info->fix.line_length * info->var.yres_virtual;
+ void *p;
- info->screen_base = fsl_diu_alloc(smem_len, &phys);
- if (info->screen_base = NULL) {
+ p = alloc_pages_exact(smem_len, GFP_DMA | __GFP_ZERO);
+ if (!p) {
dev_err(info->dev, "unable to allocate fb memory\n");
return -ENOMEM;
}
mutex_lock(&info->mm_lock);
- info->fix.smem_start = (unsigned long) phys;
+ info->screen_base = p;
+ info->fix.smem_start = virt_to_phys(info->screen_base);
info->fix.smem_len = smem_len;
mutex_unlock(&info->mm_lock);
info->screen_size = info->fix.smem_len;
@@ -894,12 +864,17 @@ static int map_video_memory(struct fb_info *info)
static void unmap_video_memory(struct fb_info *info)
{
- fsl_diu_free(info->screen_base, info->fix.smem_len);
+ void *p = info->screen_base;
+ size_t l = info->fix.smem_len;
+
mutex_lock(&info->mm_lock);
info->screen_base = NULL;
info->fix.smem_start = 0;
info->fix.smem_len = 0;
mutex_unlock(&info->mm_lock);
+
+ if (p)
+ free_pages_exact(p, l);
}
/*
--
1.7.3.4
^ permalink raw reply related
* [PATCH] s3fb: fix Virge/VX
From: Ondrej Zary @ 2011-12-19 22:39 UTC (permalink / raw)
To: Florian Tobias Schandinat
Cc: Paul Mundt, Ondrej Zajicek, linux-fbdev, Kernel development list
Add memory size detection for Virge/VX and small delay in mode setting (same
as in X.org driver) to fix blank screen problem.
Also adjust DTPC position to fix garbled screen in some modes (tested that
this adjustment does not break other cards - at least Trio32, Trio64V+,
Trio64V2/DX, Virge, Virge/DX).
Tested on ELSA Winner 2000AVI/3D.
Signed-off-by: Ondrej Zary <linux@rainbow-software.org>
--- linux-3.1-orig/drivers/video/s3fb.c 2011-10-24 09:10:05.000000000 +0200
+++ linux-3.1/drivers/video/s3fb.c 2011-12-19 23:28:34.000000000 +0100
@@ -727,7 +727,7 @@
if (par->chip = CHIP_988_VIRGE_VX) {
vga_wcrt(par->state.vgabase, 0x50, 0x00);
vga_wcrt(par->state.vgabase, 0x67, 0x50);
-
+ msleep(10); /* screen remains blank sometimes without this */
vga_wcrt(par->state.vgabase, 0x63, (mode <= 2) ? 0x90 : 0x09);
vga_wcrt(par->state.vgabase, 0x66, 0x90);
}
@@ -901,7 +901,8 @@
/* Set Data Transfer Position */
hsstart = ((info->var.xres + info->var.right_margin) * hmul) / 8;
- value = clamp((htotal + hsstart + 1) / 2, hsstart + 4, htotal + 1);
+ /* + 2 is needed for Virge/VX, does no harm on other cards */
+ value = clamp((htotal + hsstart + 1) / 2 + 2, hsstart + 4, htotal + 1);
svga_wcrt_multi(par->state.vgabase, s3_dtpc_regs, value);
memset_io(info->screen_base, 0x00, screen_size);
@@ -1215,6 +1216,31 @@
info->screen_size = 2 << 20;
break;
}
+ } else if (par->chip = CHIP_988_VIRGE_VX) {
+ switch ((regval & 0x60) >> 5) {
+ case 0: /* 2MB */
+ info->screen_size = 2 << 20;
+ break;
+ case 1: /* 4MB */
+ info->screen_size = 4 << 20;
+ break;
+ case 2: /* 6MB */
+ info->screen_size = 6 << 20;
+ break;
+ case 3: /* 8MB */
+ info->screen_size = 8 << 20;
+ break;
+ }
+ /* off-screen memory */
+ regval = vga_rcrt(par->state.vgabase, 0x37);
+ switch ((regval & 0x60) >> 5) {
+ case 1: /* 4MB */
+ info->screen_size -= 4 << 20;
+ break;
+ case 2: /* 2MB */
+ info->screen_size -= 2 << 20;
+ break;
+ }
} else
info->screen_size = s3_memsizes[regval >> 5] << 10;
info->fix.smem_len = info->screen_size;
--
Ondrej Zary
^ permalink raw reply
* Re: [PATCH RESEND] MXSFB: Fix driver registration
From: Shawn Guo @ 2011-12-19 22:54 UTC (permalink / raw)
To: Marek Vasut
Cc: linux-kernel, linux-fbdev, FlorianSchandinat, Wolfgang Denk,
Stefano Babic, Huang Shijie, Axel Lin, Sascha Hauer
In-Reply-To: <1324309079-10739-1-git-send-email-marek.vasut@gmail.com>
On 19 December 2011 23:37, Marek Vasut <marek.vasut@gmail.com> wrote:
> The driver should be registered with mxsfb_driver, not with mxsfb_devtype.
> This caused obvious null pointer dereference and crash.
>
> Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
> Cc: Wolfgang Denk <wd@denx.de>
> Cc: Stefano Babic <sbabic@denx.de>
> Cc: Shawn Guo <shawn.guo@linaro.org>
> Cc: Huang Shijie <b32955@freescale.com>
> Cc: Axel Lin <axel.lin@gmail.com>
> Cc: Sascha Hauer <s.hauer@pengutronix.de>
> Acked-by: Axel Lin <axel.lin@gmail.com>
> Acked-by: Sascha Hauer <s.hauer@pengutronix.de>
Acked-by: Shawn Guo <shawn.guo@linaro.org>
--
Regards,
Shawn
^ permalink raw reply
* [PATCH v2 0/7] ARM: OMAP1: ams-delta: replace custom I/O with GPIO
From: Janusz Krzysztofik @ 2011-12-19 23:08 UTC (permalink / raw)
To: Tony Lindgren
Cc: linux-omap, linux-arm-kernel, linux-kernel, Janusz Krzysztofik,
Grant Likely, Dmitry Torokhov, Richard Purdie, David Woodhouse,
Tomi Valkeinen, Jarkko Nikula, Liam Girdwood, Mark Brown,
linux-input, linux-mtd, linux-fbdev, alsa-devel
In-Reply-To: <1323634328-856-1-git-send-email-jkrzyszt@tis.icnet.pl>
The Amstrad Delta board has two extra output ports used for driving
input lines of different on-board devices. Those ports are now
controlled with custom functions, provided by the board arch code and
used by several device drivers.
The idea behind the series is to replace those custom I/O functions
with gpiolib API. This way, existing drivers can be made less platform
dependent, and some of them perhaps even superseded with generic GPIO
based drivers after the board platform device descriptions are
converted. Moreover, should a new driver for the on-board Smart Card
controller ever be created, it could be designed as a generic GPIO
based driver, not a custom one.
Changes against initial version:
* the initial patch, which tried to move the gpio-generic driver
initialization up to the postcore_initcall level, replaced with an
alternative solution, moving the on-board devices initialization down
to late_initcall; thanks to Tony Lindgren who suggested this solution,
* dropped patches introducing changes to the modem and ASoC device
handling; those will be addressed in a separate patch series,
* final cleanups also dropped until those remaining devices are updated,
* the serio driver now takes care of one more GPIO pin which, even if
not used, belongs to the device interface and affects its functioning,
* misc code and changelog cosmetic cleanups,
* rebased on top of 3.2-rc6.
Thanks to those who reviewed the initial submission and responded with
their comments or Acks.
Janusz
Janusz Krzysztofik (7):
ARM: OMAP1: ams-delta: register latch dependent devices later
ARM: OMAP1: ams-delta: convert latches to basic_mmio_gpio
ARM: OMAP1: ams-delta: supersede custom led device by leds-gpio
LED: drop leds-ams-delta driver
MTD: NAND: ams-delta: use GPIO instead of custom I/O
omapfb: lcd_ams_delta: drive control lines over GPIO
input: serio: ams-delta: toggle keyboard power over GPIO
arch/arm/mach-omap1/Kconfig | 2 +
arch/arm/mach-omap1/board-ams-delta.c | 226 +++++++++++++++++----
arch/arm/plat-omap/include/plat/board-ams-delta.h | 48 ++---
drivers/input/serio/ams_delta_serio.c | 51 +++--
drivers/leds/Kconfig | 7 -
drivers/leds/Makefile | 1 -
drivers/leds/leds-ams-delta.c | 137 -------------
drivers/mtd/nand/ams-delta.c | 74 +++++--
drivers/video/omap/lcd_ams_delta.c | 27 ++-
sound/soc/omap/ams-delta.c | 4 +
10 files changed, 318 insertions(+), 259 deletions(-)
delete mode 100644 drivers/leds/leds-ams-delta.c
--
1.7.3.4
^ permalink raw reply
* [PATCH v2 6/7] omapfb: lcd_ams_delta: drive control lines over GPIO
From: Janusz Krzysztofik @ 2011-12-19 23:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1323634328-856-1-git-send-email-jkrzyszt@tis.icnet.pl>
Don't use Amstrad Delta custom I/O functions any longer, use GPIO API
instead.
Depends on patch 2/7 "ARM: OMAP1: ams-delta: convert latches to
basic_mmio_gpio".
Signed-off-by: Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>
Acked-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
Cc: Tony Lindgren <tony@atomide.com>
---
Changes against initial version:
* was 8/10,
* no functional changes,
* rebased on top of v2 of patch 2/7, just in case.
arch/arm/mach-omap1/board-ams-delta.c | 10 -------
arch/arm/plat-omap/include/plat/board-ams-delta.h | 2 -
drivers/video/omap/lcd_ams_delta.c | 27 +++++++++++++++-----
3 files changed, 20 insertions(+), 19 deletions(-)
diff --git a/arch/arm/mach-omap1/board-ams-delta.c b/arch/arm/mach-omap1/board-ams-delta.c
index cc6f962..3aba8f9 100644
--- a/arch/arm/mach-omap1/board-ams-delta.c
+++ b/arch/arm/mach-omap1/board-ams-delta.c
@@ -227,16 +227,6 @@ static struct gpio latch_gpios[] __initconst = {
.label = "dockit2",
},
{
- .gpio = AMS_DELTA_GPIO_PIN_LCD_VBLEN,
- .flags = GPIOF_OUT_INIT_LOW,
- .label = "lcd_vblen",
- },
- {
- .gpio = AMS_DELTA_GPIO_PIN_LCD_NDISP,
- .flags = GPIOF_OUT_INIT_LOW,
- .label = "lcd_ndisp",
- },
- {
.gpio = AMS_DELTA_GPIO_PIN_KEYBRD_PWR,
.flags = GPIOF_OUT_INIT_LOW,
.label = "keybrd_pwr",
diff --git a/arch/arm/plat-omap/include/plat/board-ams-delta.h b/arch/arm/plat-omap/include/plat/board-ams-delta.h
index 3e57833..e9ad673 100644
--- a/arch/arm/plat-omap/include/plat/board-ams-delta.h
+++ b/arch/arm/plat-omap/include/plat/board-ams-delta.h
@@ -28,8 +28,6 @@
#if defined (CONFIG_MACH_AMS_DELTA)
-#define AMS_DELTA_LATCH2_LCD_VBLEN 0x0001
-#define AMS_DELTA_LATCH2_LCD_NDISP 0x0002
#define AMD_DELTA_LATCH2_KEYBRD_PWR 0x0100
#define AMD_DELTA_LATCH2_KEYBRD_DATA 0x0200
#define AMD_DELTA_LATCH2_SCARD_RSTIN 0x0400
diff --git a/drivers/video/omap/lcd_ams_delta.c b/drivers/video/omap/lcd_ams_delta.c
index 6978ae4..73b211b 100644
--- a/drivers/video/omap/lcd_ams_delta.c
+++ b/drivers/video/omap/lcd_ams_delta.c
@@ -25,6 +25,7 @@
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/lcd.h>
+#include <linux/gpio.h>
#include <plat/board-ams-delta.h>
#include <mach/hardware.h>
@@ -98,29 +99,41 @@ static struct lcd_ops ams_delta_lcd_ops = {
/* omapfb panel section */
+static struct gpio _gpios[] __initconst_or_module = {
+ {
+ .gpio = AMS_DELTA_GPIO_PIN_LCD_VBLEN,
+ .flags = GPIOF_OUT_INIT_LOW,
+ .label = "lcd_vblen",
+ },
+ {
+ .gpio = AMS_DELTA_GPIO_PIN_LCD_NDISP,
+ .flags = GPIOF_OUT_INIT_LOW,
+ .label = "lcd_ndisp",
+ },
+};
+
static int ams_delta_panel_init(struct lcd_panel *panel,
struct omapfb_device *fbdev)
{
- return 0;
+ return gpio_request_array(_gpios, ARRAY_SIZE(_gpios));
}
static void ams_delta_panel_cleanup(struct lcd_panel *panel)
{
+ gpio_free_array(_gpios, ARRAY_SIZE(_gpios));
}
static int ams_delta_panel_enable(struct lcd_panel *panel)
{
- ams_delta_latch2_write(AMS_DELTA_LATCH2_LCD_NDISP,
- AMS_DELTA_LATCH2_LCD_NDISP);
- ams_delta_latch2_write(AMS_DELTA_LATCH2_LCD_VBLEN,
- AMS_DELTA_LATCH2_LCD_VBLEN);
+ gpio_set_value(AMS_DELTA_GPIO_PIN_LCD_NDISP, 1);
+ gpio_set_value(AMS_DELTA_GPIO_PIN_LCD_VBLEN, 1);
return 0;
}
static void ams_delta_panel_disable(struct lcd_panel *panel)
{
- ams_delta_latch2_write(AMS_DELTA_LATCH2_LCD_VBLEN, 0);
- ams_delta_latch2_write(AMS_DELTA_LATCH2_LCD_NDISP, 0);
+ gpio_set_value(AMS_DELTA_GPIO_PIN_LCD_VBLEN, 0);
+ gpio_set_value(AMS_DELTA_GPIO_PIN_LCD_NDISP, 0);
}
static unsigned long ams_delta_panel_get_caps(struct lcd_panel *panel)
--
1.7.3.4
^ permalink raw reply related
* Re: [PATCH] video: s3c-fb: set missing bitmask of enabled hardware
From: Florian Tobias Schandinat @ 2011-12-19 23:10 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1322820437-20079-1-git-send-email-jg1.han@samsung.com>
On 12/02/2011 10:07 AM, Jingoo Han wrote:
> This patch set missing bitmask of enabled hardware window which
> should be checked whenever the hardware window is enabled.
>
> Signed-off-by: Jingoo Han <jg1.han@samsung.com>
Applied.
Thanks,
Florian Tobias Schandinat
> ---
> drivers/video/s3c-fb.c | 1 +
> 1 files changed, 1 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c
> index 12eaee0..fc3df1d 100644
> --- a/drivers/video/s3c-fb.c
> +++ b/drivers/video/s3c-fb.c
> @@ -574,6 +574,7 @@ static int s3c_fb_set_par(struct fb_info *info)
> }
>
> data = WINCONx_ENWIN;
> + sfb->enabled |= (1 << win->index);
>
> /* note, since we have to round up the bits-per-pixel, we end up
> * relying on the bitfield information for r/g/b/a to work out
^ permalink raw reply
* Re: [PATCH] drivers/video: fsl-diu-fb: merge all allocated data into
From: Florian Tobias Schandinat @ 2011-12-19 23:11 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1322867007-14827-1-git-send-email-timur@freescale.com>
On 12/02/2011 11:03 PM, Timur Tabi wrote:
> The Freescale DIU driver allocates multiple blocks of memory, including
> multiple DMA buffers. Merge all of these blocks into one data structure.
>
> Specifically:
>
> 1) struct fsl_diu_data now contains everything that needs to be allocated,
> except for the framebuffers themselves. DMA'able objects are aligned correctly
> within the structure.
>
> 2) struct diu_addr is no longer needed, because we don't have to manage
> multiple blocks of DMA memory.
>
> 3) Since there's no diu_addr any more, macro DMA_ADDR is used to calculate
> the DMA address of any field in fsl_diu_data.
>
> 4) Functions allocate_buf() and free_buf() are no longer needed, because we
> now assume that dma_alloc_coherent() will allocate a page-aligned block,
> and everything is properly aligned with fsl_diu_data already, so we no longer
> need to align any memory blocks ourselves.
>
> 5) The "dummy" area descriptor is now defined separately from the other
> five ADs, so NUM_AOIS (previously called FSL_AOI_NUM) is now set to five
> instead of six. Previously, all six were combined together to avoid a
> separate call to allocate_buf() just for the dummy AD.
>
> 6) framebuffer_alloc() and framebuffer_release() are no longer used. The
> framebuffer is initialized manually.
>
> 7) Error handling is simplified since there's only one memory buffer
> allocated.
>
> Signed-off-by: Timur Tabi <timur@freescale.com>
As you like the idea, applied.
Thanks,
Florian Tobias Schandinat
> ---
> drivers/video/fsl-diu-fb.c | 326 +++++++++++++++++++-------------------------
> 1 files changed, 139 insertions(+), 187 deletions(-)
>
> diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
> index a16beeb..4d54188 100644
> --- a/drivers/video/fsl-diu-fb.c
> +++ b/drivers/video/fsl-diu-fb.c
> @@ -36,8 +36,7 @@
> #include <linux/fsl-diu-fb.h>
> #include "edid.h"
>
> -#define FSL_AOI_NUM 6 /* 5 AOIs and one dummy AOI */
> - /* 1 for plane 0, 2 for plane 1&2 each */
> +#define NUM_AOIS 5 /* 1 for plane 0, 2 for planes 1 & 2 each */
>
> /* HW cursor parameters */
> #define MAX_CURS 32
> @@ -49,12 +48,6 @@
> #define INT_PARERR 0x08 /* Display parameters error interrupt */
> #define INT_LS_BF_VS 0x10 /* Lines before vsync. interrupt */
>
> -struct diu_addr {
> - void *vaddr; /* Virtual address */
> - dma_addr_t paddr; /* Physical address */
> - __u32 offset;
> -};
> -
> /*
> * List of supported video modes
> *
> @@ -330,23 +323,6 @@ static unsigned int d_cache_line_size;
>
> static DEFINE_SPINLOCK(diu_lock);
>
> -struct fsl_diu_data {
> - struct fb_info *fsl_diu_info[FSL_AOI_NUM - 1];
> - /*FSL_AOI_NUM has one dummy AOI */
> - struct device_attribute dev_attr;
> - struct diu_ad *dummy_ad;
> - void *dummy_aoi_virt;
> - unsigned int irq;
> - int fb_enabled;
> - enum fsl_diu_monitor_port monitor_port;
> - struct diu __iomem *diu_reg;
> - spinlock_t reg_lock;
> - struct diu_addr ad;
> - struct diu_addr gamma;
> - struct diu_addr pallete;
> - struct diu_addr cursor;
> -};
> -
> enum mfb_index {
> PLANE0 = 0, /* Plane 0, only one AOI that fills the screen */
> PLANE1_AOI0, /* Plane 1, first AOI */
> @@ -370,6 +346,44 @@ struct mfb_info {
> u8 *edid_data;
> };
>
> +/**
> + * struct fsl_diu_data - per-DIU data structure
> + * @dma_addr: DMA address of this structure
> + * @fsl_diu_info: fb_info objects, one per AOI
> + * @dev_attr: sysfs structure
> + * @irq: IRQ
> + * @fb_enabled: TRUE if the DIU is enabled, FALSE if not
> + * @monitor_port: the monitor port this DIU is connected to
> + * @diu_reg: pointer to the DIU hardware registers
> + * @reg_lock: spinlock for register access
> + * @dummy_aoi: video buffer for the 4x4 32-bit dummy AOI
> + * dummy_ad: DIU Area Descriptor for the dummy AOI
> + * @ad[]: Area Descriptors for each real AOI
> + * @gamma: gamma color table
> + * @cursor: hardware cursor data
> + *
> + * This data structure must be allocated with 32-byte alignment, so that the
> + * internal fields can be aligned properly.
> + */
> +struct fsl_diu_data {
> + dma_addr_t dma_addr;
> + struct fb_info fsl_diu_info[NUM_AOIS];
> + struct mfb_info mfb[NUM_AOIS];
> + struct device_attribute dev_attr;
> + unsigned int irq;
> + int fb_enabled;
> + enum fsl_diu_monitor_port monitor_port;
> + struct diu __iomem *diu_reg;
> + spinlock_t reg_lock;
> + u8 dummy_aoi[4 * 4 * 4];
> + struct diu_ad dummy_ad __aligned(8);
> + struct diu_ad ad[NUM_AOIS] __aligned(8);
> + u8 gamma[256 * 3] __aligned(32);
> + u8 cursor[MAX_CURS * MAX_CURS * 2] __aligned(32);
> +} __aligned(32);
> +
> +/* Determine the DMA address of a member of the fsl_diu_data structure */
> +#define DMA_ADDR(p, f) ((p)->dma_addr + offsetof(struct fsl_diu_data, f))
>
> static struct mfb_info mfb_template[] = {
> {
> @@ -504,7 +518,7 @@ static void fsl_diu_enable_panel(struct fb_info *info)
> wr_reg_wa(&hw->desc[0], ad->paddr);
> break;
> case PLANE1_AOI0:
> - cmfbi = machine_data->fsl_diu_info[2]->par;
> + cmfbi = &machine_data->mfb[2];
> if (hw->desc[1] != ad->paddr) { /* AOI0 closed */
> if (cmfbi->count > 0) /* AOI1 open */
> ad->next_ad > @@ -515,7 +529,7 @@ static void fsl_diu_enable_panel(struct fb_info *info)
> }
> break;
> case PLANE2_AOI0:
> - cmfbi = machine_data->fsl_diu_info[4]->par;
> + cmfbi = &machine_data->mfb[4];
> if (hw->desc[2] != ad->paddr) { /* AOI0 closed */
> if (cmfbi->count > 0) /* AOI1 open */
> ad->next_ad > @@ -526,17 +540,17 @@ static void fsl_diu_enable_panel(struct fb_info *info)
> }
> break;
> case PLANE1_AOI1:
> - pmfbi = machine_data->fsl_diu_info[1]->par;
> + pmfbi = &machine_data->mfb[1];
> ad->next_ad = 0;
> - if (hw->desc[1] = machine_data->dummy_ad->paddr)
> + if (hw->desc[1] = machine_data->dummy_ad.paddr)
> wr_reg_wa(&hw->desc[1], ad->paddr);
> else /* AOI0 open */
> pmfbi->ad->next_ad = cpu_to_le32(ad->paddr);
> break;
> case PLANE2_AOI1:
> - pmfbi = machine_data->fsl_diu_info[3]->par;
> + pmfbi = &machine_data->mfb[3];
> ad->next_ad = 0;
> - if (hw->desc[2] = machine_data->dummy_ad->paddr)
> + if (hw->desc[2] = machine_data->dummy_ad.paddr)
> wr_reg_wa(&hw->desc[2], ad->paddr);
> else /* AOI0 was open */
> pmfbi->ad->next_ad = cpu_to_le32(ad->paddr);
> @@ -553,47 +567,47 @@ static void fsl_diu_disable_panel(struct fb_info *info)
>
> switch (mfbi->index) {
> case PLANE0:
> - if (hw->desc[0] != machine_data->dummy_ad->paddr)
> - wr_reg_wa(&hw->desc[0], machine_data->dummy_ad->paddr);
> + if (hw->desc[0] != machine_data->dummy_ad.paddr)
> + wr_reg_wa(&hw->desc[0], machine_data->dummy_ad.paddr);
> break;
> case PLANE1_AOI0:
> - cmfbi = machine_data->fsl_diu_info[2]->par;
> + cmfbi = &machine_data->mfb[2];
> if (cmfbi->count > 0) /* AOI1 is open */
> wr_reg_wa(&hw->desc[1], cmfbi->ad->paddr);
> /* move AOI1 to the first */
> else /* AOI1 was closed */
> - wr_reg_wa(&hw->desc[1], machine_data->dummy_ad->paddr);
> + wr_reg_wa(&hw->desc[1], machine_data->dummy_ad.paddr);
> /* close AOI 0 */
> break;
> case PLANE2_AOI0:
> - cmfbi = machine_data->fsl_diu_info[4]->par;
> + cmfbi = &machine_data->mfb[4];
> if (cmfbi->count > 0) /* AOI1 is open */
> wr_reg_wa(&hw->desc[2], cmfbi->ad->paddr);
> /* move AOI1 to the first */
> else /* AOI1 was closed */
> - wr_reg_wa(&hw->desc[2], machine_data->dummy_ad->paddr);
> + wr_reg_wa(&hw->desc[2], machine_data->dummy_ad.paddr);
> /* close AOI 0 */
> break;
> case PLANE1_AOI1:
> - pmfbi = machine_data->fsl_diu_info[1]->par;
> + pmfbi = &machine_data->mfb[1];
> if (hw->desc[1] != ad->paddr) {
> /* AOI1 is not the first in the chain */
> if (pmfbi->count > 0)
> /* AOI0 is open, must be the first */
> pmfbi->ad->next_ad = 0;
> } else /* AOI1 is the first in the chain */
> - wr_reg_wa(&hw->desc[1], machine_data->dummy_ad->paddr);
> + wr_reg_wa(&hw->desc[1], machine_data->dummy_ad.paddr);
> /* close AOI 1 */
> break;
> case PLANE2_AOI1:
> - pmfbi = machine_data->fsl_diu_info[3]->par;
> + pmfbi = &machine_data->mfb[3];
> if (hw->desc[2] != ad->paddr) {
> /* AOI1 is not the first in the chain */
> if (pmfbi->count > 0)
> /* AOI0 is open, must be the first */
> pmfbi->ad->next_ad = 0;
> } else /* AOI1 is the first in the chain */
> - wr_reg_wa(&hw->desc[2], machine_data->dummy_ad->paddr);
> + wr_reg_wa(&hw->desc[2], machine_data->dummy_ad.paddr);
> /* close AOI 1 */
> break;
> }
> @@ -633,8 +647,8 @@ static void adjust_aoi_size_position(struct fb_var_screeninfo *var,
> int lower_aoi_is_open, upper_aoi_is_open;
> __u32 base_plane_width, base_plane_height, upper_aoi_height;
>
> - base_plane_width = machine_data->fsl_diu_info[0]->var.xres;
> - base_plane_height = machine_data->fsl_diu_info[0]->var.yres;
> + base_plane_width = machine_data->fsl_diu_info[0].var.xres;
> + base_plane_height = machine_data->fsl_diu_info[0].var.yres;
>
> if (mfbi->x_aoi_d < 0)
> mfbi->x_aoi_d = 0;
> @@ -649,7 +663,7 @@ static void adjust_aoi_size_position(struct fb_var_screeninfo *var,
> break;
> case PLANE1_AOI0:
> case PLANE2_AOI0:
> - lower_aoi_mfbi = machine_data->fsl_diu_info[index+1]->par;
> + lower_aoi_mfbi = machine_data->fsl_diu_info[index+1].par;
> lower_aoi_is_open = lower_aoi_mfbi->count > 0 ? 1 : 0;
> if (var->xres > base_plane_width)
> var->xres = base_plane_width;
> @@ -667,9 +681,9 @@ static void adjust_aoi_size_position(struct fb_var_screeninfo *var,
> break;
> case PLANE1_AOI1:
> case PLANE2_AOI1:
> - upper_aoi_mfbi = machine_data->fsl_diu_info[index-1]->par;
> + upper_aoi_mfbi = machine_data->fsl_diu_info[index-1].par;
> upper_aoi_height > - machine_data->fsl_diu_info[index-1]->var.yres;
> + machine_data->fsl_diu_info[index-1].var.yres;
> upper_aoi_bottom = upper_aoi_mfbi->y_aoi_d + upper_aoi_height;
> upper_aoi_is_open = upper_aoi_mfbi->count > 0 ? 1 : 0;
> if (var->xres > base_plane_width)
> @@ -812,15 +826,15 @@ static void update_lcdc(struct fb_info *info)
> struct fsl_diu_data *machine_data = mfbi->parent;
> struct diu __iomem *hw;
> int i, j;
> - char __iomem *cursor_base, *gamma_table_base;
> + u8 *gamma_table_base;
>
> u32 temp;
>
> hw = machine_data->diu_reg;
>
> diu_ops.set_monitor_port(machine_data->monitor_port);
> - gamma_table_base = machine_data->gamma.vaddr;
> - cursor_base = machine_data->cursor.vaddr;
> + gamma_table_base = machine_data->gamma;
> +
> /* Prep for DIU init - gamma table, cursor table */
>
> for (i = 0; i <= 2; i++)
> @@ -828,14 +842,14 @@ static void update_lcdc(struct fb_info *info)
> *gamma_table_base++ = j;
>
> diu_ops.set_gamma_table(machine_data->monitor_port,
> - machine_data->gamma.vaddr);
> + machine_data->gamma);
>
> disable_lcdc(info);
>
> /* Program DIU registers */
>
> - out_be32(&hw->gamma, machine_data->gamma.paddr);
> - out_be32(&hw->cursor, machine_data->cursor.paddr);
> + out_be32(&hw->gamma, DMA_ADDR(machine_data, gamma));
> + out_be32(&hw->cursor, DMA_ADDR(machine_data, cursor));
>
> out_be32(&hw->bgnd, 0x007F7F7F); /* BGND */
> out_be32(&hw->bgnd_wb, 0); /* BGND_WB */
> @@ -1423,37 +1437,6 @@ static int fsl_diu_resume(struct platform_device *ofdev)
> #define fsl_diu_resume NULL
> #endif /* CONFIG_PM */
>
> -/* Align to 64-bit(8-byte), 32-byte, etc. */
> -static int allocate_buf(struct device *dev, struct diu_addr *buf, u32 size,
> - u32 bytes_align)
> -{
> - u32 offset;
> - dma_addr_t mask;
> -
> - buf->vaddr > - dma_alloc_coherent(dev, size + bytes_align, &buf->paddr,
> - GFP_DMA | __GFP_ZERO);
> - if (!buf->vaddr)
> - return -ENOMEM;
> -
> - mask = bytes_align - 1;
> - offset = buf->paddr & mask;
> - if (offset) {
> - buf->offset = bytes_align - offset;
> - buf->paddr = buf->paddr + offset;
> - } else
> - buf->offset = 0;
> -
> - return 0;
> -}
> -
> -static void free_buf(struct device *dev, struct diu_addr *buf, u32 size,
> - u32 bytes_align)
> -{
> - dma_free_coherent(dev, size + bytes_align, buf->vaddr,
> - buf->paddr - buf->offset);
> -}
> -
> static ssize_t store_monitor(struct device *device,
> struct device_attribute *attr, const char *buf, size_t count)
> {
> @@ -1468,11 +1451,10 @@ static ssize_t store_monitor(struct device *device,
> /* All AOIs need adjust pixel format
> * fsl_diu_set_par only change the pixsel format here
> * unlikely to fail. */
> - fsl_diu_set_par(machine_data->fsl_diu_info[0]);
> - fsl_diu_set_par(machine_data->fsl_diu_info[1]);
> - fsl_diu_set_par(machine_data->fsl_diu_info[2]);
> - fsl_diu_set_par(machine_data->fsl_diu_info[3]);
> - fsl_diu_set_par(machine_data->fsl_diu_info[4]);
> + unsigned int i;
> +
> + for (i=0; i < NUM_AOIS; i++)
> + fsl_diu_set_par(&machine_data->fsl_diu_info[i]);
> }
> return count;
> }
> @@ -1499,28 +1481,52 @@ static int __devinit fsl_diu_probe(struct platform_device *pdev)
> {
> struct device_node *np = pdev->dev.of_node;
> struct mfb_info *mfbi;
> - phys_addr_t dummy_ad_addr = 0;
> - int ret, i, error = 0;
> struct fsl_diu_data *machine_data;
> int diu_mode;
> + dma_addr_t dma_addr; /* DMA addr of machine_data struct */
> + unsigned int i;
> + int ret;
>
> - machine_data = kzalloc(sizeof(struct fsl_diu_data), GFP_KERNEL);
> + machine_data = dma_alloc_coherent(&pdev->dev,
> + sizeof(struct fsl_diu_data), &dma_addr, GFP_DMA | __GFP_ZERO);
> if (!machine_data)
> return -ENOMEM;
> + machine_data->dma_addr = dma_addr;
> +
> + /*
> + * dma_alloc_coherent() uses a page allocator, so the address is
> + * always page-aligned. We need the memory to be 32-byte aligned,
> + * so that's good. However, if one day the allocator changes, we
> + * need to catch that. It's not worth the effort to handle unaligned
> + * alloctions now because it's highly unlikely to ever be a problem.
> + */
> + if ((unsigned long)machine_data & 31) {
> + dev_err(&pdev->dev, "misaligned allocation");
> + ret = -ENOMEM;
> + goto error;
> + }
>
> spin_lock_init(&machine_data->reg_lock);
>
> - for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) {
> - machine_data->fsl_diu_info[i] > - framebuffer_alloc(sizeof(struct mfb_info), &pdev->dev);
> - if (!machine_data->fsl_diu_info[i]) {
> - dev_err(&pdev->dev, "cannot allocate memory\n");
> - ret = -ENOMEM;
> - goto error2;
> - }
> - mfbi = machine_data->fsl_diu_info[i]->par;
> + for (i = 0; i < NUM_AOIS; i++) {
> + struct fb_info *info = &machine_data->fsl_diu_info[i];
> +
> + info->device = &pdev->dev;
> + info->par = &machine_data->mfb[i];
> +
> + /*
> + * We store the physical address of the AD in the reserved
> + * 'paddr' field of the AD itself.
> + */
> + machine_data->ad[i].paddr = DMA_ADDR(machine_data, ad[i]);
> +
> + info->fix.smem_start = 0;
> +
> + /* Initialize the AOI data structure */
> + mfbi = info->par;
> memcpy(mfbi, &mfb_template[i], sizeof(struct mfb_info));
> mfbi->parent = machine_data;
> + mfbi->ad = &machine_data->ad[i];
>
> if (mfbi->index = PLANE0) {
> const u8 *prop;
> @@ -1538,7 +1544,7 @@ static int __devinit fsl_diu_probe(struct platform_device *pdev)
> if (!machine_data->diu_reg) {
> dev_err(&pdev->dev, "cannot map DIU registers\n");
> ret = -EFAULT;
> - goto error2;
> + goto error;
> }
>
> diu_mode = in_be32(&machine_data->diu_reg->diu_mode);
> @@ -1555,41 +1561,16 @@ static int __devinit fsl_diu_probe(struct platform_device *pdev)
> }
> machine_data->monitor_port = monitor_port;
>
> - /* Area descriptor memory pool aligns to 64-bit boundary */
> - if (allocate_buf(&pdev->dev, &machine_data->ad,
> - sizeof(struct diu_ad) * FSL_AOI_NUM, 8))
> - return -ENOMEM;
> -
> - /* Get memory for Gamma Table - 32-byte aligned memory */
> - if (allocate_buf(&pdev->dev, &machine_data->gamma, 768, 32)) {
> - ret = -ENOMEM;
> - goto error;
> - }
> -
> - /* For performance, cursor bitmap buffer aligns to 32-byte boundary */
> - if (allocate_buf(&pdev->dev, &machine_data->cursor,
> - MAX_CURS * MAX_CURS * 2, 32)) {
> - ret = -ENOMEM;
> - goto error;
> - }
> -
> - i = ARRAY_SIZE(machine_data->fsl_diu_info);
> - machine_data->dummy_ad = (struct diu_ad *)((u32)machine_data->ad.vaddr +
> - machine_data->ad.offset) + i;
> - machine_data->dummy_ad->paddr = machine_data->ad.paddr +
> - i * sizeof(struct diu_ad);
> - machine_data->dummy_aoi_virt = fsl_diu_alloc(64, &dummy_ad_addr);
> - if (!machine_data->dummy_aoi_virt) {
> - ret = -ENOMEM;
> - goto error;
> - }
> - machine_data->dummy_ad->addr = cpu_to_le32(dummy_ad_addr);
> - machine_data->dummy_ad->pix_fmt = 0x88882317;
> - machine_data->dummy_ad->src_size_g_alpha = cpu_to_le32((4 << 12) | 4);
> - machine_data->dummy_ad->aoi_size = cpu_to_le32((4 << 16) | 2);
> - machine_data->dummy_ad->offset_xyi = 0;
> - machine_data->dummy_ad->offset_xyd = 0;
> - machine_data->dummy_ad->next_ad = 0;
> + /* Initialize the dummy Area Descriptor */
> + machine_data->dummy_ad.addr > + cpu_to_le32(DMA_ADDR(machine_data, dummy_aoi));
> + machine_data->dummy_ad.pix_fmt = 0x88882317;
> + machine_data->dummy_ad.src_size_g_alpha = cpu_to_le32((4 << 12) | 4);
> + machine_data->dummy_ad.aoi_size = cpu_to_le32((4 << 16) | 2);
> + machine_data->dummy_ad.offset_xyi = 0;
> + machine_data->dummy_ad.offset_xyd = 0;
> + machine_data->dummy_ad.next_ad = 0;
> + machine_data->dummy_ad.paddr = DMA_ADDR(machine_data, dummy_ad);
>
> /*
> * Let DIU display splash screen if it was pre-initialized
> @@ -1597,19 +1578,13 @@ static int __devinit fsl_diu_probe(struct platform_device *pdev)
> */
> if (diu_mode = MFB_MODE0)
> out_be32(&machine_data->diu_reg->desc[0],
> - machine_data->dummy_ad->paddr);
> -
> - out_be32(&machine_data->diu_reg->desc[1], machine_data->dummy_ad->paddr);
> - out_be32(&machine_data->diu_reg->desc[2], machine_data->dummy_ad->paddr);
> -
> - for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) {
> - machine_data->fsl_diu_info[i]->fix.smem_start = 0;
> - mfbi = machine_data->fsl_diu_info[i]->par;
> - mfbi->ad = (struct diu_ad *)((u32)machine_data->ad.vaddr
> - + machine_data->ad.offset) + i;
> - mfbi->ad->paddr > - machine_data->ad.paddr + i * sizeof(struct diu_ad);
> - ret = install_fb(machine_data->fsl_diu_info[i]);
> + machine_data->dummy_ad.paddr);
> +
> + out_be32(&machine_data->diu_reg->desc[1], machine_data->dummy_ad.paddr);
> + out_be32(&machine_data->diu_reg->desc[2], machine_data->dummy_ad.paddr);
> +
> + for (i = 0; i < NUM_AOIS; i++) {
> + ret = install_fb(&machine_data->fsl_diu_info[i]);
> if (ret) {
> dev_err(&pdev->dev, "could not register fb %d\n", i);
> goto error;
> @@ -1626,9 +1601,8 @@ static int __devinit fsl_diu_probe(struct platform_device *pdev)
> machine_data->dev_attr.attr.mode = S_IRUGO|S_IWUSR;
> machine_data->dev_attr.show = show_monitor;
> machine_data->dev_attr.store = store_monitor;
> - error = device_create_file(machine_data->fsl_diu_info[0]->dev,
> - &machine_data->dev_attr);
> - if (error) {
> + ret = device_create_file(&pdev->dev, &machine_data->dev_attr);
> + if (ret) {
> dev_err(&pdev->dev, "could not create sysfs file %s\n",
> machine_data->dev_attr.attr.name);
> }
> @@ -1637,26 +1611,13 @@ static int __devinit fsl_diu_probe(struct platform_device *pdev)
> return 0;
>
> error:
> - for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++)
> - uninstall_fb(machine_data->fsl_diu_info[i]);
> -
> - if (machine_data->ad.vaddr)
> - free_buf(&pdev->dev, &machine_data->ad,
> - sizeof(struct diu_ad) * FSL_AOI_NUM, 8);
> - if (machine_data->gamma.vaddr)
> - free_buf(&pdev->dev, &machine_data->gamma, 768, 32);
> - if (machine_data->cursor.vaddr)
> - free_buf(&pdev->dev, &machine_data->cursor,
> - MAX_CURS * MAX_CURS * 2, 32);
> - if (machine_data->dummy_aoi_virt)
> - fsl_diu_free(machine_data->dummy_aoi_virt, 64);
> + for (i = 0; i < NUM_AOIS; i++)
> + uninstall_fb(&machine_data->fsl_diu_info[i]);
> +
> iounmap(machine_data->diu_reg);
>
> -error2:
> - for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++)
> - if (machine_data->fsl_diu_info[i])
> - framebuffer_release(machine_data->fsl_diu_info[i]);
> - kfree(machine_data);
> + dma_free_coherent(&pdev->dev, sizeof(struct fsl_diu_data),
> + machine_data, machine_data->dma_addr);
>
> return ret;
> }
> @@ -1667,25 +1628,16 @@ static int fsl_diu_remove(struct platform_device *pdev)
> int i;
>
> machine_data = dev_get_drvdata(&pdev->dev);
> - disable_lcdc(machine_data->fsl_diu_info[0]);
> + disable_lcdc(&machine_data->fsl_diu_info[0]);
> free_irq_local(machine_data);
> - for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++)
> - uninstall_fb(machine_data->fsl_diu_info[i]);
> - if (machine_data->ad.vaddr)
> - free_buf(&pdev->dev, &machine_data->ad,
> - sizeof(struct diu_ad) * FSL_AOI_NUM, 8);
> - if (machine_data->gamma.vaddr)
> - free_buf(&pdev->dev, &machine_data->gamma, 768, 32);
> - if (machine_data->cursor.vaddr)
> - free_buf(&pdev->dev, &machine_data->cursor,
> - MAX_CURS * MAX_CURS * 2, 32);
> - if (machine_data->dummy_aoi_virt)
> - fsl_diu_free(machine_data->dummy_aoi_virt, 64);
> +
> + for (i = 0; i < NUM_AOIS; i++)
> + uninstall_fb(&machine_data->fsl_diu_info[i]);
> +
> iounmap(machine_data->diu_reg);
> - for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++)
> - if (machine_data->fsl_diu_info[i])
> - framebuffer_release(machine_data->fsl_diu_info[i]);
> - kfree(machine_data);
> +
> + dma_free_coherent(&pdev->dev, sizeof(struct fsl_diu_data),
> + machine_data, machine_data->dma_addr);
>
> return 0;
> }
^ permalink raw reply
* Re: [PATCH V2] video: s3c-fb: modify runtime pm functions
From: Florian Tobias Schandinat @ 2011-12-19 23:12 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <002801ccb2f7$926c0240$b74406c0$%han@samsung.com>
On 12/05/2011 02:42 AM, Jingoo Han wrote:
> Runtime suspend and runtime resume are modified in order to
> reduce the complexity and improve the usability of runtime pm.
> After probe function, s3c-fb driver is not suspended until
> suspend or remove is called.
>
> The scheme is changed as follows:
> runtime_get is only called in probe and resume.
> runtime_put is only called in remove and suspend.
> open/close cannot call the runtime_get/put.
>
> Also, runtime_susepnd/resume are just called by runtime pm,
> not doing suspend/resume routine any longer. This is because
> open/close cannot call the runtime_get/put; the suspend/resume
> routine in runtime_suspend/resume were previously used when
> open and close were called.
>
> The name of s3c-fb dev_pm_ops is changed from s3cfb_pm_ops to
> s3c_fb_pm_ops in order to use more consistent naming.
>
> Signed-off-by: Jingoo Han <jg1.han@samsung.com>
Applied.
Thanks,
Florian Tobias Schandinat
> ---
> v2: fix unaligned lines
>
> drivers/video/s3c-fb.c | 51 ++++++++++++++++++-----------------------------
> 1 files changed, 20 insertions(+), 31 deletions(-)
>
> diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c
> index e84677e..91e629a 100644
> --- a/drivers/video/s3c-fb.c
> +++ b/drivers/video/s3c-fb.c
> @@ -1028,30 +1028,8 @@ static int s3c_fb_ioctl(struct fb_info *info, unsigned int cmd,
> return ret;
> }
>
> -static int s3c_fb_open(struct fb_info *info, int user)
> -{
> - struct s3c_fb_win *win = info->par;
> - struct s3c_fb *sfb = win->parent;
> -
> - pm_runtime_get_sync(sfb->dev);
> -
> - return 0;
> -}
> -
> -static int s3c_fb_release(struct fb_info *info, int user)
> -{
> - struct s3c_fb_win *win = info->par;
> - struct s3c_fb *sfb = win->parent;
> -
> - pm_runtime_put_sync(sfb->dev);
> -
> - return 0;
> -}
> -
> static struct fb_ops s3c_fb_ops = {
> .owner = THIS_MODULE,
> - .fb_open = s3c_fb_open,
> - .fb_release = s3c_fb_release,
> .fb_check_var = s3c_fb_check_var,
> .fb_set_par = s3c_fb_set_par,
> .fb_blank = s3c_fb_blank,
> @@ -1458,7 +1436,6 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev)
> }
>
> platform_set_drvdata(pdev, sfb);
> - pm_runtime_put_sync(sfb->dev);
>
> return 0;
>
> @@ -1498,8 +1475,6 @@ static int __devexit s3c_fb_remove(struct platform_device *pdev)
> struct s3c_fb *sfb = platform_get_drvdata(pdev);
> int win;
>
> - pm_runtime_get_sync(sfb->dev);
> -
> for (win = 0; win < S3C_FB_MAX_WIN; win++)
> if (sfb->windows[win])
> s3c_fb_release_win(sfb, sfb->windows[win]);
> @@ -1525,7 +1500,7 @@ static int __devexit s3c_fb_remove(struct platform_device *pdev)
> return 0;
> }
>
> -#ifdef CONFIG_PM
> +#ifdef CONFIG_PM_SLEEP
> static int s3c_fb_suspend(struct device *dev)
> {
> struct platform_device *pdev = to_platform_device(dev);
> @@ -1546,6 +1521,8 @@ static int s3c_fb_suspend(struct device *dev)
> clk_disable(sfb->lcd_clk);
>
> clk_disable(sfb->bus_clk);
> + pm_runtime_put_sync(sfb->dev);
> +
> return 0;
> }
>
> @@ -1557,6 +1534,7 @@ static int s3c_fb_resume(struct device *dev)
> struct s3c_fb_win *win;
> int win_no;
>
> + pm_runtime_get_sync(sfb->dev);
> clk_enable(sfb->bus_clk);
>
> if (!sfb->variant.has_clksel)
> @@ -1590,11 +1568,19 @@ static int s3c_fb_resume(struct device *dev)
>
> return 0;
> }
> -#else
> -#define s3c_fb_suspend NULL
> -#define s3c_fb_resume NULL
> #endif
>
> +#ifdef CONFIG_PM_RUNTIME
> +static int s3c_fb_runtime_suspend(struct device *dev)
> +{
> + return 0;
> +}
> +
> +static int s3c_fb_runtime_resume(struct device *dev)
> +{
> + return 0;
> +}
> +#endif
>
> #define VALID_BPP124 (VALID_BPP(1) | VALID_BPP(2) | VALID_BPP(4))
> #define VALID_BPP1248 (VALID_BPP124 | VALID_BPP(8))
> @@ -1917,7 +1903,10 @@ static struct platform_device_id s3c_fb_driver_ids[] = {
> };
> MODULE_DEVICE_TABLE(platform, s3c_fb_driver_ids);
>
> -static UNIVERSAL_DEV_PM_OPS(s3cfb_pm_ops, s3c_fb_suspend, s3c_fb_resume, NULL);
> +static const struct dev_pm_ops s3c_fb_pm_ops = {
> + SET_SYSTEM_SLEEP_PM_OPS(s3c_fb_suspend, s3c_fb_resume)
> + SET_RUNTIME_PM_OPS(s3c_fb_runtime_suspend, s3c_fb_runtime_resume, NULL)
> +};
>
> static struct platform_driver s3c_fb_driver = {
> .probe = s3c_fb_probe,
> @@ -1926,7 +1915,7 @@ static struct platform_driver s3c_fb_driver = {
> .driver = {
> .name = "s3c-fb",
> .owner = THIS_MODULE,
> - .pm = &s3cfb_pm_ops,
> + .pm = &s3c_fb_pm_ops,
> },
> };
>
^ permalink raw reply
* Re: [PATCH] video: s3c-fb: add shadow register protect
From: Florian Tobias Schandinat @ 2011-12-19 23:13 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <002901ccb588$e2d43700$a87ca500$%han@samsung.com>
On 12/08/2011 09:08 AM, Jingoo Han wrote:
> Shadow registers should be protectd whenever the registers are
> updated. Shadow registers are updated after SHADOWCON shadow
> register is cleared.
>
> Signed-off-by: Jingoo Han <jg1.han@samsung.com>
Applied.
Thanks,
Florian Tobias Schandinat
> ---
> drivers/video/s3c-fb.c | 16 +++++++++++++++-
> 1 files changed, 15 insertions(+), 1 deletions(-)
>
> diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c
> index e84677e..e04c2ab 100644
> --- a/drivers/video/s3c-fb.c
> +++ b/drivers/video/s3c-fb.c
> @@ -811,12 +811,16 @@ static int s3c_fb_blank(int blank_mode, struct fb_info *info)
>
> case FB_BLANK_NORMAL:
> /* disable the DMA and display 0x0 (black) */
> + shadow_protect_win(win, 1);
> writel(WINxMAP_MAP | WINxMAP_MAP_COLOUR(0x0),
> sfb->regs + sfb->variant.winmap + (index * 4));
> + shadow_protect_win(win, 0);
> break;
>
> case FB_BLANK_UNBLANK:
> + shadow_protect_win(win, 1);
> writel(0x0, sfb->regs + sfb->variant.winmap + (index * 4));
> + shadow_protect_win(win, 0);
> wincon |= WINCONx_ENWIN;
> sfb->enabled |= (1 << index);
> break;
> @@ -827,7 +831,9 @@ static int s3c_fb_blank(int blank_mode, struct fb_info *info)
> return 1;
> }
>
> + shadow_protect_win(win, 1);
> writel(wincon, sfb->regs + sfb->variant.wincon + (index * 4));
> + shadow_protect_win(win, 0);
>
> /* Check the enabled state to see if we need to be running the
> * main LCD interface, as if there are no active windows then
> @@ -846,8 +852,11 @@ static int s3c_fb_blank(int blank_mode, struct fb_info *info)
> /* we're stuck with this until we can do something about overriding
> * the power control using the blanking event for a single fb.
> */
> - if (index = sfb->pdata->default_win)
> + if (index = sfb->pdata->default_win) {
> + shadow_protect_win(win, 1);
> s3c_fb_enable(sfb, blank_mode != FB_BLANK_POWERDOWN ? 1 : 0);
> + shadow_protect_win(win, 0);
> + }
>
> return 0;
> }
> @@ -1572,10 +1581,15 @@ static int s3c_fb_resume(struct device *dev)
>
> for (win_no = 0; win_no < sfb->variant.nr_windows - 1; win_no++) {
> void __iomem *regs = sfb->regs + sfb->variant.keycon;
> + win = sfb->windows[win_no];
> + if (!win)
> + continue;
>
> + shadow_protect_win(win, 1);
> regs += (win_no * 8);
> writel(0xffffff, regs + WKEYCON0);
> writel(0xffffff, regs + WKEYCON1);
> + shadow_protect_win(win, 0);
> }
>
> /* restore framebuffers */
^ permalink raw reply
* Re: [PATCH] drivers/video: fsl-diu-fb: rename "machine_data_" to
From: Florian Tobias Schandinat @ 2011-12-19 23:14 UTC (permalink / raw)
To: linux-fbdev
In-Reply-To: <1323386851-3480-1-git-send-email-timur@freescale.com>
On 12/08/2011 11:27 PM, Timur Tabi wrote:
> "machine_data" is too long and clunky, and the "machine" part doesn't make
> much sense, anyway.
>
> Signed-off-by: Timur Tabi <timur@freescale.com>
Applied.
Thanks,
Florian Tobias Schandinat
> ---
> drivers/video/fsl-diu-fb.c | 236 ++++++++++++++++++++++----------------------
> 1 files changed, 116 insertions(+), 120 deletions(-)
>
> diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
> index 4d54188..408272c 100644
> --- a/drivers/video/fsl-diu-fb.c
> +++ b/drivers/video/fsl-diu-fb.c
> @@ -509,8 +509,8 @@ static void fsl_diu_enable_panel(struct fb_info *info)
> {
> struct mfb_info *pmfbi, *cmfbi, *mfbi = info->par;
> struct diu_ad *ad = mfbi->ad;
> - struct fsl_diu_data *machine_data = mfbi->parent;
> - struct diu __iomem *hw = machine_data->diu_reg;
> + struct fsl_diu_data *data = mfbi->parent;
> + struct diu __iomem *hw = data->diu_reg;
>
> switch (mfbi->index) {
> case PLANE0:
> @@ -518,7 +518,7 @@ static void fsl_diu_enable_panel(struct fb_info *info)
> wr_reg_wa(&hw->desc[0], ad->paddr);
> break;
> case PLANE1_AOI0:
> - cmfbi = &machine_data->mfb[2];
> + cmfbi = &data->mfb[2];
> if (hw->desc[1] != ad->paddr) { /* AOI0 closed */
> if (cmfbi->count > 0) /* AOI1 open */
> ad->next_ad > @@ -529,7 +529,7 @@ static void fsl_diu_enable_panel(struct fb_info *info)
> }
> break;
> case PLANE2_AOI0:
> - cmfbi = &machine_data->mfb[4];
> + cmfbi = &data->mfb[4];
> if (hw->desc[2] != ad->paddr) { /* AOI0 closed */
> if (cmfbi->count > 0) /* AOI1 open */
> ad->next_ad > @@ -540,17 +540,17 @@ static void fsl_diu_enable_panel(struct fb_info *info)
> }
> break;
> case PLANE1_AOI1:
> - pmfbi = &machine_data->mfb[1];
> + pmfbi = &data->mfb[1];
> ad->next_ad = 0;
> - if (hw->desc[1] = machine_data->dummy_ad.paddr)
> + if (hw->desc[1] = data->dummy_ad.paddr)
> wr_reg_wa(&hw->desc[1], ad->paddr);
> else /* AOI0 open */
> pmfbi->ad->next_ad = cpu_to_le32(ad->paddr);
> break;
> case PLANE2_AOI1:
> - pmfbi = &machine_data->mfb[3];
> + pmfbi = &data->mfb[3];
> ad->next_ad = 0;
> - if (hw->desc[2] = machine_data->dummy_ad.paddr)
> + if (hw->desc[2] = data->dummy_ad.paddr)
> wr_reg_wa(&hw->desc[2], ad->paddr);
> else /* AOI0 was open */
> pmfbi->ad->next_ad = cpu_to_le32(ad->paddr);
> @@ -562,52 +562,52 @@ static void fsl_diu_disable_panel(struct fb_info *info)
> {
> struct mfb_info *pmfbi, *cmfbi, *mfbi = info->par;
> struct diu_ad *ad = mfbi->ad;
> - struct fsl_diu_data *machine_data = mfbi->parent;
> - struct diu __iomem *hw = machine_data->diu_reg;
> + struct fsl_diu_data *data = mfbi->parent;
> + struct diu __iomem *hw = data->diu_reg;
>
> switch (mfbi->index) {
> case PLANE0:
> - if (hw->desc[0] != machine_data->dummy_ad.paddr)
> - wr_reg_wa(&hw->desc[0], machine_data->dummy_ad.paddr);
> + if (hw->desc[0] != data->dummy_ad.paddr)
> + wr_reg_wa(&hw->desc[0], data->dummy_ad.paddr);
> break;
> case PLANE1_AOI0:
> - cmfbi = &machine_data->mfb[2];
> + cmfbi = &data->mfb[2];
> if (cmfbi->count > 0) /* AOI1 is open */
> wr_reg_wa(&hw->desc[1], cmfbi->ad->paddr);
> /* move AOI1 to the first */
> else /* AOI1 was closed */
> - wr_reg_wa(&hw->desc[1], machine_data->dummy_ad.paddr);
> + wr_reg_wa(&hw->desc[1], data->dummy_ad.paddr);
> /* close AOI 0 */
> break;
> case PLANE2_AOI0:
> - cmfbi = &machine_data->mfb[4];
> + cmfbi = &data->mfb[4];
> if (cmfbi->count > 0) /* AOI1 is open */
> wr_reg_wa(&hw->desc[2], cmfbi->ad->paddr);
> /* move AOI1 to the first */
> else /* AOI1 was closed */
> - wr_reg_wa(&hw->desc[2], machine_data->dummy_ad.paddr);
> + wr_reg_wa(&hw->desc[2], data->dummy_ad.paddr);
> /* close AOI 0 */
> break;
> case PLANE1_AOI1:
> - pmfbi = &machine_data->mfb[1];
> + pmfbi = &data->mfb[1];
> if (hw->desc[1] != ad->paddr) {
> /* AOI1 is not the first in the chain */
> if (pmfbi->count > 0)
> /* AOI0 is open, must be the first */
> pmfbi->ad->next_ad = 0;
> } else /* AOI1 is the first in the chain */
> - wr_reg_wa(&hw->desc[1], machine_data->dummy_ad.paddr);
> + wr_reg_wa(&hw->desc[1], data->dummy_ad.paddr);
> /* close AOI 1 */
> break;
> case PLANE2_AOI1:
> - pmfbi = &machine_data->mfb[3];
> + pmfbi = &data->mfb[3];
> if (hw->desc[2] != ad->paddr) {
> /* AOI1 is not the first in the chain */
> if (pmfbi->count > 0)
> /* AOI0 is open, must be the first */
> pmfbi->ad->next_ad = 0;
> } else /* AOI1 is the first in the chain */
> - wr_reg_wa(&hw->desc[2], machine_data->dummy_ad.paddr);
> + wr_reg_wa(&hw->desc[2], data->dummy_ad.paddr);
> /* close AOI 1 */
> break;
> }
> @@ -616,24 +616,24 @@ static void fsl_diu_disable_panel(struct fb_info *info)
> static void enable_lcdc(struct fb_info *info)
> {
> struct mfb_info *mfbi = info->par;
> - struct fsl_diu_data *machine_data = mfbi->parent;
> - struct diu __iomem *hw = machine_data->diu_reg;
> + struct fsl_diu_data *data = mfbi->parent;
> + struct diu __iomem *hw = data->diu_reg;
>
> - if (!machine_data->fb_enabled) {
> + if (!data->fb_enabled) {
> out_be32(&hw->diu_mode, MFB_MODE1);
> - machine_data->fb_enabled++;
> + data->fb_enabled++;
> }
> }
>
> static void disable_lcdc(struct fb_info *info)
> {
> struct mfb_info *mfbi = info->par;
> - struct fsl_diu_data *machine_data = mfbi->parent;
> - struct diu __iomem *hw = machine_data->diu_reg;
> + struct fsl_diu_data *data = mfbi->parent;
> + struct diu __iomem *hw = data->diu_reg;
>
> - if (machine_data->fb_enabled) {
> + if (data->fb_enabled) {
> out_be32(&hw->diu_mode, 0);
> - machine_data->fb_enabled = 0;
> + data->fb_enabled = 0;
> }
> }
>
> @@ -641,14 +641,14 @@ static void adjust_aoi_size_position(struct fb_var_screeninfo *var,
> struct fb_info *info)
> {
> struct mfb_info *lower_aoi_mfbi, *upper_aoi_mfbi, *mfbi = info->par;
> - struct fsl_diu_data *machine_data = mfbi->parent;
> + struct fsl_diu_data *data = mfbi->parent;
> int available_height, upper_aoi_bottom;
> enum mfb_index index = mfbi->index;
> int lower_aoi_is_open, upper_aoi_is_open;
> __u32 base_plane_width, base_plane_height, upper_aoi_height;
>
> - base_plane_width = machine_data->fsl_diu_info[0].var.xres;
> - base_plane_height = machine_data->fsl_diu_info[0].var.yres;
> + base_plane_width = data->fsl_diu_info[0].var.xres;
> + base_plane_height = data->fsl_diu_info[0].var.yres;
>
> if (mfbi->x_aoi_d < 0)
> mfbi->x_aoi_d = 0;
> @@ -663,7 +663,7 @@ static void adjust_aoi_size_position(struct fb_var_screeninfo *var,
> break;
> case PLANE1_AOI0:
> case PLANE2_AOI0:
> - lower_aoi_mfbi = machine_data->fsl_diu_info[index+1].par;
> + lower_aoi_mfbi = data->fsl_diu_info[index+1].par;
> lower_aoi_is_open = lower_aoi_mfbi->count > 0 ? 1 : 0;
> if (var->xres > base_plane_width)
> var->xres = base_plane_width;
> @@ -681,9 +681,8 @@ static void adjust_aoi_size_position(struct fb_var_screeninfo *var,
> break;
> case PLANE1_AOI1:
> case PLANE2_AOI1:
> - upper_aoi_mfbi = machine_data->fsl_diu_info[index-1].par;
> - upper_aoi_height > - machine_data->fsl_diu_info[index-1].var.yres;
> + upper_aoi_mfbi = data->fsl_diu_info[index-1].par;
> + upper_aoi_height = data->fsl_diu_info[index-1].var.yres;
> upper_aoi_bottom = upper_aoi_mfbi->y_aoi_d + upper_aoi_height;
> upper_aoi_is_open = upper_aoi_mfbi->count > 0 ? 1 : 0;
> if (var->xres > base_plane_width)
> @@ -823,17 +822,17 @@ static void update_lcdc(struct fb_info *info)
> {
> struct fb_var_screeninfo *var = &info->var;
> struct mfb_info *mfbi = info->par;
> - struct fsl_diu_data *machine_data = mfbi->parent;
> + struct fsl_diu_data *data = mfbi->parent;
> struct diu __iomem *hw;
> int i, j;
> u8 *gamma_table_base;
>
> u32 temp;
>
> - hw = machine_data->diu_reg;
> + hw = data->diu_reg;
>
> - diu_ops.set_monitor_port(machine_data->monitor_port);
> - gamma_table_base = machine_data->gamma;
> + diu_ops.set_monitor_port(data->monitor_port);
> + gamma_table_base = data->gamma;
>
> /* Prep for DIU init - gamma table, cursor table */
>
> @@ -841,15 +840,14 @@ static void update_lcdc(struct fb_info *info)
> for (j = 0; j <= 255; j++)
> *gamma_table_base++ = j;
>
> - diu_ops.set_gamma_table(machine_data->monitor_port,
> - machine_data->gamma);
> + diu_ops.set_gamma_table(data->monitor_port, data->gamma);
>
> disable_lcdc(info);
>
> /* Program DIU registers */
>
> - out_be32(&hw->gamma, DMA_ADDR(machine_data, gamma));
> - out_be32(&hw->cursor, DMA_ADDR(machine_data, cursor));
> + out_be32(&hw->gamma, DMA_ADDR(data, gamma));
> + out_be32(&hw->cursor, DMA_ADDR(data, cursor));
>
> out_be32(&hw->bgnd, 0x007F7F7F); /* BGND */
> out_be32(&hw->bgnd_wb, 0); /* BGND_WB */
> @@ -940,11 +938,11 @@ static int fsl_diu_set_par(struct fb_info *info)
> unsigned long len;
> struct fb_var_screeninfo *var = &info->var;
> struct mfb_info *mfbi = info->par;
> - struct fsl_diu_data *machine_data = mfbi->parent;
> + struct fsl_diu_data *data = mfbi->parent;
> struct diu_ad *ad = mfbi->ad;
> struct diu __iomem *hw;
>
> - hw = machine_data->diu_reg;
> + hw = data->diu_reg;
>
> set_fix(info);
> mfbi->cursor_reset = 1;
> @@ -962,7 +960,7 @@ static int fsl_diu_set_par(struct fb_info *info)
> }
> }
>
> - ad->pix_fmt = diu_ops.get_pixel_format(machine_data->monitor_port,
> + ad->pix_fmt = diu_ops.get_pixel_format(data->monitor_port,
> var->bits_per_pixel);
> ad->addr = cpu_to_le32(info->fix.smem_start);
> ad->src_size_g_alpha = cpu_to_le32((var->yres_virtual << 12) |
> @@ -1373,16 +1371,16 @@ static irqreturn_t fsl_diu_isr(int irq, void *dev_id)
> return IRQ_NONE;
> }
>
> -static int request_irq_local(struct fsl_diu_data *machine_data)
> +static int request_irq_local(struct fsl_diu_data *data)
> {
> - struct diu __iomem *hw = machine_data->diu_reg;
> + struct diu __iomem *hw = data->diu_reg;
> u32 ints;
> int ret;
>
> /* Read to clear the status */
> in_be32(&hw->int_status);
>
> - ret = request_irq(machine_data->irq, fsl_diu_isr, 0, "fsl-diu-fb", hw);
> + ret = request_irq(data->irq, fsl_diu_isr, 0, "fsl-diu-fb", hw);
> if (!ret) {
> ints = INT_PARERR | INT_LS_BF_VS;
> #if !defined(CONFIG_NOT_COHERENT_CACHE)
> @@ -1397,14 +1395,14 @@ static int request_irq_local(struct fsl_diu_data *machine_data)
> return ret;
> }
>
> -static void free_irq_local(struct fsl_diu_data *machine_data)
> +static void free_irq_local(struct fsl_diu_data *data)
> {
> - struct diu __iomem *hw = machine_data->diu_reg;
> + struct diu __iomem *hw = data->diu_reg;
>
> /* Disable all LCDC interrupt */
> out_be32(&hw->int_mask, 0x1f);
>
> - free_irq(machine_data->irq, NULL);
> + free_irq(data->irq, NULL);
> }
>
> #ifdef CONFIG_PM
> @@ -1414,20 +1412,20 @@ static void free_irq_local(struct fsl_diu_data *machine_data)
> */
> static int fsl_diu_suspend(struct platform_device *ofdev, pm_message_t state)
> {
> - struct fsl_diu_data *machine_data;
> + struct fsl_diu_data *data;
>
> - machine_data = dev_get_drvdata(&ofdev->dev);
> - disable_lcdc(machine_data->fsl_diu_info[0]);
> + data = dev_get_drvdata(&ofdev->dev);
> + disable_lcdc(data->fsl_diu_info[0]);
>
> return 0;
> }
>
> static int fsl_diu_resume(struct platform_device *ofdev)
> {
> - struct fsl_diu_data *machine_data;
> + struct fsl_diu_data *data;
>
> - machine_data = dev_get_drvdata(&ofdev->dev);
> - enable_lcdc(machine_data->fsl_diu_info[0]);
> + data = dev_get_drvdata(&ofdev->dev);
> + enable_lcdc(data->fsl_diu_info[0]);
>
> return 0;
> }
> @@ -1441,20 +1439,20 @@ static ssize_t store_monitor(struct device *device,
> struct device_attribute *attr, const char *buf, size_t count)
> {
> enum fsl_diu_monitor_port old_monitor_port;
> - struct fsl_diu_data *machine_data > + struct fsl_diu_data *data > container_of(attr, struct fsl_diu_data, dev_attr);
>
> - old_monitor_port = machine_data->monitor_port;
> - machine_data->monitor_port = fsl_diu_name_to_port(buf);
> + old_monitor_port = data->monitor_port;
> + data->monitor_port = fsl_diu_name_to_port(buf);
>
> - if (old_monitor_port != machine_data->monitor_port) {
> + if (old_monitor_port != data->monitor_port) {
> /* All AOIs need adjust pixel format
> * fsl_diu_set_par only change the pixsel format here
> * unlikely to fail. */
> unsigned int i;
>
> for (i=0; i < NUM_AOIS; i++)
> - fsl_diu_set_par(&machine_data->fsl_diu_info[i]);
> + fsl_diu_set_par(&data->fsl_diu_info[i]);
> }
> return count;
> }
> @@ -1462,10 +1460,10 @@ static ssize_t store_monitor(struct device *device,
> static ssize_t show_monitor(struct device *device,
> struct device_attribute *attr, char *buf)
> {
> - struct fsl_diu_data *machine_data > + struct fsl_diu_data *data > container_of(attr, struct fsl_diu_data, dev_attr);
>
> - switch (machine_data->monitor_port) {
> + switch (data->monitor_port) {
> case FSL_DIU_PORT_DVI:
> return sprintf(buf, "DVI\n");
> case FSL_DIU_PORT_LVDS:
> @@ -1481,17 +1479,17 @@ static int __devinit fsl_diu_probe(struct platform_device *pdev)
> {
> struct device_node *np = pdev->dev.of_node;
> struct mfb_info *mfbi;
> - struct fsl_diu_data *machine_data;
> + struct fsl_diu_data *data;
> int diu_mode;
> - dma_addr_t dma_addr; /* DMA addr of machine_data struct */
> + dma_addr_t dma_addr; /* DMA addr of fsl_diu_data struct */
> unsigned int i;
> int ret;
>
> - machine_data = dma_alloc_coherent(&pdev->dev,
> - sizeof(struct fsl_diu_data), &dma_addr, GFP_DMA | __GFP_ZERO);
> - if (!machine_data)
> + data = dma_alloc_coherent(&pdev->dev, sizeof(struct fsl_diu_data),
> + &dma_addr, GFP_DMA | __GFP_ZERO);
> + if (!data)
> return -ENOMEM;
> - machine_data->dma_addr = dma_addr;
> + data->dma_addr = dma_addr;
>
> /*
> * dma_alloc_coherent() uses a page allocator, so the address is
> @@ -1500,33 +1498,33 @@ static int __devinit fsl_diu_probe(struct platform_device *pdev)
> * need to catch that. It's not worth the effort to handle unaligned
> * alloctions now because it's highly unlikely to ever be a problem.
> */
> - if ((unsigned long)machine_data & 31) {
> + if ((unsigned long)data & 31) {
> dev_err(&pdev->dev, "misaligned allocation");
> ret = -ENOMEM;
> goto error;
> }
>
> - spin_lock_init(&machine_data->reg_lock);
> + spin_lock_init(&data->reg_lock);
>
> for (i = 0; i < NUM_AOIS; i++) {
> - struct fb_info *info = &machine_data->fsl_diu_info[i];
> + struct fb_info *info = &data->fsl_diu_info[i];
>
> info->device = &pdev->dev;
> - info->par = &machine_data->mfb[i];
> + info->par = &data->mfb[i];
>
> /*
> * We store the physical address of the AD in the reserved
> * 'paddr' field of the AD itself.
> */
> - machine_data->ad[i].paddr = DMA_ADDR(machine_data, ad[i]);
> + data->ad[i].paddr = DMA_ADDR(data, ad[i]);
>
> info->fix.smem_start = 0;
>
> /* Initialize the AOI data structure */
> mfbi = info->par;
> memcpy(mfbi, &mfb_template[i], sizeof(struct mfb_info));
> - mfbi->parent = machine_data;
> - mfbi->ad = &machine_data->ad[i];
> + mfbi->parent = data;
> + mfbi->ad = &data->ad[i];
>
> if (mfbi->index = PLANE0) {
> const u8 *prop;
> @@ -1540,104 +1538,102 @@ static int __devinit fsl_diu_probe(struct platform_device *pdev)
> }
> }
>
> - machine_data->diu_reg = of_iomap(np, 0);
> - if (!machine_data->diu_reg) {
> + data->diu_reg = of_iomap(np, 0);
> + if (!data->diu_reg) {
> dev_err(&pdev->dev, "cannot map DIU registers\n");
> ret = -EFAULT;
> goto error;
> }
>
> - diu_mode = in_be32(&machine_data->diu_reg->diu_mode);
> + diu_mode = in_be32(&data->diu_reg->diu_mode);
> if (diu_mode = MFB_MODE0)
> - out_be32(&machine_data->diu_reg->diu_mode, 0); /* disable DIU */
> + out_be32(&data->diu_reg->diu_mode, 0); /* disable DIU */
>
> /* Get the IRQ of the DIU */
> - machine_data->irq = irq_of_parse_and_map(np, 0);
> + data->irq = irq_of_parse_and_map(np, 0);
>
> - if (!machine_data->irq) {
> + if (!data->irq) {
> dev_err(&pdev->dev, "could not get DIU IRQ\n");
> ret = -EINVAL;
> goto error;
> }
> - machine_data->monitor_port = monitor_port;
> + data->monitor_port = monitor_port;
>
> /* Initialize the dummy Area Descriptor */
> - machine_data->dummy_ad.addr > - cpu_to_le32(DMA_ADDR(machine_data, dummy_aoi));
> - machine_data->dummy_ad.pix_fmt = 0x88882317;
> - machine_data->dummy_ad.src_size_g_alpha = cpu_to_le32((4 << 12) | 4);
> - machine_data->dummy_ad.aoi_size = cpu_to_le32((4 << 16) | 2);
> - machine_data->dummy_ad.offset_xyi = 0;
> - machine_data->dummy_ad.offset_xyd = 0;
> - machine_data->dummy_ad.next_ad = 0;
> - machine_data->dummy_ad.paddr = DMA_ADDR(machine_data, dummy_ad);
> + data->dummy_ad.addr = cpu_to_le32(DMA_ADDR(data, dummy_aoi));
> + data->dummy_ad.pix_fmt = 0x88882317;
> + data->dummy_ad.src_size_g_alpha = cpu_to_le32((4 << 12) | 4);
> + data->dummy_ad.aoi_size = cpu_to_le32((4 << 16) | 2);
> + data->dummy_ad.offset_xyi = 0;
> + data->dummy_ad.offset_xyd = 0;
> + data->dummy_ad.next_ad = 0;
> + data->dummy_ad.paddr = DMA_ADDR(data, dummy_ad);
>
> /*
> * Let DIU display splash screen if it was pre-initialized
> * by the bootloader, set dummy area descriptor otherwise.
> */
> if (diu_mode = MFB_MODE0)
> - out_be32(&machine_data->diu_reg->desc[0],
> - machine_data->dummy_ad.paddr);
> + out_be32(&data->diu_reg->desc[0], data->dummy_ad.paddr);
>
> - out_be32(&machine_data->diu_reg->desc[1], machine_data->dummy_ad.paddr);
> - out_be32(&machine_data->diu_reg->desc[2], machine_data->dummy_ad.paddr);
> + out_be32(&data->diu_reg->desc[1], data->dummy_ad.paddr);
> + out_be32(&data->diu_reg->desc[2], data->dummy_ad.paddr);
>
> for (i = 0; i < NUM_AOIS; i++) {
> - ret = install_fb(&machine_data->fsl_diu_info[i]);
> + ret = install_fb(&data->fsl_diu_info[i]);
> if (ret) {
> dev_err(&pdev->dev, "could not register fb %d\n", i);
> goto error;
> }
> }
>
> - if (request_irq_local(machine_data)) {
> + if (request_irq_local(data)) {
> dev_err(&pdev->dev, "could not claim irq\n");
> goto error;
> }
>
> - sysfs_attr_init(&machine_data->dev_attr.attr);
> - machine_data->dev_attr.attr.name = "monitor";
> - machine_data->dev_attr.attr.mode = S_IRUGO|S_IWUSR;
> - machine_data->dev_attr.show = show_monitor;
> - machine_data->dev_attr.store = store_monitor;
> - ret = device_create_file(&pdev->dev, &machine_data->dev_attr);
> + sysfs_attr_init(&data->dev_attr.attr);
> + data->dev_attr.attr.name = "monitor";
> + data->dev_attr.attr.mode = S_IRUGO|S_IWUSR;
> + data->dev_attr.show = show_monitor;
> + data->dev_attr.store = store_monitor;
> + ret = device_create_file(&pdev->dev, &data->dev_attr);
> if (ret) {
> dev_err(&pdev->dev, "could not create sysfs file %s\n",
> - machine_data->dev_attr.attr.name);
> + data->dev_attr.attr.name);
> }
>
> - dev_set_drvdata(&pdev->dev, machine_data);
> + dev_set_drvdata(&pdev->dev, data);
> return 0;
>
> error:
> for (i = 0; i < NUM_AOIS; i++)
> - uninstall_fb(&machine_data->fsl_diu_info[i]);
> + uninstall_fb(&data->fsl_diu_info[i]);
>
> - iounmap(machine_data->diu_reg);
> + iounmap(data->diu_reg);
>
> - dma_free_coherent(&pdev->dev, sizeof(struct fsl_diu_data),
> - machine_data, machine_data->dma_addr);
> + dma_free_coherent(&pdev->dev, sizeof(struct fsl_diu_data), data,
> + data->dma_addr);
>
> return ret;
> }
>
> static int fsl_diu_remove(struct platform_device *pdev)
> {
> - struct fsl_diu_data *machine_data;
> + struct fsl_diu_data *data;
> int i;
>
> - machine_data = dev_get_drvdata(&pdev->dev);
> - disable_lcdc(&machine_data->fsl_diu_info[0]);
> - free_irq_local(machine_data);
> + data = dev_get_drvdata(&pdev->dev);
> + disable_lcdc(&data->fsl_diu_info[0]);
> + free_irq_local(data);
>
> for (i = 0; i < NUM_AOIS; i++)
> - uninstall_fb(&machine_data->fsl_diu_info[i]);
> + uninstall_fb(&data->fsl_diu_info[i]);
>
> - iounmap(machine_data->diu_reg);
> + iounmap(data->diu_reg);
>
> - dma_free_coherent(&pdev->dev, sizeof(struct fsl_diu_data),
> - machine_data, machine_data->dma_addr);
> + dma_free_coherent(&pdev->dev, sizeof(struct fsl_diu_data), data,
> + data->dma_addr);
>
> return 0;
> }
^ permalink raw reply
* Re: [PATCH 1/3] video: convert mbxfb to use module_platform_driver()
From: Florian Tobias Schandinat @ 2011-12-19 23:14 UTC (permalink / raw)
To: Axel Lin; +Cc: linux-kernel, Mike Rapoport, linux-fbdev
In-Reply-To: <1323395873.3740.4.camel@phoenix>
On 12/09/2011 01:57 AM, Axel Lin wrote:
> This patch converts mbxfb to use the module_platform_driver() macro
> which makes the code smaller and a bit simpler.
>
> Cc: Mike Rapoport <mike@compulab.co.il>
> Signed-off-by: Axel Lin <axel.lin@gmail.com>
Applied.
Thanks,
Florian Tobias Schandinat
> ---
> drivers/video/mbx/mbxfb.c | 13 +------------
> 1 files changed, 1 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/video/mbx/mbxfb.c b/drivers/video/mbx/mbxfb.c
> index 6ce3416..55bf619 100644
> --- a/drivers/video/mbx/mbxfb.c
> +++ b/drivers/video/mbx/mbxfb.c
> @@ -1053,18 +1053,7 @@ static struct platform_driver mbxfb_driver = {
> },
> };
>
> -int __devinit mbxfb_init(void)
> -{
> - return platform_driver_register(&mbxfb_driver);
> -}
> -
> -static void __devexit mbxfb_exit(void)
> -{
> - platform_driver_unregister(&mbxfb_driver);
> -}
> -
> -module_init(mbxfb_init);
> -module_exit(mbxfb_exit);
> +module_platform_driver(mbxfb_driver);
>
> MODULE_DESCRIPTION("loadable framebuffer driver for Marathon device");
> MODULE_AUTHOR("Mike Rapoport, Compulab");
^ permalink raw reply
* Re: [PATCH 3/3] video: pnx4008: convert drivers/video/pnx4008/* to
From: Florian Tobias Schandinat @ 2011-12-19 23:15 UTC (permalink / raw)
To: Axel Lin; +Cc: linux-kernel, Grigory Tolstolytkin, linux-fbdev
In-Reply-To: <1323396075.3740.8.camel@phoenix>
On 12/09/2011 02:01 AM, Axel Lin wrote:
> This patch converts the drivers in drivers/video/pnx4008/* to use the
> module_platform_driver() macro which makes the code smaller and a bit
> simpler.
>
> Cc: Grigory Tolstolytkin <gtolstolytkin@ru.mvista.com>
> Signed-off-by: Axel Lin <axel.lin@gmail.com>
Applied.
Thanks,
Florian Tobias Schandinat
> ---
> drivers/video/pnx4008/pnxrgbfb.c | 13 +------------
> drivers/video/pnx4008/sdum.c | 13 +------------
> 2 files changed, 2 insertions(+), 24 deletions(-)
>
> diff --git a/drivers/video/pnx4008/pnxrgbfb.c b/drivers/video/pnx4008/pnxrgbfb.c
> index b2252fe..6d30428 100644
> --- a/drivers/video/pnx4008/pnxrgbfb.c
> +++ b/drivers/video/pnx4008/pnxrgbfb.c
> @@ -193,17 +193,6 @@ static struct platform_driver rgbfb_driver = {
> .remove = rgbfb_remove,
> };
>
> -static int __init rgbfb_init(void)
> -{
> - return platform_driver_register(&rgbfb_driver);
> -}
> -
> -static void __exit rgbfb_exit(void)
> -{
> - platform_driver_unregister(&rgbfb_driver);
> -}
> -
> -module_init(rgbfb_init);
> -module_exit(rgbfb_exit);
> +module_platform_driver(rgbfb_driver);
>
> MODULE_LICENSE("GPL");
> diff --git a/drivers/video/pnx4008/sdum.c b/drivers/video/pnx4008/sdum.c
> index 50e0039..c5c7414 100644
> --- a/drivers/video/pnx4008/sdum.c
> +++ b/drivers/video/pnx4008/sdum.c
> @@ -856,17 +856,6 @@ static struct platform_driver sdum_driver = {
> .resume = sdum_resume,
> };
>
> -int __init sdum_init(void)
> -{
> - return platform_driver_register(&sdum_driver);
> -}
> -
> -static void __exit sdum_exit(void)
> -{
> - platform_driver_unregister(&sdum_driver);
> -};
> -
> -module_init(sdum_init);
> -module_exit(sdum_exit);
> +module_platform_driver(sdum_driver);
>
> MODULE_LICENSE("GPL");
^ permalink raw reply
* Re: [PATCH 3/15] i810: fix module_param bool abuse.
From: Florian Tobias Schandinat @ 2011-12-19 23:16 UTC (permalink / raw)
To: Rusty Russell
Cc: lkml - Kernel Mailing List, Antonino Daplas, linux-fbdev,
Pawel Moll
In-Reply-To: <874nx2tu1v.fsf@rustcorp.com.au>
On 12/15/2011 03:03 AM, Rusty Russell wrote:
> The driver says "module_param(ddc3, bool, 0);". But it's not a used
> as a bool, it's used as a count.
>
> Make it a bool.
>
> Cc: Antonino Daplas <adaplas@gmail.com>
> Cc: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
> Cc: linux-fbdev@vger.kernel.org
> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Applied.
Thanks,
Florian Tobias Schandinat
> ---
> drivers/video/i810/i810_main.c | 6 +++---
> 1 file changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/video/i810/i810_main.c b/drivers/video/i810/i810_main.c
> --- a/drivers/video/i810/i810_main.c
> +++ b/drivers/video/i810/i810_main.c
> @@ -147,7 +147,7 @@ static int vyres __devinitdata;
> static int sync __devinitdata;
> static int extvga __devinitdata;
> static int dcolor __devinitdata;
> -static int ddc3 __devinitdata = 2;
> +static bool ddc3 __devinitdata;
>
> /*------------------------------------------------------------*/
>
> @@ -1776,7 +1776,7 @@ static void __devinit i810_init_defaults
> if (sync)
> par->dev_flags |= ALWAYS_SYNC;
>
> - par->ddc_num = ddc3;
> + par->ddc_num = (ddc3 ? 3 : 2);
>
> if (bpp < 8)
> bpp = 8;
> @@ -1999,7 +1999,7 @@ static int __devinit i810fb_setup(char *
> else if (!strncmp(this_opt, "dcolor", 6))
> dcolor = 1;
> else if (!strncmp(this_opt, "ddc3", 4))
> - ddc3 = 3;
> + ddc3 = true;
> else
> mode_option = this_opt;
> }
>
^ permalink raw reply
* Re: [PATCH v5 0/3] fbdev: Add FOURCC-based format configuration API
From: Florian Tobias Schandinat @ 2011-12-19 23:20 UTC (permalink / raw)
To: Laurent Pinchart; +Cc: linux-fbdev, linux-media
In-Reply-To: <1323781348-9884-1-git-send-email-laurent.pinchart@ideasonboard.com>
Hi Laurent,
On 12/13/2011 01:02 PM, Laurent Pinchart wrote:
> Hi everybody,
> fbdev: Add FOURCC-based format configuration API
> Here's the fifth version of the fbdev FOURCC-based format configuration API.
Applied this series.
Thanks and congratulations,
Florian Tobias Schandinat
>
> Compared to the fourth version,
>
> - fb_set_var() now checks that the red, green, blue and transp fields are all
> set to 0 when using the FOURCC-based API and return an error if they are not
>
> - the NV24 and NV42 format documentation doesn't include emacs formatting
> directives anymore.
>
> As usual the fbdev-test tool supporting this new API is available in the
> fbdev-test yuv branch at
> http://git.ideasonboard.org/?pûdev-test.git;a=shortlog;h=refs/heads/yuv.
>
> Laurent Pinchart (3):
> fbdev: Add FOURCC-based format configuration API
> v4l: Add V4L2_PIX_FMT_NV24 and V4L2_PIX_FMT_NV42 formats
> fbdev: sh_mobile_lcdc: Support FOURCC-based format API
>
> Documentation/DocBook/media/v4l/pixfmt-nv24.xml | 121 ++++++++
> Documentation/DocBook/media/v4l/pixfmt.xml | 1 +
> Documentation/fb/api.txt | 306 +++++++++++++++++++
> arch/arm/mach-shmobile/board-ag5evm.c | 2 +-
> arch/arm/mach-shmobile/board-ap4evb.c | 4 +-
> arch/arm/mach-shmobile/board-mackerel.c | 4 +-
> arch/sh/boards/mach-ap325rxa/setup.c | 2 +-
> arch/sh/boards/mach-ecovec24/setup.c | 2 +-
> arch/sh/boards/mach-kfr2r09/setup.c | 2 +-
> arch/sh/boards/mach-migor/setup.c | 4 +-
> arch/sh/boards/mach-se/7724/setup.c | 2 +-
> drivers/video/fbmem.c | 14 +
> drivers/video/sh_mobile_lcdcfb.c | 360 +++++++++++++++--------
> include/linux/fb.h | 14 +-
> include/linux/videodev2.h | 2 +
> include/video/sh_mobile_lcdc.h | 4 +-
> 16 files changed, 707 insertions(+), 137 deletions(-)
> create mode 100644 Documentation/DocBook/media/v4l/pixfmt-nv24.xml
> create mode 100644 Documentation/fb/api.txt
>
^ permalink raw reply
* [PATCH v3] video: support MIPI-DSI controller driver
From: Donghwa Lee @ 2011-12-20 3:47 UTC (permalink / raw)
To: linux-arm-kernel
Samsung S5PC210 and EXYNOS SoC platform has MIPI-DSI controller and MIPI-DSI
based LCD Panel could be used with it. This patch supports MIPI-DSI driver
based Samsung SoC chip.
LCD panel driver based MIPI-DSI should be registered to MIPI-DSI driver at
machine code and LCD panel driver specific function registered to mipi_dsim_ddi
structure at lcd panel init function called system init.
In the MIPI-DSI driver, find lcd panel driver by using registered
lcd panel name, and then initialize lcd panel driver.
Changes since v2:
- support regulators control in the driver.
- avoid type casting and use array to read easily in data write
function.
- etc.
Signed-off-by: Donghwa Lee <dh09.lee@samsung.com>
Signed-off-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
drivers/video/Kconfig | 7 +
drivers/video/Makefile | 2 +
drivers/video/s5p_mipi_dsi.c | 619 ++++++++++++++++++++++
drivers/video/s5p_mipi_dsi_common.c | 902 +++++++++++++++++++++++++++++++++
drivers/video/s5p_mipi_dsi_common.h | 46 ++
drivers/video/s5p_mipi_dsi_lowlevel.c | 627 +++++++++++++++++++++++
drivers/video/s5p_mipi_dsi_lowlevel.h | 112 ++++
drivers/video/s5p_mipi_dsi_regs.h | 156 ++++++
include/linux/mipi_dsim.h | 361 +++++++++++++
9 files changed, 2832 insertions(+), 0 deletions(-)
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
create mode 100644 drivers/video/s5p_mipi_dsi_regs.h
create mode 100644 include/linux/mipi_dsim.h
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index d83e967..879177b 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -2082,6 +2082,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_S5PV310 || ARCH_EXYNOS)
+ 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 9b9d8ff..29eb7c9 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -120,6 +120,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..f6c22cd
--- /dev/null
+++ b/drivers/video/s5p_mipi_dsi.c
@@ -0,0 +1,619 @@
+/* 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>
+ * Donghwa Lee, <dh09.lee@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 <linux/mipi_dsim.h>
+#include <linux/regulator/consumer.h>
+#include <linux/pm_runtime.h>
+
+#include <plat/fb.h>
+
+#include "s5p_mipi_dsi_common.h"
+#include "s5p_mipi_dsi_lowlevel.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 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 struct regulator_bulk_data supplies[] = {
+ { .supply = "vdd10", },
+ { .supply = "vdd18", },
+};
+
+static int s5p_mipi_regulator_enable(struct mipi_dsim_device *dsim)
+{
+ int ret = 0;
+
+ mutex_lock(&dsim->lock);
+ ret = regulator_bulk_enable(ARRAY_SIZE(supplies), supplies);
+ if (ret)
+ goto out;
+
+out:
+ mutex_unlock(&dsim->lock);
+ return ret;
+}
+
+static int s5p_mipi_regulator_disable(struct mipi_dsim_device *dsim)
+{
+ int ret = 0;
+
+ mutex_lock(&dsim->lock);
+ ret = regulator_bulk_disable(ARRAY_SIZE(supplies), supplies);
+ if (ret)
+ goto out;
+
+out:
+ mutex_unlock(&dsim->lock);
+ return ret;
+}
+
+/* update all register settings to MIPI DSI controller. */
+static void s5p_mipi_update_cfg(struct mipi_dsim_device *dsim)
+{
+ /*
+ * data from Display controller(FIMD) is not transferred in video mode
+ * but in case of command mode, all settings is not updated to
+ * registers.
+ */
+ s5p_mipi_dsi_stand_by(dsim, 0);
+
+ 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);
+
+ /*
+ * data from Display controller(FIMD) is transferred in video mode
+ * but in case of command mode, all settigs is updated to registers.
+ */
+ s5p_mipi_dsi_stand_by(dsim, 1);
+}
+
+static int s5p_mipi_dsi_early_blank_mode(struct mipi_dsim_device *dsim,
+ int power)
+{
+ struct mipi_dsim_lcd_driver *client_drv = master_to_driver(dsim);
+ struct mipi_dsim_lcd_device *client_dev = master_to_device(dsim);
+
+ switch (power) {
+ case FB_BLANK_POWERDOWN:
+ if (dsim->suspended)
+ return 0;
+
+ if (client_drv && client_drv->suspend)
+ client_drv->suspend(client_dev);
+
+ clk_disable(dsim->clock);
+
+ s5p_mipi_regulator_disable(dsim);
+
+ dsim->suspended = true;
+
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int s5p_mipi_dsi_blank_mode(struct mipi_dsim_device *dsim, int power)
+{
+ struct platform_device *pdev = to_platform_device(dsim->dev);
+ struct mipi_dsim_lcd_driver *client_drv = master_to_driver(dsim);
+ struct mipi_dsim_lcd_device *client_dev = master_to_device(dsim);
+
+ switch (power) {
+ case FB_BLANK_UNBLANK:
+ if (!dsim->suspended)
+ return 0;
+
+ /* lcd panel power on. */
+ if (client_drv && client_drv->power_on)
+ client_drv->power_on(client_dev, 1);
+
+ s5p_mipi_regulator_disable(dsim);
+
+ /* enable MIPI-DSI PHY. */
+ if (dsim->pd->phy_enable)
+ dsim->pd->phy_enable(pdev, true);
+
+ clk_enable(dsim->clock);
+
+ s5p_mipi_update_cfg(dsim);
+
+ /* set lcd panel sequence commands. */
+ if (client_drv && client_drv->set_sequence)
+ client_drv->set_sequence(client_dev);
+
+ dsim->suspended = false;
+
+ break;
+ case FB_BLANK_NORMAL:
+ /* TODO. */
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+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, *next;
+ struct mipi_dsim_lcd_device *lcd_dev;
+
+ mutex_lock(&mipi_dsim_lock);
+
+ list_for_each_entry_safe(dsim_ddi, next, &dsim_ddi_list, list) {
+ if (!dsim_ddi)
+ goto out;
+
+ lcd_dev = dsim_ddi->dsim_lcd_dev;
+ if (!lcd_dev)
+ continue;
+
+ 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;
+ }
+
+ list_del(&dsim_ddi->list);
+ kfree(dsim_ddi);
+ }
+
+out:
+ 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, *next;
+ struct mipi_dsim_lcd_driver *lcd_drv;
+ struct mipi_dsim_lcd_device *lcd_dev;
+ int ret;
+
+ mutex_lock(&dsim->lock);
+
+ list_for_each_entry_safe(dsim_ddi, next, &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_read = s5p_mipi_dsi_rd_data,
+ .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,
+ .set_early_blank_mode = s5p_mipi_dsi_early_blank_mode,
+ .set_blank_mode = s5p_mipi_dsi_blank_mode,
+};
+
+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 mipi_dsim_platform_data *dsim_pd;
+ struct mipi_dsim_ddi *dsim_ddi;
+ int ret = -EINVAL;
+
+ 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;
+
+ /* get mipi_dsim_platform_data. */
+ dsim_pd = (struct mipi_dsim_platform_data *)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;
+
+ mutex_init(&dsim->lock);
+
+ ret = regulator_bulk_get(&pdev->dev, ARRAY_SIZE(supplies), supplies);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to get regulators: %d\n", ret);
+ goto out_free_reg;
+ }
+
+ dsim->clock = clk_get(&pdev->dev, "dsim0");
+ 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");
+ goto err_platform_get;
+ }
+
+ dsim->res = request_mem_region(res->start, resource_size(res),
+ dev_name(&pdev->dev));
+ if (!dsim->res) {
+ dev_err(&pdev->dev, "failed to request io memory region\n");
+ ret = -ENOMEM;
+ goto err_mem_region;
+ }
+
+ dsim->reg_base = ioremap(res->start, resource_size(res));
+ if (!dsim->reg_base) {
+ dev_err(&pdev->dev, "failed to remap io region\n");
+ ret = -EFAULT;
+ goto err_ioremap;
+ }
+
+ mutex_init(&dsim->lock);
+
+ /* 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;
+ }
+
+ dsim->irq = platform_get_irq(pdev, 0);
+ if (dsim->irq < 0) {
+ dev_err(&pdev->dev, "failed to request dsim irq resource\n");
+ ret = -EINVAL;
+ goto err_platform_get_irq;
+ }
+
+ ret = request_irq(dsim->irq, s5p_mipi_dsi_interrupt_handler,
+ IRQF_SHARED, pdev->name, dsim);
+ if (ret != 0) {
+ dev_err(&pdev->dev, "failed to request dsim irq\n");
+ ret = -EINVAL;
+ goto err_bind;
+ }
+
+ init_completion(&dsim_wr_comp);
+ init_completion(&dsim_rd_comp);
+
+ /* enable interrupt */
+ s5p_mipi_dsi_init_interrupt(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);
+
+ /* in case that mipi got enabled at bootloader. */
+ if (dsim_pd->enabled)
+ goto out;
+
+ /* lcd panel power on. */
+ if (dsim_ddi->dsim_lcd_drv && dsim_ddi->dsim_lcd_drv->power_on)
+ dsim_ddi->dsim_lcd_drv->power_on(dsim_ddi->dsim_lcd_dev, 1);
+
+ s5p_mipi_regulator_enable(dsim);
+
+ /* enable MIPI-DSI PHY. */
+ if (dsim->pd->phy_enable)
+ dsim->pd->phy_enable(pdev, true);
+
+ s5p_mipi_update_cfg(dsim);
+
+ /* set lcd panel sequence commands. */
+ if (dsim_ddi->dsim_lcd_drv && dsim_ddi->dsim_lcd_drv->set_sequence)
+ dsim_ddi->dsim_lcd_drv->set_sequence(dsim_ddi->dsim_lcd_dev);
+
+ dsim->suspended = false;
+
+out:
+ platform_set_drvdata(pdev, dsim);
+
+ 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:
+ iounmap((void __iomem *) dsim->reg_base);
+
+err_ioremap:
+ release_mem_region(dsim->res->start, resource_size(dsim->res));
+
+err_mem_region:
+ release_resource(dsim->res);
+
+err_platform_get:
+ clk_disable(dsim->clock);
+ clk_put(dsim->clock);
+out_free_reg:
+ regulator_bulk_free(ARRAY_SIZE(supplies), supplies);
+err_clock_get:
+ kfree(dsim);
+
+err_platform_get_irq:
+ 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, *next;
+ struct mipi_dsim_lcd_driver *dsim_lcd_drv;
+
+ iounmap(dsim->reg_base);
+
+ clk_disable(dsim->clock);
+ clk_put(dsim->clock);
+
+ release_resource(dsim->res);
+ release_mem_region(dsim->res->start, resource_size(dsim->res));
+
+ list_for_each_entry_safe(dsim_ddi, next, &dsim_ddi_list, list) {
+ if (dsim_ddi) {
+ if (dsim->id != dsim_ddi->bus_id)
+ continue;
+
+ dsim_lcd_drv = dsim_ddi->dsim_lcd_drv;
+
+ if (dsim_lcd_drv->remove)
+ dsim_lcd_drv->remove(dsim_ddi->dsim_lcd_dev);
+
+ kfree(dsim_ddi);
+ }
+ }
+
+ regulator_bulk_free(ARRAY_SIZE(supplies), supplies);
+ 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);
+
+ disable_irq(dsim->irq);
+
+ if (dsim->suspended)
+ return 0;
+
+ if (master_to_driver(dsim) && (master_to_driver(dsim))->suspend)
+ (master_to_driver(dsim))->suspend(master_to_device(dsim));
+
+ /* enable MIPI-DSI PHY. */
+ if (dsim->pd->phy_enable)
+ dsim->pd->phy_enable(pdev, false);
+
+ clk_disable(dsim->clock);
+
+ s5p_mipi_regulator_disable(dsim);
+
+ dsim->suspended = true;
+
+ return 0;
+}
+
+static int s5p_mipi_dsi_resume(struct platform_device *pdev)
+{
+ struct mipi_dsim_device *dsim = platform_get_drvdata(pdev);
+ struct mipi_dsim_lcd_driver *client_drv = master_to_driver(dsim);
+ struct mipi_dsim_lcd_device *client_dev = master_to_device(dsim);
+
+ enable_irq(dsim->irq);
+
+ if (!dsim->suspended)
+ return 0;
+
+ /* lcd panel power on. */
+ if (client_drv && client_drv->power_on)
+ client_drv->power_on(client_dev, 1);
+
+ s5p_mipi_regulator_enable(dsim);
+
+ /* enable MIPI-DSI PHY. */
+ if (dsim->pd->phy_enable)
+ dsim->pd->phy_enable(pdev, true);
+
+ clk_enable(dsim->clock);
+
+ s5p_mipi_update_cfg(dsim);
+
+ /* set lcd panel sequence commands. */
+ if (client_drv && client_drv->set_sequence)
+ client_drv->set_sequence(client_dev);
+
+ dsim->suspended = false;
+
+ 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,
+ },
+};
+
+module_platform_driver(s5p_mipi_dsi_driver);
+
+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..46fe2a7
--- /dev/null
+++ b/drivers/video/s5p_mipi_dsi_common.c
@@ -0,0 +1,902 @@
+/* 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>
+ * Donghwa Lee, <dh09.lee@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 <linux/mipi_dsim.h>
+
+#include <video/mipi_display.h>
+
+#include <mach/map.h>
+
+#include "s5p_mipi_dsi_regs.h"
+#include "s5p_mipi_dsi_lowlevel.h"
+#include "s5p_mipi_dsi_common.h"
+
+#define MIPI_FIFO_TIMEOUT msecs_to_jiffies(250)
+#define MIPI_RX_FIFO_READ_DONE 0x30800002
+#define MIPI_MAX_RX_FIFO 20
+#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 TRY_FIFO_CLEAR (10)
+
+/* 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
+};
+
+irqreturn_t s5p_mipi_dsi_interrupt_handler(int irq, void *dev_id)
+{
+ unsigned int intsrc = 0;
+ unsigned int intmsk = 0;
+ struct mipi_dsim_device *dsim = NULL;
+
+ dsim = (struct mipi_dsim_device *)dev_id;
+ if (!dsim) {
+ dev_dbg(dsim->dev, KERN_ERR "%s:error: wrong parameter\n",
+ __func__);
+ return IRQ_HANDLED;
+ }
+
+ intsrc = s5p_mipi_dsi_read_interrupt(dsim);
+ intmsk = s5p_mipi_dsi_read_interrupt_mask(dsim);
+
+ intmsk = ~(intmsk) & intsrc;
+
+ switch (intmsk) {
+ case INTMSK_RX_DONE:
+ complete(&dsim_rd_comp);
+ dev_dbg(dsim->dev, "MIPI INTMSK_RX_DONE\n");
+ break;
+ case INTMSK_FIFO_EMPTY:
+ complete(&dsim_wr_comp);
+ dev_dbg(dsim->dev, "MIPI INTMSK_FIFO_EMPTY\n");
+ break;
+ default:
+ break;
+ }
+
+ s5p_mipi_dsi_clear_interrupt(dsim, intmsk);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * write long packet to mipi dsi slave
+ * @dsim: mipi dsim device structure.
+ * @data0: packet data to send.
+ * @data1: size of packet data
+ */
+static void s5p_mipi_dsi_long_data_wr(struct mipi_dsim_device *dsim,
+ unsigned char *data0, unsigned int data_size)
+{
+ unsigned int data_cnt = 0, payload = 0;
+
+ /* in case that data count is more then 4 */
+ for (data_cnt = 0; data_cnt < data_size; data_cnt += 4) {
+ /*
+ * after sending 4bytes per one time,
+ * send remainder data less then 4.
+ */
+ if ((data_size - data_cnt) < 4) {
+ if ((data_size - data_cnt) = 3) {
+ payload = data0[data_cnt] |
+ data0[data_cnt + 1] << 8 |
+ data0[data_cnt + 2] << 16;
+ dev_dbg(dsim->dev, "count = 3 payload = %x, %x %x %x\n",
+ payload, data0[data_cnt],
+ data0[data_cnt + 1],
+ data0[data_cnt + 2]);
+ } else if ((data_size - data_cnt) = 2) {
+ payload = data0[data_cnt] |
+ data0[data_cnt + 1] << 8;
+ dev_dbg(dsim->dev,
+ "count = 2 payload = %x, %x %x\n", payload,
+ data0[data_cnt],
+ data0[data_cnt + 1]);
+ } else if ((data_size - data_cnt) = 1) {
+ payload = data0[data_cnt];
+ }
+
+ s5p_mipi_dsi_wr_tx_data(dsim, payload);
+ /* send 4bytes per one time. */
+ } else {
+ payload = data0[data_cnt] |
+ data0[data_cnt + 1] << 8 |
+ data0[data_cnt + 2] << 16 |
+ data0[data_cnt + 3] << 24;
+
+ dev_dbg(dsim->dev,
+ "count = 4 payload = %x, %x %x %x %x\n",
+ payload, *(u8 *)(data0 + data_cnt),
+ data0[data_cnt + 1],
+ data0[data_cnt + 2],
+ 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 char *data0, unsigned int data_size)
+{
+ unsigned int check_rx_ack = 0;
+
+ if (dsim->state = DSIM_STATE_ULPS) {
+ dev_err(dsim->dev, "state is ULPS.\n");
+
+ return -EINVAL;
+ }
+
+ /* FIXME!!! why does it need this delay? */
+ msleep(20);
+
+ mutex_lock(&dsim->lock);
+
+ 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[0], data0[1]);
+ if (check_rx_ack) {
+ /* process response func should be implemented */
+ mutex_unlock(&dsim->lock);
+ return 0;
+ } else {
+ mutex_unlock(&dsim->lock);
+ 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[0], data0[1]);
+ if (check_rx_ack) {
+ /* process response func should be implemented. */
+ mutex_unlock(&dsim->lock);
+ return 0;
+ } else {
+ mutex_unlock(&dsim->lock);
+ 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:
+ mutex_unlock(&dsim->lock);
+ return 0;
+
+ /* long packet type and null packet */
+ case MIPI_DSI_NULL_PACKET:
+ case MIPI_DSI_BLANKING_PACKET:
+ mutex_unlock(&dsim->lock);
+ return 0;
+ case MIPI_DSI_GENERIC_LONG_WRITE:
+ case MIPI_DSI_DCS_LONG_WRITE:
+ {
+ unsigned int size, payload = 0;
+ INIT_COMPLETION(dsim_wr_comp);
+
+ size = data_size * 4;
+
+ /* if data count is less then 4, then send 3bytes data. */
+ if (data_size < 4) {
+ payload = data0[0] |
+ data0[1] << 8 |
+ data0[2] << 16;
+
+ s5p_mipi_dsi_wr_tx_data(dsim, payload);
+
+ dev_dbg(dsim->dev, "count = %d payload = %x,%x %x %x\n",
+ data_size, payload, data0[0],
+ data0[1], data0[2]);
+
+ /* in case that data count is more then 4 */
+ } else
+ s5p_mipi_dsi_long_data_wr(dsim, data0, data_size);
+
+ /* put data into header fifo */
+ s5p_mipi_dsi_wr_tx_header(dsim, data_id, data_size & 0xff,
+ (data_size & 0xff00) >> 8);
+
+ if (!wait_for_completion_interruptible_timeout(&dsim_wr_comp,
+ MIPI_FIFO_TIMEOUT)) {
+ dev_warn(dsim->dev, "command write timeout.\n");
+ mutex_unlock(&dsim->lock);
+ return -EAGAIN;
+ }
+
+ if (check_rx_ack) {
+ /* process response func should be implemented. */
+ mutex_unlock(&dsim->lock);
+ return 0;
+ } else {
+ mutex_unlock(&dsim->lock);
+ 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. */
+ mutex_unlock(&dsim->lock);
+ return 0;
+ } else {
+ mutex_unlock(&dsim->lock);
+ return -EINVAL;
+ }
+ default:
+ dev_warn(dsim->dev,
+ "data id %x is not supported current DSI spec.\n",
+ data_id);
+
+ mutex_unlock(&dsim->lock);
+ return -EINVAL;
+ }
+
+ mutex_unlock(&dsim->lock);
+ return 0;
+}
+
+static unsigned int s5p_mipi_dsi_long_data_rd(struct mipi_dsim_device *dsim,
+ unsigned int req_size, unsigned int rx_data, u8 *rx_buf)
+{
+ unsigned int rcv_pkt, i, j;
+ u16 rxsize;
+
+ /* for long packet */
+ rxsize = (u16)((rx_data & 0x00ffff00) >> 8);
+ dev_dbg(dsim->dev, "mipi dsi rx size : %d\n", rxsize);
+ if (rxsize != req_size) {
+ dev_dbg(dsim->dev,
+ KERN_ERR "received data size mismatch \
+ received: %d, requested: %d\n", rxsize, req_size);
+ goto err;
+ }
+
+ for (i = 0; i < (rxsize >> 2); i++) {
+ rcv_pkt = s5p_mipi_dsi_rd_rx_fifo(dsim);
+ dev_dbg(dsim->dev, "received pkt : %08x\n", rcv_pkt);
+ for (j = 0; j < 4; j++) {
+ rx_buf[(i * 4) + j] + (u8)(rcv_pkt >> (j * 8)) & 0xff;
+ dev_dbg(dsim->dev, "received value : %02x\n",
+ (rcv_pkt >> (j * 8)) & 0xff);
+ }
+ }
+ if (rxsize % 4) {
+ rcv_pkt = s5p_mipi_dsi_rd_rx_fifo(dsim);
+ dev_dbg(dsim->dev, "received pkt : %08x\n", rcv_pkt);
+ for (j = 0; j < (rxsize % 4); j++) {
+ rx_buf[(i * 4) + j] + (u8)(rcv_pkt >> (j * 8)) & 0xff;
+ dev_dbg(dsim->dev, "received value : %02x\n",
+ (rcv_pkt >> (j * 8)) & 0xff);
+ }
+ }
+
+ return rxsize;
+
+err:
+ return -EINVAL;
+}
+
+static unsigned int s5p_mipi_dsi_respense_size(unsigned int req_size)
+{
+ u8 response;
+ switch (req_size) {
+ case 1:
+ response = MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE;
+ break;
+ case 2:
+ response = MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE;
+ break;
+ default:
+ response = MIPI_DSI_RX_GENERIC_LONG_READ_RESPONSE;
+ break;
+ }
+
+ return response;
+}
+
+int s5p_mipi_dsi_rd_data(struct mipi_dsim_device *dsim, unsigned int data_id,
+ unsigned int data0, unsigned int req_size, u8 *rx_buf)
+{
+ unsigned int rx_data, rcv_pkt, i;
+ u8 response = 0;
+ u16 rxsize;
+
+ if (dsim->state = DSIM_STATE_ULPS) {
+ dev_err(dsim->dev, "state is ULPS.\n");
+
+ return -EINVAL;
+ }
+
+ /* FIXME!!! */
+ msleep(20);
+
+ mutex_lock(&dsim->lock);
+ INIT_COMPLETION(dsim_rd_comp);
+ s5p_mipi_dsi_rd_tx_header(dsim,
+ MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE, req_size);
+
+ response = s5p_mipi_dsi_respense_size(req_size);
+
+ switch (data_id) {
+ 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_rd_tx_header(dsim,
+ data_id, data0);
+ /* process response func should be implemented. */
+ break;
+ default:
+ dev_warn(dsim->dev,
+ "data id %x is not supported current DSI spec.\n",
+ data_id);
+
+ return -EINVAL;
+ }
+
+ if (!wait_for_completion_interruptible_timeout(&dsim_rd_comp,
+ MIPI_FIFO_TIMEOUT)) {
+ printk(KERN_ERR "RX done interrupt timeout\n");
+ mutex_unlock(&dsim->lock);
+ return 0;
+ }
+
+ msleep(20);
+
+ rx_data = s5p_mipi_dsi_rd_rx_fifo(dsim);
+
+ if ((u8)(rx_data & 0xff) != response) {
+ printk(KERN_ERR
+ "mipi dsi wrong response rx_data : %x, response:%x\n",
+ rx_data, response);
+ goto clear_rx_fifo;
+ }
+
+ if (req_size <= 2) {
+ /* for short packet */
+ for (i = 0; i < req_size; i++)
+ rx_buf[i] = (rx_data >> (8 + (i * 8))) & 0xff;
+ rxsize = req_size;
+ } else {
+ /* for long packet */
+ rxsize = s5p_mipi_dsi_long_data_rd(dsim, req_size, rx_data,
+ rx_buf);
+ if (rxsize != req_size)
+ goto clear_rx_fifo;
+ }
+
+ rcv_pkt = s5p_mipi_dsi_rd_rx_fifo(dsim);
+
+ msleep(20);
+
+ if (rcv_pkt != MIPI_RX_FIFO_READ_DONE) {
+ dev_info(dsim->dev,
+ "Can't found RX FIFO READ DONE FLAG : %x\n", rcv_pkt);
+ goto clear_rx_fifo;
+ }
+
+ mutex_unlock(&dsim->lock);
+
+ return rxsize;
+
+clear_rx_fifo:
+ i = 0;
+ while (1) {
+ rcv_pkt = s5p_mipi_dsi_rd_rx_fifo(dsim);
+ if ((rcv_pkt = MIPI_RX_FIFO_READ_DONE)
+ || (i > MIPI_MAX_RX_FIFO))
+ break;
+ dev_dbg(dsim->dev,
+ "mipi dsi clear rx fifo : %08x\n", rcv_pkt);
+ i++;
+ }
+ dev_info(dsim->dev,
+ "mipi dsi rx done count : %d, rcv_pkt : %08x\n", i, rcv_pkt);
+
+ mutex_unlock(&dsim->lock);
+
+ return 0;
+}
+
+static 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_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;
+}
+
+static 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;
+}
+
+static 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\n");
+ dev_warn(dsim->dev,
+ "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\n");
+ dev_warn(dsim->dev,
+ "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, 1);
+
+ /* 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, 0);
+
+ 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_func_reset(dsim);
+
+ s5p_mipi_dsi_dp_dn_swap(dsim, 0);
+
+ return 0;
+}
+
+void s5p_mipi_dsi_init_interrupt(struct mipi_dsim_device *dsim)
+{
+ unsigned int src = 0;
+
+ src = (INTSRC_SFR_FIFO_EMPTY | INTSRC_RX_DATA_DONE);
+ s5p_mipi_dsi_set_interrupt(dsim, src, 1);
+
+ src = 0;
+ src = ~(INTMSK_RX_DONE | INTMSK_FIFO_EMPTY);
+ s5p_mipi_dsi_set_interrupt_mask(dsim, src, 1);
+}
+
+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;
+}
+
+void s5p_mipi_dsi_stand_by(struct mipi_dsim_device *dsim,
+ unsigned int enable)
+{
+
+ /* consider Main display and Sub display. */
+
+ s5p_mipi_dsi_set_main_stand_by(dsim, enable);
+}
+
+int s5p_mipi_dsi_set_display_mode(struct mipi_dsim_device *dsim,
+ struct mipi_dsim_config *dsim_config)
+{
+ struct mipi_dsim_platform_data *dsim_pd;
+ struct fb_videomode *timing;
+
+ dsim_pd = (struct mipi_dsim_platform_data *)dsim->pd;
+ timing = (struct fb_videomode *)dsim_pd->lcd_panel_info;
+
+ /* in case of VIDEO MODE (RGB INTERFACE), it sets polarities. */
+ if (dsim_config->e_interface = (u32) DSIM_VIDEO) {
+ if (dsim_config->auto_vertical_cnt = 0) {
+ s5p_mipi_dsi_set_main_disp_vporch(dsim,
+ dsim_config->cmd_allow,
+ timing->upper_margin,
+ timing->lower_margin);
+ s5p_mipi_dsi_set_main_disp_hporch(dsim,
+ timing->left_margin,
+ timing->right_margin);
+ s5p_mipi_dsi_set_main_disp_sync_area(dsim,
+ timing->vsync_len,
+ timing->hsync_len);
+ }
+ }
+
+ s5p_mipi_dsi_set_main_disp_resol(dsim, timing->xres,
+ timing->yres);
+
+ s5p_mipi_dsi_display_config(dsim, dsim_config);
+
+ dev_info(dsim->dev, "lcd panel => width = %d, height = %d\n",
+ timing->xres, timing->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_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;
+}
+
+int s5p_mipi_dsi_fifo_clear(struct mipi_dsim_device *dsim,
+ unsigned int val)
+{
+ int try = TRY_FIFO_CLEAR;
+
+ s5p_mipi_dsi_sw_reset_release(dsim);
+ s5p_mipi_dsi_func_reset(dsim);
+
+ do {
+ if (s5p_mipi_dsi_get_sw_reset_release(dsim)) {
+ s5p_mipi_dsi_init_interrupt(dsim);
+ dev_dbg(dsim->dev, "reset release done.\n");
+ return 0;
+ }
+ } while (--try);
+
+ dev_err(dsim->dev, "failed to clear dsim fifo.\n");
+ return -EAGAIN;
+}
+
+MODULE_AUTHOR("InKi Dae <inki.dae@samsung.com>");
+MODULE_DESCRIPTION("Samusung SoC MIPI-DSI 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..e1063e6
--- /dev/null
+++ b/drivers/video/s5p_mipi_dsi_common.h
@@ -0,0 +1,46 @@
+/* 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>
+ * Donghwa Lee <dh09.lee@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
+
+static DECLARE_COMPLETION(dsim_rd_comp);
+static DECLARE_COMPLETION(dsim_wr_comp);
+
+int s5p_mipi_dsi_wr_data(struct mipi_dsim_device *dsim, unsigned int data_id,
+ unsigned char *data0, unsigned int data_size);
+int s5p_mipi_dsi_rd_data(struct mipi_dsim_device *dsim, unsigned int data_id,
+ unsigned int data0, unsigned int req_size, u8 *rx_buf);
+irqreturn_t s5p_mipi_dsi_interrupt_handler(int irq, void *dev_id);
+void s5p_mipi_dsi_init_interrupt(struct mipi_dsim_device *dsim);
+int s5p_mipi_dsi_init_dsim(struct mipi_dsim_device *dsim);
+void s5p_mipi_dsi_stand_by(struct mipi_dsim_device *dsim,
+ unsigned int enable);
+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;
+
+int s5p_mipi_dsi_fifo_clear(struct mipi_dsim_device *dsim,
+ unsigned int val);
+
+#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..3af1e82
--- /dev/null
+++ b/drivers/video/s5p_mipi_dsi_lowlevel.c
@@ -0,0 +1,627 @@
+/* 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>
+ * Donghwa Lee, <dh09.lee@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 <linux/mipi_dsim.h>
+
+#include <mach/map.h>
+
+#include "s5p_mipi_dsi_regs.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_sw_reset_release(struct mipi_dsim_device *dsim)
+{
+ unsigned int reg;
+
+ reg = readl(dsim->reg_base + S5P_DSIM_INTSRC);
+
+ reg |= INTSRC_SW_RST_RELEASE;
+
+ writel(reg, dsim->reg_base + S5P_DSIM_INTSRC);
+}
+
+int s5p_mipi_dsi_get_sw_reset_release(struct mipi_dsim_device *dsim)
+{
+ return (readl(dsim->reg_base + S5P_DSIM_INTSRC)) &
+ INTSRC_SW_RST_RELEASE;
+}
+
+unsigned int s5p_mipi_dsi_read_interrupt_mask(struct mipi_dsim_device *dsim)
+{
+ unsigned int reg;
+
+ reg = readl(dsim->reg_base + S5P_DSIM_INTMSK);
+
+ return reg;
+}
+
+void s5p_mipi_dsi_set_interrupt_mask(struct mipi_dsim_device *dsim,
+ unsigned int mode, unsigned int mask)
+{
+ unsigned int reg = 0;
+
+ 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_stand_by(struct mipi_dsim_device *dsim,
+ unsigned int enable)
+{
+ unsigned int reg;
+
+ reg = readl(dsim->reg_base + S5P_DSIM_MDRESOL);
+
+ reg &= ~DSIM_MAIN_STAND_BY;
+
+ if (enable)
+ reg |= DSIM_MAIN_STAND_BY;
+
+ writel(reg, dsim->reg_base + S5P_DSIM_MDRESOL);
+}
+
+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, "unknown lcd type.\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);
+}
+
+unsigned int s5p_mipi_dsi_read_interrupt(struct mipi_dsim_device *dsim)
+{
+ return readl(dsim->reg_base + S5P_DSIM_INTSRC);
+}
+
+void s5p_mipi_dsi_clear_interrupt(struct mipi_dsim_device *dsim,
+ unsigned int src)
+{
+ unsigned int reg = readl(dsim->reg_base + S5P_DSIM_INTSRC);
+
+ reg |= src;
+
+ writel(reg, dsim->reg_base + S5P_DSIM_INTSRC);
+}
+
+void s5p_mipi_dsi_set_interrupt(struct mipi_dsim_device *dsim,
+ unsigned int src, unsigned int enable)
+{
+ unsigned int reg = 0;
+
+ if (enable)
+ reg |= src;
+ else
+ reg &= ~src;
+
+ 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);
+}
+
+void s5p_mipi_dsi_rd_tx_header(struct mipi_dsim_device *dsim,
+ unsigned int di, unsigned int data0)
+{
+ unsigned int reg = (data0 << 8) | (di << 0);
+
+ writel(reg, dsim->reg_base + S5P_DSIM_PKTHDR);
+}
+
+unsigned int s5p_mipi_dsi_rd_rx_fifo(struct mipi_dsim_device *dsim)
+{
+ unsigned int reg = 0;
+
+ reg = readl(dsim->reg_base + S5P_DSIM_RXFIFO);
+
+ return reg;
+}
+
+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..da3a63e
--- /dev/null
+++ b/drivers/video/s5p_mipi_dsi_lowlevel.h
@@ -0,0 +1,112 @@
+/* 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>
+ * Donghwa Lee <dh09.lee@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_sw_reset_release(struct mipi_dsim_device *dsim);
+int s5p_mipi_dsi_get_sw_reset_release(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_stand_by(struct mipi_dsim_device *dsim,
+ unsigned int enable);
+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);
+unsigned int s5p_mipi_dsi_read_interrupt(struct mipi_dsim_device *dsim);
+unsigned int s5p_mipi_dsi_read_interrupt_mask(struct mipi_dsim_device *dsim);
+void s5p_mipi_dsi_clear_interrupt(struct mipi_dsim_device *dsim,
+ unsigned int src);
+void s5p_mipi_dsi_set_interrupt(struct mipi_dsim_device *dsim,
+ unsigned int src, unsigned int enable);
+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);
+void s5p_mipi_dsi_rd_tx_header(struct mipi_dsim_device *dsim,
+ unsigned int data0, unsigned int data1);
+unsigned int s5p_mipi_dsi_rd_rx_fifo(struct mipi_dsim_device *dsim);
+
+#endif /* _S5P_MIPI_DSI_LOWLEVEL_H */
diff --git a/drivers/video/s5p_mipi_dsi_regs.h b/drivers/video/s5p_mipi_dsi_regs.h
new file mode 100644
index 0000000..3ad0fe3
--- /dev/null
+++ b/drivers/video/s5p_mipi_dsi_regs.h
@@ -0,0 +1,156 @@
+/* linux/driver/video/s5p_mipi_dsi_regs.h
+ *
+ * Register definition file for Samsung MIPI-DSIM driver
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * InKi Dae <inki.dae@samsung.com>
+ * Donghwa Lee <dh09.lee@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_PLL_STABLE (1 << 31)
+#define INTSRC_SW_RST_RELEASE (1 << 30)
+#define INTSRC_SFR_FIFO_EMPTY (1 << 29)
+#define INTSRC_FRAME_DONE (1 << 24)
+#define INTSRC_RX_DATA_DONE (1 << 18)
+
+/* S5P_DSIM_INTMSK */
+#define INTMSK_FIFO_EMPTY (1 << 29)
+#define INTMSK_BTA (1 << 25)
+#define INTMSK_FRAME_DONE (1 << 24)
+#define INTMSK_RX_TIMEOUT (1 << 21)
+#define INTMSK_BTA_TIMEOUT (1 << 20)
+#define INTMSK_RX_DONE (1 << 18)
+#define INTMSK_RX_TE (1 << 17)
+#define INTMSK_RX_ACK (1 << 16)
+#define INTMSK_RX_ECC_ERR (1 << 15)
+#define INTMSK_RX_CRC_ERR (1 << 14)
+
+/* 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/include/linux/mipi_dsim.h b/include/linux/mipi_dsim.h
new file mode 100644
index 0000000..a6d3b01
--- /dev/null
+++ b/include/linux/mipi_dsim.h
@@ -0,0 +1,361 @@
+/* include/linux/mipi_dsim.h
+ *
+ * Platform data header for Samsung SoC MIPI-DSIM.
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * InKi Dae <inki.dae@samsung.com>
+ * Donghwa Lee <dh09.lee@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 _LINUX_MIPI_DSIM_H
+#define _LINUX_MIPI_DSIM_H
+
+#include <linux/device.h>
+#include <linux/fb.h>
+
+#define PANEL_NAME_SIZE (32)
+
+/*
+ * enumurate display interface type.
+ *
+ * DSIM_COMMAND means cpu interface and rgb interface for DSIM_VIDEO.
+ *
+ * P.S. MIPI DSI Master has two display controller intefaces, RGB Interface
+ * for main display and CPU Interface(same as I80 Interface) for main
+ * and sub display.
+ */
+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_BURST_SYNC_EVENT,
+ DSIM_NON_BURST_SYNC_PULSE,
+ 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)
+ * @cma_allow: specifies the number of horizontal lines, where command packet
+ * transmission is allowed after Stable VFP period.
+ * @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;
+ unsigned char cmd_allow;
+
+ 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 |
+ * | 6 | 118 | 1 | 472 |
+ * | 3 | 120 | 1 | 480 |
+ * | 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 |
+ * -------------------------------------------
+ */
+
+ /*
+ * pms could be calculated as the following.
+ * M * 24 / P * 2 ^ S = MHz
+ */
+ 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.
+ * @power_t: current power status.
+ * @state: specifies status of MIPI-DSI controller.
+ * the status could be RESET, INIT, STOP, HSCLKEN and ULPS.
+ * @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;
+
+ atomic_t power_t;
+ unsigned int state;
+ unsigned int data_lane;
+ unsigned int e_clk_src;
+ bool suspended;
+
+ struct mipi_dsim_platform_data *pd;
+};
+
+/*
+ * struct mipi_dsim_platform_data - 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.
+ * @enabled: indicate whether mipi controller got enabled or not.
+ * @lcd_panel_info: pointer for lcd panel specific structure.
+ * this structure specifies width, height, timing and polarity and so on.
+ * @phy_enable: pointer to a callback controlling D-PHY enable/reset
+ */
+struct mipi_dsim_platform_data {
+ char lcd_panel_name[PANEL_NAME_SIZE];
+
+ struct mipi_dsim_config *dsim_config;
+ unsigned int enabled;
+ void *lcd_panel_info;
+
+ 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.
+ * @set_early_blank_mode: set framebuffer blank mode.
+ * - this callback should be called prior to fb_blank() by a client driver
+ * only if needing.
+ * @set_blank_mode: set framebuffer blank mode.
+ * - this callback should be called after fb_blank() by a client driver
+ * only if needing.
+ */
+
+struct mipi_dsim_master_ops {
+ int (*cmd_write)(struct mipi_dsim_device *dsim, unsigned int data_id,
+ unsigned char *data0, unsigned int data1);
+ int (*cmd_read)(struct mipi_dsim_device *dsim, unsigned int data_id,
+ unsigned int data0, unsigned int req_size, u8 *rx_buf);
+ 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);
+ int (*set_early_blank_mode)(struct mipi_dsim_device *dsim, int power);
+ int (*set_blank_mode)(struct mipi_dsim_device *dsim, int power);
+};
+
+/*
+ * 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;
+
+ void (*power_on)(struct mipi_dsim_lcd_device *dsim_dev, int enable);
+ void (*set_sequence)(struct mipi_dsim_lcd_device *dsim_dev);
+ 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_device to mipi-dsi master.
+ */
+int s5p_mipi_dsi_register_lcd_device(struct mipi_dsim_lcd_device
+ *lcd_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);
+#endif /* _LINUX_MIPI_DSIM_H */
--
1.7.4.1
^ permalink raw reply related
* linux-next: build warning after merge of the fbdev tree
From: Stephen Rothwell @ 2011-12-20 5:32 UTC (permalink / raw)
To: Florian Tobias Schandinat, linux-fbdev
Cc: linux-next, linux-kernel, Laurent Pinchart
[-- Attachment #1: Type: text/plain, Size: 1290 bytes --]
Hi all,
After merging the fbdev tree, today's linux-next build (powerpc ppc64_defconfig)
produced this warning:
drivers/video/matrox/matroxfb_base.c:150:2: warning: braces around scalar initializer [enabled by default]
drivers/video/matrox/matroxfb_base.c:150:2: warning: (near initialization for 'vesafb_defined.colorspace') [enabled by default]
drivers/video/matrox/matroxfb_base.c:150:2: warning: excess elements in scalar initializer [enabled by default]
drivers/video/matrox/matroxfb_base.c:150:2: warning: (near initialization for 'vesafb_defined.colorspace') [enabled by default]
drivers/video/matrox/matroxfb_crtc2.c:596:3: warning: braces around scalar initializer [enabled by default]
drivers/video/matrox/matroxfb_crtc2.c:596:3: warning: (near initialization for 'matroxfb_dh_defined.colorspace') [enabled by default]
drivers/video/matrox/matroxfb_crtc2.c:596:3: warning: excess elements in scalar initializer [enabled by default]
drivers/video/matrox/matroxfb_crtc2.c:596:3: warning: (near initialization for 'matroxfb_dh_defined.colorspace') [enabled by default]
Introduced by commit fb21c2f42879 ("fbdev: Add FOURCC-based format
configuration API").
--
Cheers,
Stephen Rothwell sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/
[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]
^ 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