Linux Framebuffer Layer development
 help / color / mirror / Atom feed
* Re: [PATCH] Corrected matroxfb video option in comments and kernel config help.
From: Paul Mundt @ 2011-01-06  6:35 UTC (permalink / raw)
  To: linux-fbdev
In-Reply-To: <AANLkTikqCduraRjVvtaU3u1ikQyR-3GryovdTMe-z5HD@mail.gmail.com>

On Tue, Dec 28, 2010 at 11:03:50AM +0100, Vicente Jim?nez wrote:
> From 81561bbf722613794c77cd03c537f4139b2d0976 Mon Sep 17 00:00:00 2001
> From: Vicente Jimenez Aguilar <googuy@gmail.com>
> Date: Tue, 28 Dec 2010 11:35:24 +0100
> Subject: [PATCH 2/2] Corrected matroxfb video option in comments and kernel config help.
> 
> Configuring the kernel I found that the Matrox frame buffer help has a
> different option than the one in the docs (Documentation/fb/matroxfb.txt).
> I decided to check the source code to see what is the correct option.
> drivers/video/matrox/matroxfb_base.c has a lot of comments that sugests
> that the video option is "matrox".
> However in line 2452 of this same file you have:
> fb_get_options("matroxfb", &option)
> 
> video=matroxfb:XXX is the correct video option not video=matrox:XXX.

Missing Signed-off-by.

^ permalink raw reply

* Re: [PATCH 5/5] S5PC110: add MIPI-DSI based sample lcd panel driver.
From: InKi Dae @ 2011-01-06  6:31 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20110106051458.GP23889@linux-sh.org>

thank you for your reviews.

all the problems you  pointed out would be corrected for actual lcd
panel driver.
(this lcd panel driver has being worked locally and it will be posted
in the future)

after this patch, I posted next patches.
refer to below please.
http://permalink.gmane.org/gmane.linux.ports.arm.kernel/101521

in this patch, I removed sample driver and also have code compacting
and refactoring for MIPI-DSI driver. so could you please give me your
review about this one?

2011/1/6 Paul Mundt <lethal@linux-sh.org>:
> On Tue, Dec 28, 2010 at 08:26:35PM +0900, Inki Dae wrote:
>> this patch addes MIPI-DSI based sample panel driver.
>> to write MIPI-DSI based lcd panel driver, you can refer to
>> this sample driver.
>>
>> Signed-off-by: Inki Dae <inki.dae@samsung.com>
>
> Sample drivers are ok, but unless it has some sort of practical run-time
> use you are probably better off just including this along with your
> subsystem/platform documentation in Documentation somewhere. You can
> search for .c files there to see how others are doing it.
>
> Having said that ..
>
>> diff --git a/drivers/video/s5p_mipi_sample.c b/drivers/video/s5p_mipi_sample.c
>> new file mode 100644
>> index 0000000..8a8abfe
>> --- /dev/null
>> +++ b/drivers/video/s5p_mipi_sample.c
>> @@ -0,0 +1,220 @@
>> +/* linux/drivers/video/sample.c
>> + *
> This is precisely why file comments are useless, since they invariably
> fail to match up.
>
>> + * MIPI-DSI based sample AMOLED lcd panel driver.
>> + *
>> + * Inki Dae, <inki.dae@samsung.com>
>> + *
> No Copyright notice?
>
>> +static void sample_long_command(struct sample *lcd)
>> +{
>> +     struct dsim_master_ops *ops = lcd_to_master_ops(lcd);
>> +     unsigned char data_to_send[5] = {
>> +             0x00, 0x00, 0x00, 0x00, 0x00
>> +     };
>> +
>> +     ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
>> +             (unsigned int) data_to_send, sizeof(data_to_send));
>> +}
>> +
>> +static void sample_short_command(struct sample *lcd)
>> +{
>> +     struct dsim_master_ops *ops = lcd_to_master_ops(lcd);
>> +
>> +     ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_SHORT_WRITE_PARAM,
>> +                             0x00, 0x00);
>> +}
>> +
> ops->cmd_write() can fail for any number of reasons, so you will want to
> change these to make sure that you are actually handling the error cases.
>
>> +static int sample_panel_init(struct sample *lcd)
>> +{
>> +     sample_long_command(lcd);
>> +     sample_short_command(lcd);
>> +
>> +     return 0;
>
> At which point you can fail the initialization instead of just blowing up
> later.
>
>> +static int sample_gamma_ctrl(struct sample *lcd, int gamma)
>> +{
>> +     struct dsim_master_ops *ops = lcd_to_master_ops(lcd);
>> +
>> +     /* change transfer mode to LP mode */
>> +     if (ops->change_dsim_transfer_mode)
>> +             ops->change_dsim_transfer_mode(lcd_to_master(lcd), 0);
>> +
> ops->change_dsim_transfer_mode() can also fail. You could do this more
> cleanly as:
>
> enum { DSIM_XFER_LP, DSIM_XFER_HS };
>
> static inline int dsim_set_xfer_mode(struct mipi_dsim_device *dsim, int mode)
> {
>        struct mipi_dsim_master_ops *ops = dsim->master_ops;
>
>        if (!ops->change_dsim_transfer_mode)
>                return -ENOSYS; /* not implemented */
>
>        return ops->change_dsim_transfer_mode(dsim, mode);
> }
>
> Then simply do your sample_gamma_ctrl() as:
>
>        ret = dsim_set_xfer_mode(dsim, DSIM_XFER_LP);
>        if (ret != 0)
>                return ret;
>
>> +     /* update gamma table. */
>> +
>
>        return dsim_set_xfer_mode(dsim, DSIM_XFER_HS);
>> +}
>> +
>
> Or something similar. Your sample code should really be as
> self-documenting and error-proof as possible. You don't really want to be
> in a situation where subtle bugs leak through that then everyone who uses
> this code as a reference will carry over!
>
>> +static int sample_set_brightness(struct backlight_device *bd)
>> +{
>> +     int ret = 0, brightness = bd->props.brightness;
>> +     struct sample *lcd = bl_get_data(bd);
>> +
>> +     if (brightness < MIN_BRIGHTNESS ||
>> +             brightness > bd->props.max_brightness) {
>> +             dev_err(lcd->dev, "lcd brightness should be %d to %d.\n",
>> +                     MIN_BRIGHTNESS, MAX_BRIGHTNESS);
>> +             return -EINVAL;
>> +     }
>> +
>> +     ret = sample_gamma_ctrl(lcd, bd->props.brightness);
>> +     if (ret) {
>> +             dev_err(&bd->dev, "lcd brightness setting failed.\n");
>> +             return -EIO;
>> +     }
>> +
> With your current approach this error condition will never be reached,
> for example.
>
>> +static int sample_probe(struct mipi_lcd_device *mipi_dev)
>> +{
>> +     struct sample *lcd = NULL;
>> +     struct backlight_device *bd = NULL;
>> +
>> +     lcd = kzalloc(sizeof(struct sample), GFP_KERNEL);
>> +     if (!lcd) {
>> +             dev_err(&mipi_dev->dev, "failed to allocate sample structure.\n");
>> +             return -ENOMEM;
>> +     }
>> +
>> +     lcd->mipi_dev = mipi_dev;
>> +     lcd->ddi_pd >> +             (struct mipi_ddi_platform_data *)device_to_ddi_pd(mipi_dev);
>
> Does this really need to be casted?
>
>> +     lcd->dev = &mipi_dev->dev;
>> +
>> +     dev_set_drvdata(&mipi_dev->dev, lcd);
>> +
>> +     bd = backlight_device_register("sample-bl", lcd->dev, lcd,
>> +             &sample_backlight_ops, NULL);
>> +
>> +     lcd->bd = bd;
>> +
> And here you have no error checking for backlight registration, so you
> will get a NULL pointer deref:
>
>> +     bd->props.max_brightness = MAX_BRIGHTNESS;
>> +     bd->props.brightness = MAX_BRIGHTNESS;
>> +
> here. backlight_device_register() returns an ERR_PTR(), so you will want
> to do an IS_ERR() check, which you can then map back with PTR_ERR() for a
> more precise idea of why it failed.
>
>> +     /* lcd power on */
>> +     if (lcd->ddi_pd->lcd_power_on)
>> +             lcd->ddi_pd->lcd_power_on(NULL, 1);
>> +
> You may wish to use enums for this too. It's not strictly necessary, but
> it does help to clarify which is the on and which is the off position.
>
>> +     mdelay(lcd->ddi_pd->reset_delay);
>> +
>> +     /* lcd reset */
>> +     if (lcd->ddi_pd->lcd_reset)
>> +             lcd->ddi_pd->lcd_reset(NULL);
>> +
> Reset can fail?
>
>> +     sample_panel_init(lcd);
>> +
>> +     return 0;
>> +}
> sample_panel_init() can fail as well, and in both cases you will need to
> clean up all of the above work.
>
>> +
>> +#ifdef CONFIG_PM
>> +static int sample_suspend(struct mipi_lcd_device *mipi_dev)
>> +{
>> +     struct sample *lcd = dev_get_drvdata(&mipi_dev->dev);
>> +
>> +     /* some work. */
>> +
>> +     mdelay(lcd->ddi_pd->power_off_delay);
>> +
> Adding delays in the suspend/resume path sounds like a pretty bad idea,
> is there a technical reason for it? If so, please document it, so people
> get some idea of where their suspend/resume latencies are coming from,
> and why.
>
>> +static struct mipi_lcd_driver sample_mipi_driver = {
>> +     .name = "sample",
>> +
>> +     .probe = sample_probe,
>
> No remove?
>
>> +     .suspend = sample_suspend,
>> +     .resume = sample_resume,
>> +};
>> +
>> +static int sample_init(void)
>> +{
>> +     s5p_mipi_register_lcd_driver(&sample_mipi_driver);
>> +
>> +     return 0;
>> +}
>> +
> This should be:
>
>        return s5p_mipi_register_lcd_driver(&sample_mipi_driver);
>
> And sample_init should be __init annotated.
>
>> +static void sample_exit(void)
>> +{
>> +     return;
>> +}
>> +
> This should be balanced with a
>
>        s5p_mipi_unregister_lcd_driver(&sample_mipi_driver);
>
>> +module_init(sample_init);
>> +module_exit(sample_exit);
>> +
>> +MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
>> +MODULE_DESCRIPTION("MIPI-DSI based sample AMOLED LCD Panel Driver");
>> +MODULE_LICENSE("GPL");
>
> Since you have a fairly complex subsystem it's probably a good idea to
> work out how your MODULE_ALIAS() is going to work, so that you can handle
> autoprobe for these things via udev. The fact you have no exit path
> definitely suggests you haven't tested this in a modular configuration,
> so there is probably going to be quite a bit of work to do here.
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>

^ permalink raw reply

* RE: [PATCH RE-SEND] s3c-fb: Add support S5PV310 FIMD
From: Kukjin Kim @ 2011-01-06  5:19 UTC (permalink / raw)
  To: 'Inki Dae', linux-samsung-soc, linux-fbdev
  Cc: ben-linux, akpm, lethal, 'Jonghun Han',
	'Sangbeom Kim'
In-Reply-To: <001b01cbabf6$c62180a0$526481e0$%dae@samsung.com>

Inki Dae wrote:
> 
> Hello, Mr. Kukjin.
> 
Hi,

> I know we had a discussion about your patch below.
> after that, did you have some discussion about that?
> If not, Paul advised to use clkdev lookup.
> 
> Please, refer to below mail.
>
http://www.mail-archive.com/linux-samsung-soc@vger.kernel.org/msg03448.html

I think it's different with your approach even though the purpose is similar
and I know, Mr. Han explained about clock configurable by call.

Paul, how do you think about this?

Personally, if we want to support S5PV310 FIMD now, this patch is good to
support it and to us now.
Of course, I think, we can upgrade it later.

Thanks.

Best regards,
Kgene.
--
Kukjin Kim <kgene.kim@samsung.com>, Senior Engineer,
SW Solution Development Team, Samsung Electronics Co., Ltd.

> > -----Original Message-----
> > From: linux-fbdev-owner@vger.kernel.org [mailto:linux-fbdev-
> > owner@vger.kernel.org] On Behalf Of Kukjin Kim
> > Sent: Tuesday, January 04, 2011 5:06 PM
> > To: linux-samsung-soc@vger.kernel.org; linux-fbdev@vger.kernel.org
> > Cc: ben-linux@fluff.org; akpm@linux-foundation.org; lethal@linux-sh.org;
> > Jonghun Han; Sangbeom Kim; InKi Dae; Kukjin Kim
> > Subject: [PATCH RE-SEND] s3c-fb: Add support S5PV310 FIMD
> >
> > From: Jonghun Han <jonghun.han@samsung.com>
> >
> > This patch adds struct s3c_fb_driverdata s3c_fb_data_s5pv310 for S5PV310
> > and S5PC210. The clk_type is added to distinguish clock type in it and
> > lcd_clk is added in structure s3c_fb to calculate divider for lcd panel.
> >
> > Please refer to below diagrams about clocks of FIMD IP. FIMD driver
needs
> > two clocks for FIMD IP and LCD pixel clock. Actually, the LCD pixel
clock
> > can be selected from 1.clk 'lcd' and 2.SCLK_FIMD before S5PV310. But
from
> > S5PV310, the 2.SCLK_FIMD can be used only for source of LCD pixel clock.
> >
> > FIMD_CLK_TYPE0:
> >            ------------------------------------
> >                       dsys bus
> >            ----------------+-------------------
> >                            |
> >                            |1.clk 'lcd'
> >                            |
> >                            | FIMD block
> >                        +---+-----------+
> > 4.mout_mpll |\         |   |           |
> >     --------|m|        | +-+-+ +----+  |
> >             |u|-+      | |   +-+core|  |
> >             |x| |      | |     +----+  |
> >             |/  |      | | |\          |
> >                 |      | +-|m|  +---+  |
> >                 |      |   |u|--+div|  |
> >                 +------+---|x|  +---+  |
> >            2.SCLK_FIMD |   |/     |    |
> >                        |          |    |
> >                        +----------+----+
> >                                   |
> >            inside of SoC          |
> >            -----------------------+--------------------------
> >            outside of SoC         |
> >                                   | 3.LCD pixel clock
> >                                   |
> >                           +--------------+
> >                           | LCD module   |
> >                           +--------------+
> >
> > FIMD_CLK_TYPE1:
> >            ------------------------------------
> >                       dsys bus
> >            ----------------+-------------------
> >                            |
> >                            |1.clk 'fimd'
> >                            |
> >                            | FIMD block
> >                        +---+-----------+
> > 4.mout_mpll |\         |   |           |
> >     --------|m|        |   |   +----+  |
> >             |u|-+      |   +---+core|  |
> >             |x| |      |       +----+  |
> >             |/  |      |               |
> >                 |      |        +---+  |
> >                 |      |     +--+div|  |
> >                 +------+-----+  +---+  |
> >            2.SCLK_FIMD |          |    |
> >                        |          |    |
> >                        +----------+----+
> >                                   |
> >            inside of SoC          |
> >            -----------------------+--------------------------
> >            outside of SoC         |
> >                                   | 3.LCD pixel clock
> >                                   |
> >                           +--------------+
> >                           | LCD module   |
> >                           +--------------+
> >
> > Signed-off-by: Jonghun Han <jonghun.han@samsung.com>
> > Signed-off-by: Sangbeom Kim <sbkim73@samsung.com>
> > Cc: InKi Dae <inki.dae@samsung.com>
> > Cc: Ben Dooks <ben-linux@fluff.org>
> > Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
> > ---
> > Hi Paul,
> >
> > I and Mr. Han, Jonghun sent below patch several weeks ago.
> > But I couldn't find it in your tree...
> > (Re-made against on your latest fbdev-2.6.git #master)
> >
> > I think this should be merged for supporting S5PV310/S5PC210 frame
buffer.
> > So could you please let me know your opinion or plan about this?
> >
> > NOTE: Needs following platform device patches for S5PV310/S5PC210 frame
> > buffer.
> > And I already applied that in my tree as S5P SoCs architecture
maintainer.
> >
> > 0001-ARM-S5PV310-Add-FIMD-resource-definition.patch
> > 0002-ARM-S5PV310-Add-platform-device-and-helper-functio.patch
> > 0004-ARM-S5PV310-Add-support-FIMD0-and-LTE480WV-LCD-for.patch
> >
> >  drivers/video/Kconfig  |    2 +-
> >  drivers/video/s3c-fb.c |  125
> > +++++++++++++++++++++++++++++++++++++++++++-----
> >  2 files changed, 113 insertions(+), 14 deletions(-)


^ permalink raw reply

* Re: [PATCH 5/5] S5PC110: add MIPI-DSI based sample lcd panel driver.
From: Paul Mundt @ 2011-01-06  5:14 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1293535595-24861-1-git-send-email-inki.dae@samsung.com>

On Tue, Dec 28, 2010 at 08:26:35PM +0900, Inki Dae wrote:
> this patch addes MIPI-DSI based sample panel driver.
> to write MIPI-DSI based lcd panel driver, you can refer to
> this sample driver.
> 
> Signed-off-by: Inki Dae <inki.dae@samsung.com>

Sample drivers are ok, but unless it has some sort of practical run-time
use you are probably better off just including this along with your
subsystem/platform documentation in Documentation somewhere. You can
search for .c files there to see how others are doing it.

Having said that ..

> diff --git a/drivers/video/s5p_mipi_sample.c b/drivers/video/s5p_mipi_sample.c
> new file mode 100644
> index 0000000..8a8abfe
> --- /dev/null
> +++ b/drivers/video/s5p_mipi_sample.c
> @@ -0,0 +1,220 @@
> +/* linux/drivers/video/sample.c
> + *
This is precisely why file comments are useless, since they invariably
fail to match up.

> + * MIPI-DSI based sample AMOLED lcd panel driver.
> + *
> + * Inki Dae, <inki.dae@samsung.com>
> + *
No Copyright notice?

> +static void sample_long_command(struct sample *lcd)
> +{
> +	struct dsim_master_ops *ops = lcd_to_master_ops(lcd);
> +	unsigned char data_to_send[5] = {
> +		0x00, 0x00, 0x00, 0x00, 0x00
> +	};
> +
> +	ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
> +		(unsigned int) data_to_send, sizeof(data_to_send));
> +}
> +
> +static void sample_short_command(struct sample *lcd)
> +{
> +	struct dsim_master_ops *ops = lcd_to_master_ops(lcd);
> +
> +	ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_SHORT_WRITE_PARAM,
> +				0x00, 0x00);
> +}
> +
ops->cmd_write() can fail for any number of reasons, so you will want to
change these to make sure that you are actually handling the error cases.

> +static int sample_panel_init(struct sample *lcd)
> +{
> +	sample_long_command(lcd);
> +	sample_short_command(lcd);
> +
> +	return 0;

At which point you can fail the initialization instead of just blowing up
later.

> +static int sample_gamma_ctrl(struct sample *lcd, int gamma)
> +{
> +	struct dsim_master_ops *ops = lcd_to_master_ops(lcd);
> +
> +	/* change transfer mode to LP mode */
> +	if (ops->change_dsim_transfer_mode)
> +		ops->change_dsim_transfer_mode(lcd_to_master(lcd), 0);
> +
ops->change_dsim_transfer_mode() can also fail. You could do this more
cleanly as:

enum { DSIM_XFER_LP, DSIM_XFER_HS };

static inline int dsim_set_xfer_mode(struct mipi_dsim_device *dsim, int mode)
{
	struct mipi_dsim_master_ops *ops = dsim->master_ops;

	if (!ops->change_dsim_transfer_mode)
		return -ENOSYS;	/* not implemented */

	return ops->change_dsim_transfer_mode(dsim, mode);
}

Then simply do your sample_gamma_ctrl() as:

	ret = dsim_set_xfer_mode(dsim, DSIM_XFER_LP);
	if (ret != 0)
		return ret;

> +	/* update gamma table. */
> +

	return dsim_set_xfer_mode(dsim, DSIM_XFER_HS);
> +}
> +

Or something similar. Your sample code should really be as
self-documenting and error-proof as possible. You don't really want to be
in a situation where subtle bugs leak through that then everyone who uses
this code as a reference will carry over!

> +static int sample_set_brightness(struct backlight_device *bd)
> +{
> +	int ret = 0, brightness = bd->props.brightness;
> +	struct sample *lcd = bl_get_data(bd);
> +
> +	if (brightness < MIN_BRIGHTNESS ||
> +		brightness > bd->props.max_brightness) {
> +		dev_err(lcd->dev, "lcd brightness should be %d to %d.\n",
> +			MIN_BRIGHTNESS, MAX_BRIGHTNESS);
> +		return -EINVAL;
> +	}
> +
> +	ret = sample_gamma_ctrl(lcd, bd->props.brightness);
> +	if (ret) {
> +		dev_err(&bd->dev, "lcd brightness setting failed.\n");
> +		return -EIO;
> +	}
> +
With your current approach this error condition will never be reached,
for example.

> +static int sample_probe(struct mipi_lcd_device *mipi_dev)
> +{
> +	struct sample *lcd = NULL;
> +	struct backlight_device *bd = NULL;
> +
> +	lcd = kzalloc(sizeof(struct sample), GFP_KERNEL);
> +	if (!lcd) {
> +		dev_err(&mipi_dev->dev, "failed to allocate sample structure.\n");
> +		return -ENOMEM;
> +	}
> +
> +	lcd->mipi_dev = mipi_dev;
> +	lcd->ddi_pd > +		(struct mipi_ddi_platform_data *)device_to_ddi_pd(mipi_dev);

Does this really need to be casted?

> +	lcd->dev = &mipi_dev->dev;
> +
> +	dev_set_drvdata(&mipi_dev->dev, lcd);
> +
> +	bd = backlight_device_register("sample-bl", lcd->dev, lcd,
> +		&sample_backlight_ops, NULL);
> +
> +	lcd->bd = bd;
> +
And here you have no error checking for backlight registration, so you
will get a NULL pointer deref:

> +	bd->props.max_brightness = MAX_BRIGHTNESS;
> +	bd->props.brightness = MAX_BRIGHTNESS;
> +
here. backlight_device_register() returns an ERR_PTR(), so you will want
to do an IS_ERR() check, which you can then map back with PTR_ERR() for a
more precise idea of why it failed.

> +	/* lcd power on */
> +	if (lcd->ddi_pd->lcd_power_on)
> +		lcd->ddi_pd->lcd_power_on(NULL, 1);
> +
You may wish to use enums for this too. It's not strictly necessary, but
it does help to clarify which is the on and which is the off position.

> +	mdelay(lcd->ddi_pd->reset_delay);
> +
> +	/* lcd reset */
> +	if (lcd->ddi_pd->lcd_reset)
> +		lcd->ddi_pd->lcd_reset(NULL);
> +
Reset can fail?

> +	sample_panel_init(lcd);
> +
> +	return 0;
> +}
sample_panel_init() can fail as well, and in both cases you will need to
clean up all of the above work.

> +
> +#ifdef CONFIG_PM
> +static int sample_suspend(struct mipi_lcd_device *mipi_dev)
> +{
> +	struct sample *lcd = dev_get_drvdata(&mipi_dev->dev);
> +
> +	/* some work. */
> +
> +	mdelay(lcd->ddi_pd->power_off_delay);
> +
Adding delays in the suspend/resume path sounds like a pretty bad idea,
is there a technical reason for it? If so, please document it, so people
get some idea of where their suspend/resume latencies are coming from,
and why.

> +static struct mipi_lcd_driver sample_mipi_driver = {
> +	.name = "sample",
> +
> +	.probe = sample_probe,

No remove?

> +	.suspend = sample_suspend,
> +	.resume = sample_resume,
> +};
> +
> +static int sample_init(void)
> +{
> +	s5p_mipi_register_lcd_driver(&sample_mipi_driver);
> +
> +	return 0;
> +}
> +
This should be:

	return s5p_mipi_register_lcd_driver(&sample_mipi_driver);

And sample_init should be __init annotated.

> +static void sample_exit(void)
> +{
> +	return;
> +}
> +
This should be balanced with a

	s5p_mipi_unregister_lcd_driver(&sample_mipi_driver);

> +module_init(sample_init);
> +module_exit(sample_exit);
> +
> +MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
> +MODULE_DESCRIPTION("MIPI-DSI based sample AMOLED LCD Panel Driver");
> +MODULE_LICENSE("GPL");

Since you have a fairly complex subsystem it's probably a good idea to
work out how your MODULE_ALIAS() is going to work, so that you can handle
autoprobe for these things via udev. The fact you have no exit path
definitely suggests you haven't tested this in a modular configuration,
so there is probably going to be quite a bit of work to do here.

^ permalink raw reply

* Re: [PATCH v2 1/2] video, sm501: add OF binding to support SM501
From: Paul Mundt @ 2011-01-06  4:47 UTC (permalink / raw)
  To: Heiko Schocher
  Cc: linuxppc-dev, linux-fbdev, devicetree-discuss, Ben Dooks,
	Vincent Sanders, Samuel Ortiz, linux-kernel
In-Reply-To: <1292049075-1809-1-git-send-email-hs@denx.de>

On Sat, Dec 11, 2010 at 07:31:15AM +0100, Heiko Schocher wrote:
> - add binding to OF, compatible name "smi,sm501"
> 
> - add read/write functions for using this driver
>   also on powerpc plattforms
> 
> - add commandline options:
>   sm501.fb_mode:
>     Specify resolution as "<xres>x<yres>[-<bpp>][@<refresh>]"
>   sm501.bpp:
>     Specify bit-per-pixel if not specified mode
> 
> - Add support for encoding display mode information
>   in the device tree using verbatim EDID block.
> 
>   If the "edid" entry in the "smi,sm501" node is present,
>   the driver will build mode database using EDID data
>   and allow setting the display modes from this database.
> 
> Signed-off-by: Heiko Schocher <hs@denx.de>
> cc: linux-fbdev@vger.kernel.org
> cc: devicetree-discuss@ozlabs.org
> cc: Ben Dooks <ben@simtec.co.uk>
> cc: Vincent Sanders <vince@simtec.co.uk>
> cc: Samuel Ortiz <sameo@linux.intel.com>
> cc: linux-kernel@vger.kernel.org
> 
> ---
> - changes since v1:
>   add Ben Dooks, Vincent Sanders and Samuel Ortiz to cc, as suggested from
>   Paul Mundt.
> 
>  Documentation/kernel-parameters.txt          |    7 +
>  Documentation/powerpc/dts-bindings/sm501.txt |   30 +++
>  drivers/mfd/sm501.c                          |  141 ++++++++------
>  drivers/video/sm501fb.c                      |  264 +++++++++++++++++---------
>  include/linux/sm501.h                        |    8 +
>  5 files changed, 299 insertions(+), 151 deletions(-)
>  create mode 100644 Documentation/powerpc/dts-bindings/sm501.txt
> 
So has this stalled out? If Samuel wants to ack the MFD bits I don't mind
taking it through the fbdev tree. I can dust off an SM501 board to make
sure it still works for the non-OF case, although most of the changes
look fairly mechanical, so I don't forsee too much difficulty.

A few minor notes however. For starters, it would be nice to see this
patch split out a bit more logically. All of the items in your changelog
are more or less independent logical changes, and should really be
independent patches. As such, I'd like to see the EDID support as one
patch, the OF binding support layered on top of that, the documentation
split out as a trivial patch, and the I/O routine thing dealt with
separately. This should also make it easier for Samuel to simply ack the
OF bindings part that touch the MFD driver without having to be bothered
with any of the other stuff should regressions pop up at a later point in
time via a bisection.

As far as the DTS bindings documentation goes, I'm not sure what the best
way to split that out is. Perhaps simply lumping it in with the OF
bindings makes the most logical sense, and it's obviously a dependency
for the architecture-specific portion as well.

> @@ -1698,6 +1727,9 @@ static int sm501fb_init_fb(struct fb_info *fb,
>  	fb->fbops = &par->ops;
>  	fb->flags = FBINFO_FLAG_DEFAULT | FBINFO_READS_FAST |
>  		FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT |
> +#if defined(CONFIG_PPC_MPC52xx)
> +		FBINFO_FOREIGN_ENDIAN |
> +#endif
>  		FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN;
>  
>  	/* fixed data */

This is now getting in to deep hack territory. It's also not entirely
obvious how you expect things like the imageblit op to work given that
you're not selecting any of FB_{BIG,LITTLE,BOTH,FOREIGN}_ENDIAN, which
leads me to suspect you are manually doing this in your .config in a
relatively fragile way.

In the OF case I suppose you probably want something like:

#ifdef __BIG_ENDIAN
        if (of_get_property(dp, "little-endian", NULL))
                foreign_endian = FBINFO_FOREIGN_ENDIAN;
#else
        if (of_get_property(dp, "big-endian", NULL))
                foreign_endian = FBINFO_FOREIGN_ENDIAN;
#endif

and then simply hide the details in the DTS file in order to get rid of
CPU-specific hacks.

> +#if defined(CONFIG_PPC_MPC52xx)
> +#define smc501_readl(addr)	__do_readl_be((addr))
> +#define smc501_writel(val, addr)	__do_writel_be((val), (addr))
> +#else
> +#define smc501_readl(addr)		readl(addr)
> +#define smc501_writel(val, addr)	writel(val, addr)
> +#endif

Based on the Kconfig option for endianness you could probably just wrap these
to ioread/write32{,be} and hide the semantics in your iomap implementation?

^ permalink raw reply

* Re: Using s3virge card in Sun Blade 2000
From: Alex Buell @ 2011-01-06  0:33 UTC (permalink / raw)
  To: David Miller; +Cc: linux-fbdev, linux-kernel
In-Reply-To: <1294262022.24378.2.camel@lithium>

On Wed, 2011-01-05 at 21:13 +0000, Alex Buell wrote:

> > Then replace all NULL vga_*() initial arguments in the driver
> > with par->vga_iobase. 
> 
> No wonder it was crashing, there was nothing to access with region 1! I
> will do as you suggest, and see if it works. Thank you!

After doing as you suggested:

	printk(KERN_INFO "s3fb: vga io base = 0x%p\n", par->vga_iobase);

        /* Unlock regs */
        cr38 = vga_rcrt(par->vga_iobase, 0x38);
        cr39 = vga_rcrt(par->vga_iobase, 0x39);
        vga_wseq(par->vga_iobase, 0x08, 0x06);
        vga_wcrt(par->vga_iobase, 0x38, 0x48);
        vga_wcrt(par->vga_iobase, 0x39, 0xA5);

        printk(KERN_INFO "s3fb ok...\n");

The above code seems to work, and crashes after this point:

   	/* Identify chip type */
        par->chip = id->driver_data & CHIP_MASK;
        par->rev = vga_rcrt(par->vga_iobase, 0x2f);
        if (par->chip & CHIP_UNDECIDED_FLAG)
                par->chip = s3_identification(par->chip);

The logs shows:

Jan  5 23:16:29 sodium kernel: s3fb: vga io base = 0x000007ffef000000
Jan  5 23:16:29 sodium kernel: s3fb ok...
Jan  5 23:16:29 sodium kernel: ERROR(0): Cheetah error trap taken
afsr[0030100000000000] afar[00000000000003d0] TL1(0)
Jan  5 23:16:29 sodium kernel: ERROR(0): TPC[10583b54] TNPC[10583b58]
O7[10583a3c] TSTATE[9911001606]
Jan  5 23:16:29 sodium kernel: ERROR(0): TPC<s3_pci_probe+0x410/0x93c
[s3fb]>
Jan  5 23:16:29 sodium kernel: ERROR(0): M_SYND(0),  E_SYND(0), Multiple
Errors, Privileged
Jan  5 23:16:29 sodium kernel: ERROR(0): Highest priority error
(0000100000000000) "Unmapped error from system bus"
Jan  5 23:16:29 sodium kernel: ERROR(0): D-cache idx[0]
tag[0000000000000000] utag[0000000000000000] stag[0000000000000000]
Jan  5 23:16:29 sodium kernel: ERROR(0): D-cache data0[0000000000000000]
data1[0000000000000000] data2[0000000000000000] data3[0000000000000000]
Jan  5 23:16:29 sodium kernel: ERROR(0): I-cache idx[0]
tag[0000000000000000] utag[0000000000000000] stag[0000000000000000]
u[0000000000000000] l[0000000000000000]
Jan  5 23:16:29 sodium kernel: ERROR(0): I-cache INSN0[0000000000000000]
INSN1[0000000000000000] INSN2[0000000000000000] INSN3[0000000000000000]
Jan  5 23:16:29 sodium kernel: ERROR(0): I-cache INSN4[0000000000000000]
INSN5[0000000000000000] INSN6[0000000000000000] INSN7[0000000000000000]
Jan  5 23:16:29 sodium kernel: ERROR(0): E-cache idx[3c0]
tag[0000000002249249]
Jan  5 23:16:29 sodium kernel: ERROR(0): E-cache data0[787072745f756e72]
data1[656769737465725f] data2[7472616e73706f72] data3[7400787072745f72]
Jan  5 23:16:29 sodium kernel: Kernel panic - not syncing: Irrecoverable
deferred error trap.

I'm still thinking that it probably isn't the right io_base if it's
crashing trying to identify the s3 chipset. 
-- 
Tactical Nuclear Kittens

^ permalink raw reply

* Re: Using s3virge card in Sun Blade 2000
From: Alex Buell @ 2011-01-05 21:13 UTC (permalink / raw)
  To: David Miller; +Cc: linux-fbdev, linux-kernel
In-Reply-To: <20110105.110705.104043006.davem@davemloft.net>

On Wed, 2011-01-05 at 11:07 -0800, David Miller wrote:
> > Those are 32 bit addresses, so I suppose I should be getting the
> base
> > address for the registers accesses from region 1, right? 
> 
> Actually, I take back what I said earlier.  Region 1 is a Memory
> region not an I/O region.
> 
> It looks like you'll have to find a way to get at the implicit
> I/O space for the PCI domain this framebuffer is behind and
> construct the implicit VGA addresses by hand.
> 
> There is a way to do this, via pcibios_bus_to_resource().  You could
> do something like:
> 
> struct s3fb_info {
>  ...
>         void __iomem *vga_iobase;
>  ...
> static int __devinit s3_pci_probe(struct pci_dev *dev, const struct
> pci_device_id *id)
> {
>         struct pci_bus_region bus_reg;
>         struct resource vga_res;
>  ...
>         bus_reg.start = 0;
>         bus_reg.end = 64 * 1024;
> 
>         vga_res.flags = IORESOURCE_IO;
> 
>         pcibios_bus_to_resource(dev, &bus_reg, &vga_res);
> 
>         par->vga_iobase = (void __iomem *) vga_res.start;
> 
> Then replace all NULL vga_*() initial arguments in the driver
> with par->vga_iobase. 

No wonder it was crashing, there was nothing to access with region 1! I
will do as you suggest, and see if it works. Thank you!
-- 
Tactical Nuclear Kittens

^ permalink raw reply

* Re: Using s3virge card in Sun Blade 2000
From: Geert Uytterhoeven @ 2011-01-05 20:37 UTC (permalink / raw)
  To: David Miller; +Cc: alex.buell, linux-fbdev, linux-kernel
In-Reply-To: <20110103.105827.112602895.davem@davemloft.net>

On Mon, Jan 3, 2011 at 19:58, David Miller <davem@davemloft.net> wrote:
> From: Alex Buell <alex.buell@munted.org.uk>
> Date: Mon, 03 Jan 2011 16:32:16 +0000
>
>> I'm aware the s3fb driver has big endian issues, I can help fix those
>> issues so I can get the card working. Or in other words, I'd welcome
>> advice on how to proceed with this.
>
> It's not endian issues, this driver has other problems.
>
> It uses the VGA register accessors with a NULL regbase, which is not
> going to work on sparc64.
>
> It needs to access the VGA register space relative to the I/O space
> of the PCI controller domain it is behind.
>
> Probably if you replace the NULL values passes to vga_r*() and
> vga_w*() with the I/O space resource base of the chip (should be
> resource "1") it might work.

Probably s3fb also relies on a card having been initialized by the VGA BIOS.

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply

* Re: Using s3virge card in Sun Blade 2000
From: David Miller @ 2011-01-05 19:07 UTC (permalink / raw)
  To: alex.buell; +Cc: linux-fbdev, linux-kernel
In-Reply-To: <1294090573.17576.16.camel@lithium>

From: Alex Buell <alex.buell@munted.org.uk>
Date: Mon, 03 Jan 2011 21:36:13 +0000

> On Mon, 2011-01-03 at 12:39 -0800, David Miller wrote:
> 
>> > I've just started digging into the innards of the s3fb driver, my first
>> > attempt provoked this, simply by commenting out the check to see if it's
>> > not the primary device and exits with -ENODEV: 
>> > 
>> > Jan  3 20:16:29 sodium kernel: ERROR(1): Cheetah error trap taken
>> > afsr[0030100000000000] afar[00000000000003d0] TL1(0)
>> > Jan  3 20:16:29 sodium kernel: ERROR(1): TPC[105918d8] TNPC[105918dc]
>> > O7[10591884] TSTATE[4411001606]
>> > Jan  3 20:16:29 sodium kernel: ERROR(1): TPC<s3_pci_probe+0x194/0x63c
>> > [s3fb]>
>> > Jan  3 20:16:29 sodium kernel: ERROR(1): M_SYND(0),  E_SYND(0), Multiple
>> > Errors, Privileged
>> 
>> I know, this is what happens if you call vga_*() with a NULL first parameter
>> on sparc64.  It's accessing garbage addresses.
> 
> OK. 
> 
>  # lspci -vvxx -s 0:0:03
> 0000:00:03.0 VGA compatible controller: S3 Inc. ViRGE/DX or /GX (rev 01)
> (prog-if 00 [VGA controller])
>         Subsystem: S3 Inc. ViRGE/DX
>         Physical Slot: PCI 3
>         Control: I/O- Mem+ BusMaster- SpecCycle- MemWINV- VGASnoop-
> ParErr- Stepping- SERR- FastB2B- DisINTx-
>         Status: Cap- 66MHz- UDF- FastB2B- ParErr- DEVSEL=medium >TAbort-
> <TAbort- <MAbort- >SERR- <PERR- INTx-
>         Interrupt: pin A routed to IRQ 23
>         Region 0: Memory at 14000000 (32-bit, non-prefetchable)
> [sizedM]
>         Region 1: [virtual] Memory at fffff80200000000 (32-bit,
> non-prefetchable) [size=1]
>         Region 2: [virtual] Memory at fffff80200000000 (32-bit,
> non-prefetchable) [size=1]
>         Region 3: [virtual] Memory at fffff80200000000 (32-bit,
> non-prefetchable) [size=1]
>         Region 4: [virtual] Memory at fffff80200000000 (32-bit,
> non-prefetchable) [size=1]
>         Region 5: [virtual] Memory at fffff80200000000 (32-bit,
> non-prefetchable) [size=1]
>         Expansion ROM at 00130000 [disabled] [sizedK]
>         Kernel driver in use: s3fb
>         Kernel modules: s3fb
> 00: 33 53 01 8a 02 00 00 02 01 00 00 03 00 40 00 00
> 10: 00 00 00 14 00 00 00 00 00 00 00 00 00 00 00 00
> 20: 00 00 00 00 00 00 00 00 00 00 00 00 33 53 01 8a
> 30: 00 00 13 00 00 00 00 00 00 00 00 00 00 01 04 ff
> 
> Those are 32 bit addresses, so I suppose I should be getting the base
> address for the registers accesses from region 1, right? 

Actually, I take back what I said earlier.  Region 1 is a Memory
region not an I/O region.

It looks like you'll have to find a way to get at the implicit
I/O space for the PCI domain this framebuffer is behind and
construct the implicit VGA addresses by hand.

There is a way to do this, via pcibios_bus_to_resource().  You could
do something like:

struct s3fb_info {
 ...
	void __iomem *vga_iobase;
 ...
static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
	struct pci_bus_region bus_reg;
	struct resource vga_res;
 ...
	bus_reg.start = 0;
	bus_reg.end = 64 * 1024;

	vga_res.flags = IORESOURCE_IO;

	pcibios_bus_to_resource(dev, &bus_reg, &vga_res);

	par->vga_iobase = (void __iomem *) vga_res.start;

Then replace all NULL vga_*() initial arguments in the driver
with par->vga_iobase.

^ permalink raw reply

* [PATCH 2/2] s5pc110: add MIPI-DSI controller driver.
From: Inki Dae @ 2011-01-05 10:35 UTC (permalink / raw)
  To: linux-arm-kernel

S5PC110 and S5PC210 SoC platform have one or two MIPI-DSI controller.
MIPI-DSI controller can be used to connect MIPI-DSI based LCD Panel.
this patch adds MIPI-DSI controller driver.

to use this driver, MIPI-DSI based LCD panel driver have to register
mipi_dsim_lcd_driver object to MIPI-DSI driver and then when MIPI-DSI
driver is probed, probe callback of LCD panel driver registered would
be called.

Signed-off-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 arch/arm/plat-s5p/include/plat/dsim.h      |  357 ++++++++++++++++
 arch/arm/plat-s5p/include/plat/regs-dsim.h |  141 ++++++
 drivers/video/Kconfig                      |    7 +
 drivers/video/Makefile                     |    2 +
 drivers/video/s5p_mipi_dsi.c               |  428 +++++++++++++++++++
 drivers/video/s5p_mipi_dsi_common.c        |  635 ++++++++++++++++++++++++++++
 drivers/video/s5p_mipi_dsi_common.h        |   38 ++
 drivers/video/s5p_mipi_dsi_lowlevel.c      |  553 ++++++++++++++++++++++++
 drivers/video/s5p_mipi_dsi_lowlevel.h      |   98 +++++
 9 files changed, 2259 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/plat-s5p/include/plat/dsim.h
 create mode 100644 arch/arm/plat-s5p/include/plat/regs-dsim.h
 create mode 100644 drivers/video/s5p_mipi_dsi.c
 create mode 100644 drivers/video/s5p_mipi_dsi_common.c
 create mode 100644 drivers/video/s5p_mipi_dsi_common.h
 create mode 100644 drivers/video/s5p_mipi_dsi_lowlevel.c
 create mode 100644 drivers/video/s5p_mipi_dsi_lowlevel.h

diff --git a/arch/arm/plat-s5p/include/plat/dsim.h b/arch/arm/plat-s5p/include/plat/dsim.h
new file mode 100644
index 0000000..9aa5a93
--- /dev/null
+++ b/arch/arm/plat-s5p/include/plat/dsim.h
@@ -0,0 +1,357 @@
+/* linux/arm/arch/plat-s5p/include/plat/dsim.h
+ *
+ * Platform data header for Samsung SoC MIPI-DSIM.
+ *
+ * Copyright (c) 2009 Samsung Electronics
+ * InKi Dae <inki.dae@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef _DSIM_H
+#define _DSIM_H
+
+#include <linux/device.h>
+#include <linux/fb.h>
+
+#define PANEL_NAME_SIZE		(32)
+
+enum mipi_dsim_interface_type {
+	DSIM_COMMAND,
+	DSIM_VIDEO
+};
+
+enum mipi_dsim_virtual_ch_no {
+	DSIM_VIRTUAL_CH_0,
+	DSIM_VIRTUAL_CH_1,
+	DSIM_VIRTUAL_CH_2,
+	DSIM_VIRTUAL_CH_3
+};
+
+enum mipi_dsim_burst_mode_type {
+	DSIM_NON_BURST_SYNC_EVENT,
+	DSIM_NON_BURST_SYNC_PULSE = 2,
+	DSIM_BURST,
+	DSIM_NON_VIDEO_MODE
+};
+
+enum mipi_dsim_no_of_data_lane {
+	DSIM_DATA_LANE_1,
+	DSIM_DATA_LANE_2,
+	DSIM_DATA_LANE_3,
+	DSIM_DATA_LANE_4
+};
+
+enum mipi_dsim_byte_clk_src {
+	DSIM_PLL_OUT_DIV8,
+	DSIM_EXT_CLK_DIV8,
+	DSIM_EXT_CLK_BYPASS
+};
+
+enum mipi_dsim_pixel_format {
+	DSIM_CMD_3BPP,
+	DSIM_CMD_8BPP,
+	DSIM_CMD_12BPP,
+	DSIM_CMD_16BPP,
+	DSIM_VID_16BPP_565,
+	DSIM_VID_18BPP_666PACKED,
+	DSIM_18BPP_666LOOSELYPACKED,
+	DSIM_24BPP_888
+};
+
+/**
+ * struct mipi_dsim_config - interface for configuring mipi-dsi controller.
+ *
+ * @auto_flush: enable or disable Auto flush of MD FIFO using VSYNC pulse.
+ * @eot_disable: enable or disable EoT packet in HS mode.
+ * @auto_vertical_cnt: specifies auto vertical count mode.
+ *	in Video mode, the vertical line transition uses line counter
+ *	configured by VSA, VBP, and Vertical resolution.
+ *	If this bit is set to '1', the line counter does not use VSA and VBP
+ *	registers.(in command mode, this variable is ignored)
+ * @hse: set horizontal sync event mode.
+ *	In VSYNC pulse and Vporch area, MIPI DSI master transfers only HSYNC
+ *	start packet to MIPI DSI slave at MIPI DSI spec1.1r02.
+ *	this bit transfers HSYNC end packet in VSYNC pulse and Vporch area
+ *	(in mommand mode, this variable is ignored)
+ * @hfp: specifies HFP disable mode.
+ *	if this variable is set, DSI master ignores HFP area in VIDEO mode.
+ *	(in command mode, this variable is ignored)
+ * @hbp: specifies HBP disable mode.
+ *	if this variable is set, DSI master ignores HBP area in VIDEO mode.
+ *	(in command mode, this variable is ignored)
+ * @hsa: specifies HSA disable mode.
+ *	if this variable is set, DSI master ignores HSA area in VIDEO mode.
+ *	(in command mode, this variable is ignored)
+ * @e_interface: specifies interface to be used.(CPU or RGB interface)
+ * @e_virtual_ch: specifies virtual channel number that main or
+ *	sub diaplsy uses.
+ * @e_pixel_format: specifies pixel stream format for main or sub display.
+ * @e_burst_mode: selects Burst mode in Video mode.
+ *	in Non-burst mode, RGB data area is filled with RGB data and NULL
+ *	packets, according to input bandwidth of RGB interface.
+ *	In Burst mode, RGB data area is filled with RGB data only.
+ * @e_no_data_lane: specifies data lane count to be used by Master.
+ * @e_byte_clk: select byte clock source. (it must be DSIM_PLL_OUT_DIV8)
+ *	DSIM_EXT_CLK_DIV8 and DSIM_EXT_CLK_BYPASSS are not supported.
+ * @pll_stable_time: specifies the PLL Timer for stability of the ganerated
+ *	clock(System clock cycle base)
+ *	if the timer value goes to 0x00000000, the clock stable bit of status
+ *	and interrupt register is set.
+ * @esc_clk: specifies escape clock frequency for getting the escape clock
+ *	prescaler value.
+ * @stop_holding_cnt: specifies the interval value between transmitting
+ *	read packet(or write "set_tear_on" command) and BTA request.
+ *	after transmitting read packet or write "set_tear_on" command,
+ *	BTA requests to D-PHY automatically. this counter value specifies
+ *	the interval between them.
+ * @bta_timeout: specifies the timer for BTA.
+ *	this register specifies time out from BTA request to change
+ *	the direction with respect to Tx escape clock.
+ * @rx_timeout: specifies the timer for LP Rx mode timeout.
+ *	this register specifies time out on how long RxValid deasserts,
+ *	after RxLpdt asserts with respect to Tx escape clock.
+ *	- RxValid specifies Rx data valid indicator.
+ *	- RxLpdt specifies an indicator that D-PHY is under RxLpdt mode.
+ *	- RxValid and RxLpdt specifies signal from D-PHY.
+ * @lcd_panel_info: pointer for lcd panel specific structure.
+ *	this structure specifies width, height, timing and polarity and so on.
+ * @mipi_ddi_pd: pointer to lcd panel platform data.
+ */
+struct mipi_dsim_config {
+	unsigned char auto_flush;
+	unsigned char eot_disable;
+
+	unsigned char auto_vertical_cnt;
+	unsigned char hse;
+	unsigned char hfp;
+	unsigned char hbp;
+	unsigned char hsa;
+
+	enum mipi_dsim_interface_type	e_interface;
+	enum mipi_dsim_virtual_ch_no	e_virtual_ch;
+	enum mipi_dsim_pixel_format	e_pixel_format;
+	enum mipi_dsim_burst_mode_type	e_burst_mode;
+	enum mipi_dsim_no_of_data_lane	e_no_data_lane;
+	enum mipi_dsim_byte_clk_src	e_byte_clk;
+
+	/*
+	 * =====================+	 * |    P    |    M    |    S    |    MHz    |
+	 * -------------------------------------------
+	 * |    3    |   100   |    3    |    100    |
+	 * |    3    |   100   |    2    |    200    |
+	 * |    3    |    63   |    1    |    252    |
+	 * |    4    |   100   |    1    |    300    |
+	 * |    4    |   110   |    1    |    330    |
+	 * |   12    |   350   |    1    |    350    |
+	 * |    3    |   100   |    1    |    400    |
+	 * |    4    |   150   |    1    |    450    |
+	 * |    3    |   118   |    1    |    472    |
+	 * |   12    |   250   |    0    |    500    |
+	 * |    4    |   100   |    0    |    600    |
+	 * |    3    |    81   |    0    |    648    |
+	 * |    3    |    88   |    0    |    704    |
+	 * |    3    |    90   |    0    |    720    |
+	 * |    3    |   100   |    0    |    800    |
+	 * |   12    |   425   |    0    |    850    |
+	 * |    4    |   150   |    0    |    900    |
+	 * |   12    |   475   |    0    |    950    |
+	 * |    6    |   250   |    0    |   1000    |
+	 * -------------------------------------------
+	 */
+	unsigned char p;
+	unsigned short m;
+	unsigned char s;
+
+	unsigned int pll_stable_time;
+	unsigned long esc_clk;
+
+	unsigned short stop_holding_cnt;
+	unsigned char bta_timeout;
+	unsigned short rx_timeout;
+
+	void *lcd_panel_info;
+	void *dsim_ddi_pd;
+};
+
+/**
+ * struct mipi_dsim_device - global interface for mipi-dsi driver.
+ *
+ * @dev: driver model representation of the device.
+ * @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)
+ * @pd: pointer to MIPI-DSI driver platform data.
+ * @dsim_info: infomation for configuring mipi-dsi controller.
+ * @master_ops: callbacks to mipi-dsi operations.
+ * @lcd_info: pointer to mipi_lcd_info structure.
+ * @state: specifies status of MIPI-DSI controller.
+ *	the status could be RESET, INIT, STOP, HSCLKEN and ULPS.
+ * @resume_complete: indicates whether resume operation is completed or not.
+ * @data_lane: specifiec enabled data lane number.
+ *	this variable would be set by driver according to e_no_data_lane
+ *	automatically.
+ * @e_clk_src: select byte clock source.
+ *	this variable would be set by driver according to e_byte_clock
+ *	automatically.
+ * @hs_clk: HS clock rate.
+ *	this variable would be set by driver automatically.
+ * @byte_clk: Byte clock rate.
+ *	this variable would be set by driver automatically.
+ * @escape_clk: ESCAPE clock rate.
+ *	this variable would be set by driver automatically.
+ * @freq_band: indicates Bitclk frequency band for D-PHY global timing.
+ *	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
+ *	this variable would be calculated by driver automatically.
+ */
+struct mipi_dsim_device {
+	struct device *dev;
+	struct resource *res;
+	struct clk *clock;
+	unsigned int irq;
+	void __iomem *reg_base;
+
+	struct s5p_platform_mipi_dsim *pd;
+	struct mipi_dsim_config *dsim_config;
+	struct mipi_dsim_master_ops *master_ops;
+	struct mipi_dsim_ddi *dsim_ddi;
+
+	unsigned int state;
+	unsigned int resume_complete;
+	unsigned int data_lane;
+	enum mipi_dsim_byte_clk_src e_clk_src;
+	unsigned long hs_clk;
+	unsigned long byte_clk;
+	unsigned long escape_clk;
+	unsigned char freq_band;
+};
+
+/**
+ * struct s5p_platform_mipi_dsim - interface to platform data
+ *	for mipi-dsi driver.
+ *
+ * @lcd_panel_name: specifies lcd panel name registered to mipi-dsi driver.
+ *	lcd panel driver searched would be actived.
+ * @dsim_config: pointer of structure for configuring mipi-dsi controller.
+ * @dsim_lcd_info: pointer to structure for configuring
+ *	mipi-dsi based lcd panel.
+ * @mipi_power: callback pointer for enabling or disabling mipi power.
+ * @part_reset: callback pointer for reseting mipi phy.
+ * @init_d_phy: callback pointer for enabing d_phy of dsi master.
+ * @get_fb_frame_done: callback pointer for getting frame done status of the
+ *	display controller(FIMD).
+ * @trigger: callback pointer for triggering display controller(FIMD)
+ *	in case of CPU mode.
+ * @delay_for_stabilization: specifies stable time.
+ *	this delay needs when writing data on SFR
+ *	after mipi mode became LP mode.
+ */
+struct s5p_platform_mipi_dsim {
+	char	lcd_panel_name[PANEL_NAME_SIZE];
+
+	struct mipi_dsim_config *dsim_config;
+	struct mipi_dsim_lcd_config *dsim_lcd_config;
+
+	unsigned int delay_for_stabilization;
+
+	int (*mipi_power) (struct mipi_dsim_device *dsim, unsigned int enable);
+	int (*part_reset) (struct mipi_dsim_device *dsim);
+	int (*init_d_phy) (struct mipi_dsim_device *dsim);
+	int (*get_fb_frame_done) (struct fb_info *info);
+	void (*trigger) (struct fb_info *info);
+};
+/**
+ * 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.
+ * @change_dsim_transfer_mode: change transfer mode to LP or HS mode.
+ *	- LP mode is used when commands data ard transferred to lcd panel.
+ * @get_fb_frame_done: get frame done status of display controller.
+ * @trigger: trigger display controller.
+ *	- this one would be used only in case of CPU mode.
+ */
+
+struct mipi_dsim_master_ops {
+	int (*cmd_write) (struct mipi_dsim_device *dsim, unsigned int data_id,
+		unsigned int data0, unsigned int data1);
+	int (*cmd_read) (struct mipi_dsim_device *dsim, unsigned int data_id,
+		unsigned int data0, unsigned int data1);
+	int (*get_dsim_frame_done) (struct mipi_dsim_device *dsim);
+	int (*clear_dsim_frame_done) (struct mipi_dsim_device *dsim);
+
+	int (*change_dsim_transfer_mode) (struct mipi_dsim_device *dsim,
+						unsigned int mode);
+
+	int (*get_fb_frame_done) (struct fb_info *info);
+	void (*trigger) (struct fb_info *info);
+};
+
+/**
+ * device structure for mipi-dsi based lcd panel.
+ *
+ * @dev: driver model representation of the device.
+ * @id: id of device registered and when device is registered
+ *	id would be counted.
+ * @modalias: name of the driver to use with this device, or an
+ *	alias for that name.
+ * @mipi_lcd_drv: pointer of mipi_lcd_driver.
+ * @master: pointer to dsim_device.
+ */
+struct mipi_dsim_lcd_device {
+	struct	device	dev;
+	int	id;
+	char	modalias[64];
+
+	struct mipi_dsim_lcd_driver	*dsim_drv;
+	struct mipi_dsim_device		*master;
+};
+
+/**
+ * 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.
+ */
+struct mipi_dsim_lcd_driver {
+	char		*name;
+
+	int	(*probe)(struct mipi_dsim_lcd_device *dsim_dev);
+	int	(*remove)(struct mipi_dsim_lcd_device *dsim_dev);
+	void	(*shutdown)(struct mipi_dsim_lcd_device *dsim_dev);
+	int	(*suspend)(struct mipi_dsim_lcd_device *dsim_dev);
+	int	(*resume)(struct mipi_dsim_lcd_device *dsim_dev);
+};
+
+/**
+ * register mipi_dsim_lcd_driver object defined by lcd panel driver
+ * to mipi-dsi driver.
+ */
+extern int s5p_mipi_dsi_register_lcd_driver(struct mipi_dsim_lcd_driver
+						*lcd_drv);
+
+#endif /* _DSIM_H */
diff --git a/arch/arm/plat-s5p/include/plat/regs-dsim.h b/arch/arm/plat-s5p/include/plat/regs-dsim.h
new file mode 100644
index 0000000..7ef5a2f
--- /dev/null
+++ b/arch/arm/plat-s5p/include/plat/regs-dsim.h
@@ -0,0 +1,141 @@
+/* linux/arch/arm/plat-s5p/include/plat/regs-dsim.h
+ *
+ * Register definition file for Samsung MIPI-DSIM driver
+ *
+ * InKi Dae <inki.dae@samsung.com>, Copyright (c) 2009 Samsung Electronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef _REGS_DSIM_H
+#define _REGS_DSIM_H
+
+#define S5P_DSIM_STATUS		(0x0)	/* Status register */
+#define S5P_DSIM_SWRST		(0x4)	/* Software reset register */
+#define S5P_DSIM_CLKCTRL	(0x8)	/* Clock control register */
+#define S5P_DSIM_TIMEOUT	(0xc)	/* Time out register */
+#define S5P_DSIM_CONFIG		(0x10)	/* Configuration register */
+#define S5P_DSIM_ESCMODE	(0x14)	/* Escape mode register */
+
+/* Main display image resolution register */
+#define S5P_DSIM_MDRESOL	(0x18)
+#define S5P_DSIM_MVPORCH	(0x1c)	/* Main display Vporch register */
+#define S5P_DSIM_MHPORCH	(0x20)	/* Main display Hporch register */
+#define S5P_DSIM_MSYNC		(0x24)	/* Main display sync area register */
+
+/* Sub display image resolution register */
+#define S5P_DSIM_SDRESOL	(0x28)
+#define S5P_DSIM_INTSRC		(0x2c)	/* Interrupt source register */
+#define S5P_DSIM_INTMSK		(0x30)	/* Interrupt mask register */
+#define S5P_DSIM_PKTHDR		(0x34)	/* Packet Header FIFO register */
+#define S5P_DSIM_PAYLOAD	(0x38)	/* Payload FIFO register */
+#define S5P_DSIM_RXFIFO		(0x3c)	/* Read FIFO register */
+#define S5P_DSIM_FIFOTHLD	(0x40)	/* FIFO threshold level register */
+#define S5P_DSIM_FIFOCTRL	(0x44)	/* FIFO status and control register */
+
+/* FIFO memory AC characteristic register */
+#define S5P_DSIM_PLLCTRL	(0x4c)	/* PLL control register */
+#define S5P_DSIM_PLLTMR		(0x50)	/* PLL timer register */
+#define S5P_DSIM_PHYACCHR	(0x54)	/* D-PHY AC characteristic register */
+#define S5P_DSIM_PHYACCHR1	(0x58)	/* D-PHY AC characteristic register1 */
+
+/* DSIM_STATUS */
+#define DSIM_STOP_STATE_DAT(x)	(((x) & 0xf) << 0)
+#define DSIM_STOP_STATE_CLK	(1 << 8)
+#define DSIM_TX_READY_HS_CLK	(1 << 10)
+
+/* DSIM_SWRST */
+#define DSIM_FUNCRST		(1 << 16)
+#define DSIM_SWRST		(1 << 0)
+
+/* S5P_DSIM_TIMEOUT */
+#define DSIM_LPDR_TOUT_SHIFT	(0)
+#define DSIM_BTA_TOUT_SHIFT	(16)
+
+/* S5P_DSIM_CLKCTRL */
+#define DSIM_LANE_ESC_CLKEN_SHIFT	(19)
+#define DSIM_BYTE_CLKEN_SHIFT		(24)
+#define DSIM_BYTE_CLK_SRC_SHIFT		(25)
+#define DSIM_PLL_BYPASS_SHIFT		(27)
+#define DSIM_ESC_CLKEN_SHIFT		(28)
+#define DSIM_TX_REQUEST_HSCLK_SHIFT	(31)
+#define DSIM_LANE_ESC_CLKEN(x)		(((x) & 0x1f) << \
+						DSIM_LANE_ESC_CLKEN_SHIFT)
+#define DSIM_BYTE_CLK_ENABLE		(1 << DSIM_BYTE_CLKEN_SHIFT)
+#define DSIM_BYTE_CLK_DISABLE		(0 << DSIM_BYTE_CLKEN_SHIFT)
+#define DSIM_PLL_BYPASS_EXTERNAL	(1 << DSIM_PLL_BYPASS_SHIFT)
+#define DSIM_ESC_CLKEN_ENABLE		(1 << DSIM_ESC_CLKEN_SHIFT)
+#define DSIM_ESC_CLKEN_DISABLE		(0 << DSIM_ESC_CLKEN_SHIFT)
+
+/* S5P_DSIM_CONFIG */
+#define DSIM_NUM_OF_DATALANE_SHIFT	(5)
+#define DSIM_HSA_MODE_SHIFT		(20)
+#define DSIM_HBP_MODE_SHIFT		(21)
+#define DSIM_HFP_MODE_SHIFT		(22)
+#define DSIM_HSE_MODE_SHIFT		(23)
+#define DSIM_AUTO_MODE_SHIFT		(24)
+#define DSIM_LANE_ENx(x)		(((x) & 0x1f) << 0)
+
+#define DSIM_NUM_OF_DATA_LANE(x)	((x) << DSIM_NUM_OF_DATALANE_SHIFT)
+
+/* S5P_DSIM_ESCMODE */
+#define DSIM_TX_LPDT_SHIFT		(6)
+#define DSIM_CMD_LPDT_SHIFT		(7)
+#define DSIM_TX_LPDT_LP			(1 << DSIM_TX_LPDT_SHIFT)
+#define DSIM_CMD_LPDT_LP		(1 << DSIM_CMD_LPDT_SHIFT)
+#define DSIM_STOP_STATE_CNT_SHIFT	(21)
+#define DSIM_FORCE_STOP_STATE_SHIFT	(20)
+
+/* S5P_DSIM_MDRESOL */
+#define DSIM_MAIN_STAND_BY		(1 << 31)
+#define DSIM_MAIN_VRESOL(x)		(((x) & 0x7ff) << 16)
+#define DSIM_MAIN_HRESOL(x)		(((x) & 0X7ff) << 0)
+
+/* S5P_DSIM_MVPORCH */
+#define DSIM_CMD_ALLOW_SHIFT		(28)
+#define DSIM_STABLE_VFP_SHIFT		(16)
+#define DSIM_MAIN_VBP_SHIFT		(0)
+#define DSIM_CMD_ALLOW_MASK		(0xf << DSIM_CMD_ALLOW_SHIFT)
+#define DSIM_STABLE_VFP_MASK		(0x7ff << DSIM_STABLE_VFP_SHIFT)
+#define DSIM_MAIN_VBP_MASK		(0x7ff << DSIM_MAIN_VBP_SHIFT)
+
+/* S5P_DSIM_MHPORCH */
+#define DSIM_MAIN_HFP_SHIFT		(16)
+#define DSIM_MAIN_HBP_SHIFT		(0)
+#define DSIM_MAIN_HFP_MASK		((0xffff) << DSIM_MAIN_HFP_SHIFT)
+#define DSIM_MAIN_HBP_MASK		((0xffff) << DSIM_MAIN_HBP_SHIFT)
+
+/* S5P_DSIM_MSYNC */
+#define DSIM_MAIN_VSA_SHIFT		(22)
+#define DSIM_MAIN_HSA_SHIFT		(0)
+#define DSIM_MAIN_VSA_MASK		((0x3ff) << DSIM_MAIN_VSA_SHIFT)
+#define DSIM_MAIN_HSA_MASK		((0xffff) << DSIM_MAIN_HSA_SHIFT)
+
+/* S5P_DSIM_SDRESOL */
+#define DSIM_SUB_STANDY_SHIFT		(31)
+#define DSIM_SUB_VRESOL_SHIFT		(16)
+#define DSIM_SUB_HRESOL_SHIFT		(0)
+#define DSIM_SUB_STANDY_MASK		((0x1) << DSIM_SUB_STANDY_SHIFT)
+#define DSIM_SUB_VRESOL_MASK		((0x7ff) << DSIM_SUB_VRESOL_SHIFT)
+#define DSIM_SUB_HRESOL_MASK		((0x7ff) << DSIM_SUB_HRESOL_SHIFT)
+
+/* S5P_DSIM_INTSRC */
+#define INTSRC_FRAME_DONE		(1 << 24)
+#define INTSRC_PLL_STABLE		(1 << 31)
+
+/* S5P_DSIM_INTMSK */
+#define INTMSK_FRAME_DONE		(1 << 24)
+
+/* S5P_DSIM_FIFOCTRL */
+#define SFR_HEADER_EMPTY		(1 << 22)
+
+/* S5P_DSIM_PHYACCHR */
+#define DSIM_AFC_CTL(x)			(((x) & 0x7) << 5)
+
+/* S5P_DSIM_PLLCTRL */
+#define DSIM_PLL_EN_SHIFT		(23)
+#define DSIM_FREQ_BAND_SHIFT		(24)
+
+#endif /* _REGS_DSIM_H */
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 932e7bb..9744e32 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -2098,6 +2098,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
+	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 36aca21..12052a2 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -119,6 +119,8 @@ obj-$(CONFIG_FB_SH7760)		  += sh7760fb.o
 obj-$(CONFIG_FB_IMX)              += imxfb.o
 obj-$(CONFIG_FB_S3C)		  += s3c-fb.o
 obj-$(CONFIG_FB_S3C2410)	  += s3c2410fb.o
+obj-$(CONFIG_S5P_MIPI_DSI)	  += s5p_mipi_dsi.o s5p_mipi_dsi_common.o \
+				     s5p_mipi_dsi_lowlevel.o
 obj-$(CONFIG_FB_FSL_DIU)	  += fsl-diu-fb.o
 obj-$(CONFIG_FB_COBALT)           += cobalt_lcdfb.o
 obj-$(CONFIG_FB_PNX4008_DUM)	  += pnx4008/
diff --git a/drivers/video/s5p_mipi_dsi.c b/drivers/video/s5p_mipi_dsi.c
new file mode 100644
index 0000000..0bd9a44
--- /dev/null
+++ b/drivers/video/s5p_mipi_dsi.c
@@ -0,0 +1,428 @@
+/* linux/drivers/video/s5p_mipi_dsi.c
+ *
+ * Samsung SoC MIPI-DSIM driver.
+ *
+ * InKi Dae, <inki.dae@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/clk.h>
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/fb.h>
+#include <linux/ctype.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/memory.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/kthread.h>
+#include <linux/regulator/consumer.h>
+#include <linux/notifier.h>
+
+#include <plat/fb.h>
+#include <plat/regs-dsim.h>
+#include <plat/dsim.h>
+
+#include <mach/map.h>
+
+#include "s5p_mipi_dsi_common.h"
+
+#define master_to_driver(a)	(a->dsim_ddi->dsim_lcd_drv)
+#define master_to_device(a)	(a->dsim_ddi->dsim_lcd_dev)
+#define set_master_to_device(a)	(a->dsim_ddi->dsim_lcd_dev->master = a)
+
+struct mipi_dsim_ddi {
+	struct list_head		list;
+	struct mipi_dsim_lcd_driver	*dsim_lcd_drv;
+	struct mipi_dsim_lcd_device	*dsim_lcd_dev;
+};
+
+static LIST_HEAD(dsim_ddi_list);
+static DEFINE_MUTEX(mipi_lock);
+
+static struct s5p_platform_mipi_dsim *to_dsim_plat(struct platform_device *pdev)
+{
+	return (struct s5p_platform_mipi_dsim *)pdev->dev.platform_data;
+}
+
+static irqreturn_t s5p_mipi_dsi_interrupt_handler(int irq, void *dev_id)
+{
+	return IRQ_HANDLED;
+}
+
+int s5p_mipi_dsi_register_lcd_driver(struct mipi_dsim_lcd_driver *lcd_drv)
+{
+	struct mipi_dsim_ddi *dsim_ddi;
+	struct mipi_dsim_lcd_device *dsim_lcd_dev;
+	static unsigned int id;
+	int ret;
+
+	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_drv = lcd_drv;
+
+	dsim_lcd_dev = kzalloc(sizeof(struct mipi_dsim_lcd_device), GFP_KERNEL);
+	if (!dsim_lcd_dev) {
+		printk(KERN_ERR "failed to allocate dsim_lcd_dev object.\n");
+		ret = -EFAULT;
+		goto err_dsim;
+	}
+
+	mutex_lock(&mipi_lock);
+
+	dsim_lcd_dev->id = id++;
+	dsim_ddi->dsim_lcd_dev = dsim_lcd_dev;
+
+	device_initialize(&dsim_lcd_dev->dev);
+
+	strcpy(dsim_lcd_dev->modalias, lcd_drv->name);
+
+	dev_set_name(&dsim_lcd_dev->dev, "mipi-dsi.%d\n", dsim_lcd_dev->id);
+
+	ret = device_add(&dsim_lcd_dev->dev);
+	if (ret < 0) {
+		printk(KERN_ERR "can't %s %s, status %d\n",
+				"add", dev_name(&dsim_lcd_dev->dev), ret);
+		id--;
+		goto err_device_add;
+	}
+
+	list_add_tail(&dsim_ddi->list, &dsim_ddi_list);
+
+	mutex_unlock(&mipi_lock);
+
+	printk(KERN_DEBUG "registered panel driver(%s) to mipi-dsi driver.\n",
+		lcd_drv->name);
+
+	return ret;
+
+err_device_add:
+	kfree(dsim_lcd_dev);
+
+err_dsim:
+	kfree(dsim_ddi);
+
+	return ret;
+}
+
+/*
+ * This function is a wrapper for changing transfer mode.
+ * It is used for the panel driver before and after changing gamma value.
+ */
+static int s5p_mipi_dsi_change_transfer_mode(struct mipi_dsim_device *dsim,
+		unsigned int mode)
+{
+	if (mode < 0 || mode > 1) {
+		dev_err(dsim->dev, "mode range should be 0 or 1.\n");
+		return -EINVAL;
+	}
+
+	s5p_mipi_dsi_set_data_transfer_mode(dsim, mode);
+
+	return 0;
+}
+
+static struct mipi_dsim_ddi *find_mipi_client_registered
+		(struct mipi_dsim_device *dsim, const char *name)
+{
+	struct mipi_dsim_ddi *dsim_ddi;
+	struct mipi_dsim_lcd_driver *dsim_lcd_drv = NULL;
+
+	mutex_lock(&mipi_lock);
+
+	dev_dbg(dsim->dev, "find lcd panel driver(%s).\n",
+		name);
+
+	list_for_each_entry(dsim_ddi, &dsim_ddi_list, list) {
+		dsim_lcd_drv = dsim_ddi->dsim_lcd_drv;
+
+		if ((strcmp(dsim_lcd_drv->name, name)) = 0) {
+			mutex_unlock(&mipi_lock);
+			dev_dbg(dsim->dev, "found!!!(%s).\n",
+				dsim_lcd_drv->name);
+			return dsim_ddi;
+		}
+	}
+
+	dev_warn(dsim->dev, "failed to find lcd panel driver(%s).\n",
+		name);
+
+	mutex_unlock(&mipi_lock);
+
+	return NULL;
+}
+
+/* define MIPI-DSI Master operations. */
+static struct mipi_dsim_master_ops master_ops = {
+	.cmd_write			= s5p_mipi_dsi_wr_data,
+	.get_dsim_frame_done		= s5p_mipi_dsi_get_frame_done_status,
+	.clear_dsim_frame_done		= s5p_mipi_dsi_clear_frame_done,
+	.change_dsim_transfer_mode	= s5p_mipi_dsi_change_transfer_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 s5p_platform_mipi_dsim *dsim_pd;
+	int ret = -1;
+
+	dsim = kzalloc(sizeof(struct mipi_dsim_device), GFP_KERNEL);
+	if (!dsim) {
+		dev_err(&pdev->dev, "failed to allocate dsim object.\n");
+		return -EFAULT;
+	}
+
+	dsim->pd = to_dsim_plat(pdev);
+	dsim->dev = &pdev->dev;
+	dsim->resume_complete = 0;
+
+	/* get s5p_platform_mipi_dsim. */
+	dsim_pd = (struct s5p_platform_mipi_dsim *)dsim->pd;
+	/* get mipi_dsim_config. */
+	dsim_config = dsim_pd->dsim_config;
+	dsim->dsim_config = dsim_config;
+	dsim->master_ops = &master_ops;
+
+	dsim->clock = clk_get(&pdev->dev, "dsim");
+	if (IS_ERR(dsim->clock)) {
+		dev_err(&pdev->dev, "failed to get dsim clock source\n");
+		goto err_clock_get;
+	}
+
+	clk_enable(dsim->clock);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "failed to get io memory region\n");
+		ret = -EINVAL;
+		goto err_platform_get;
+	}
+
+	res = request_mem_region(res->start, resource_size(res),
+					dev_name(&pdev->dev));
+	if (!res) {
+		dev_err(&pdev->dev, "failed to request io memory region\n");
+		ret = -EINVAL;
+		goto err_mem_region;
+	}
+
+	dsim->res = res;
+
+	dsim->reg_base = ioremap(res->start, resource_size(res));
+	if (!dsim->reg_base) {
+		dev_err(&pdev->dev, "failed to remap io region\n");
+		ret = -EINVAL;
+		goto err_mem_region;
+	}
+
+	/*
+	 * it uses frame done interrupt handler
+	 * only in case of MIPI Video mode.
+	 */
+	if (dsim_config->e_interface = DSIM_VIDEO) {
+		dsim->irq = platform_get_irq(pdev, 0);
+		if (request_irq(dsim->irq, s5p_mipi_dsi_interrupt_handler,
+				IRQF_DISABLED, "mipi-dsi", dsim)) {
+			dev_err(&pdev->dev, "request_irq failed.\n");
+			goto err_trigger_irq;
+		}
+	}
+
+	if (dsim->pd->mipi_power)
+		dsim->pd->mipi_power(dsim, 1);
+	else {
+		dev_err(&pdev->dev, "mipi_power is NULL.\n");
+		goto err_mipi_power;
+	}
+
+	/* find lcd panel driver registered to mipi-dsi driver. */
+	dsim->dsim_ddi = find_mipi_client_registered(dsim,
+				dsim_pd->lcd_panel_name);
+	if (dsim->dsim_config = NULL) {
+		dev_err(&pdev->dev, "dsim_config is NULL.\n");
+		goto err_dsim_config;
+	}
+
+	/* set dsim to master of mipi_dsim_lcd_device. */
+	set_master_to_device(dsim);
+
+	s5p_mipi_dsi_init_dsim(dsim);
+	s5p_mipi_dsi_init_link(dsim);
+
+	s5p_mipi_dsi_set_hs_enable(dsim);
+	/* set cpu command transfer mode to hs. */
+	s5p_mipi_dsi_set_data_transfer_mode(dsim, 0);
+
+	/* initialize mipi-dsi client(lcd panel). */
+	if (master_to_driver(dsim) && (master_to_driver(dsim))->probe)
+		(master_to_driver(dsim))->probe(master_to_device(dsim));
+
+	/* it needs delay for stabilization */
+	mdelay(dsim->pd->delay_for_stabilization);
+
+	s5p_mipi_dsi_set_display_mode(dsim, dsim->dsim_config);
+
+	/* set lcdc data transfer mode to hs. */
+	s5p_mipi_dsi_set_data_transfer_mode(dsim, 1);
+
+	/* in case of command mode, trigger. */
+	if (dsim->dsim_config->e_interface = DSIM_COMMAND) {
+		if (dsim_pd->trigger)
+			dsim_pd->trigger(registered_fb[0]);
+		else
+			dev_warn(&pdev->dev, "trigger is null.\n");
+	}
+
+	platform_set_drvdata(pdev, dsim);
+
+	dev_info(&pdev->dev, "mipi-dsi driver(%s mode) has been probed.\n",
+		(dsim_config->e_interface = DSIM_COMMAND) ?
+			"CPU" : "RGB");
+
+	return 0;
+
+err_dsim_config:
+	dsim->pd->mipi_power(dsim, 0);
+
+err_mipi_power:
+err_trigger_irq:
+	release_resource(dsim->res);
+	kfree(dsim->res);
+
+	iounmap((void __iomem *) dsim->reg_base);
+
+err_mem_region:
+err_platform_get:
+	clk_disable(dsim->clock);
+	clk_put(dsim->clock);
+
+err_clock_get:
+	kfree(dsim);
+
+	return ret;
+
+}
+
+static int __devexit s5p_mipi_dsi_remove(struct platform_device *pdev)
+{
+	struct mipi_dsim_device *dsim = platform_get_drvdata(pdev);
+	struct mipi_dsim_ddi *dsim_ddi = NULL;
+
+	if (dsim->dsim_config->e_interface = DSIM_VIDEO)
+		free_irq(dsim->irq, dsim);
+
+	iounmap(dsim->reg_base);
+
+	clk_disable(dsim->clock);
+	clk_put(dsim->clock);
+
+	release_resource(dsim->res);
+	kfree(dsim->res);
+
+	list_for_each_entry(dsim_ddi, &dsim_ddi_list, list)
+		kfree(dsim_ddi);
+
+	kfree(dsim);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int s5p_mipi_dsi_suspend(struct platform_device *pdev,
+		pm_message_t state)
+{
+	struct mipi_dsim_device *dsim = platform_get_drvdata(pdev);
+
+	dsim->resume_complete = 0;
+
+	if (master_to_driver(dsim) && (master_to_driver(dsim))->suspend)
+		(master_to_driver(dsim))->suspend(master_to_device(dsim));
+
+	clk_disable(dsim->clock);
+
+	if (dsim->pd->mipi_power)
+		dsim->pd->mipi_power(dsim, 0);
+
+	return 0;
+}
+
+static int s5p_mipi_dsi_resume(struct platform_device *pdev)
+{
+	struct mipi_dsim_device *dsim = platform_get_drvdata(pdev);
+
+	if (dsim->pd->mipi_power)
+		dsim->pd->mipi_power(dsim, 1);
+
+	clk_enable(dsim->clock);
+
+	s5p_mipi_dsi_init_dsim(dsim);
+	s5p_mipi_dsi_init_link(dsim);
+
+	s5p_mipi_dsi_set_hs_enable(dsim);
+	/* set cpu command transfer mode to hs. */
+	s5p_mipi_dsi_set_data_transfer_mode(dsim, 0);
+
+	/* it needs delay for stabilization */
+	mdelay(dsim->pd->delay_for_stabilization);
+
+	if (master_to_driver(dsim) && (master_to_driver(dsim))->resume)
+		(master_to_driver(dsim))->resume(master_to_device(dsim));
+
+	s5p_mipi_dsi_set_display_mode(dsim, dsim->dsim_config);
+
+	/* set lcdc data transfer mode to hs. */
+	s5p_mipi_dsi_set_data_transfer_mode(dsim, 1);
+
+	dsim->resume_complete = 1;
+
+	return 0;
+}
+#else
+#define s5p_mipi_dsi_suspend NULL
+#define s5p_mipi_dsi_resume NULL
+#endif
+
+static struct platform_driver s5p_mipi_dsi_driver = {
+	.probe = s5p_mipi_dsi_probe,
+	.remove = __devexit_p(s5p_mipi_dsi_remove),
+	.suspend = s5p_mipi_dsi_suspend,
+	.resume = s5p_mipi_dsi_resume,
+	.driver = {
+		   .name = "s5p-mipi-dsim",
+		   .owner = THIS_MODULE,
+	},
+};
+
+static int s5p_mipi_dsi_register(void)
+{
+	platform_driver_register(&s5p_mipi_dsi_driver);
+
+	return 0;
+}
+
+static void s5p_mipi_dsi_unregister(void)
+{
+	platform_driver_unregister(&s5p_mipi_dsi_driver);
+}
+
+module_init(s5p_mipi_dsi_register);
+module_exit(s5p_mipi_dsi_unregister);
+
+MODULE_AUTHOR("InKi Dae <inki.dae@samsung.com>");
+MODULE_DESCRIPTION("Samusung 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..cb5c280
--- /dev/null
+++ b/drivers/video/s5p_mipi_dsi_common.c
@@ -0,0 +1,635 @@
+/* linux/drivers/video/s5p_mipi_dsi_common.c
+ *
+ * Samsung MIPI-DSI common driver.
+ *
+ * InKi Dae, <inki.dae@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/fb.h>
+#include <linux/ctype.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/memory.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+
+#include <video/mipi_display.h>
+
+#include <plat/fb.h>
+#include <plat/regs-dsim.h>
+
+#include <mach/map.h>
+#include <plat/dsim.h>
+#include <plat/regs-dsim.h>
+
+#include "s5p_mipi_dsi_lowlevel.h"
+
+#define MHZ			(1000 * 1000)
+#define FIN_HZ			(24 * MHZ)
+
+#define DFIN_PLL_MIN_HZ		(6 * MHZ)
+#define DFIN_PLL_MAX_HZ		(12 * MHZ)
+
+#define DFVCO_MIN_HZ		(500 * MHZ)
+#define DFVCO_MAX_HZ		(1000 * MHZ)
+
+#define TRY_GET_FIFO_TIMEOUT	(5000 * 2)
+
+#define DSIM_ESCCLK_ON		(0x0)
+#define DSIM_ESCCLK_OFF		(0x1)
+
+/* MIPI-DSIM status types. */
+enum {
+	DSIM_STATE_INIT,	/* should be initialized. */
+	DSIM_STATE_STOP,	/* CPU and LCDC are LP mode. */
+	DSIM_STATE_HSCLKEN,	/* HS clock was enabled. */
+	DSIM_STATE_ULPS
+};
+
+/* define DSI lane types. */
+enum {
+	DSIM_LANE_CLOCK = (1 << 0),
+	DSIM_LANE_DATA0 = (1 << 1),
+	DSIM_LANE_DATA1 = (1 << 2),
+	DSIM_LANE_DATA2 = (1 << 3),
+	DSIM_LANE_DATA3 = (1 << 4)
+};
+
+static unsigned int dpll_table[15] = {
+	100, 120, 170, 220, 270,
+	320, 390, 450, 510, 560,
+	640, 690, 770, 870, 950 };
+
+static void s5p_mipi_dsi_long_data_wr(struct mipi_dsim_device *dsim,
+		unsigned int data0, unsigned int data1)
+{
+	unsigned int data_cnt = 0, payload = 0;
+
+	/* in case that data count is more then 4 */
+	for (data_cnt = 0; data_cnt < data1; data_cnt += 4) {
+		/*
+		 * after sending 4bytes per one time,
+		 * send remainder data less then 4.
+		 */
+		if ((data1 - data_cnt) < 4) {
+			if ((data1 - data_cnt) = 3) {
+				payload = *(u8 *)(data0 + data_cnt) |
+				    (*(u8 *)(data0 + (data_cnt + 1))) << 8 |
+					(*(u8 *)(data0 + (data_cnt + 2))) << 16;
+			dev_dbg(dsim->dev, "count = 3 payload = %x, %x %x %x\n",
+				payload, *(u8 *)(data0 + data_cnt),
+				*(u8 *)(data0 + (data_cnt + 1)),
+				*(u8 *)(data0 + (data_cnt + 2)));
+			} else if ((data1 - data_cnt) = 2) {
+				payload = *(u8 *)(data0 + data_cnt) |
+					(*(u8 *)(data0 + (data_cnt + 1))) << 8;
+			dev_dbg(dsim->dev,
+				"count = 2 payload = %x, %x %x\n", payload,
+				*(u8 *)(data0 + data_cnt),
+				*(u8 *)(data0 + (data_cnt + 1)));
+			} else if ((data1 - data_cnt) = 1) {
+				payload = *(u8 *)(data0 + data_cnt);
+			}
+
+			s5p_mipi_dsi_wr_tx_data(dsim, payload);
+		/* send 4bytes per one time. */
+		} else {
+			payload = *(u8 *)(data0 + data_cnt) |
+				(*(u8 *)(data0 + (data_cnt + 1))) << 8 |
+				(*(u8 *)(data0 + (data_cnt + 2))) << 16 |
+				(*(u8 *)(data0 + (data_cnt + 3))) << 24;
+
+			dev_dbg(dsim->dev,
+				"count = 4 payload = %x, %x %x %x %x\n",
+				payload, *(u8 *)(data0 + data_cnt),
+				*(u8 *)(data0 + (data_cnt + 1)),
+				*(u8 *)(data0 + (data_cnt + 2)),
+				*(u8 *)(data0 + (data_cnt + 3)));
+
+			s5p_mipi_dsi_wr_tx_data(dsim, payload);
+		}
+	}
+}
+
+int s5p_mipi_dsi_wr_data(struct mipi_dsim_device *dsim, unsigned int data_id,
+	unsigned int data0, unsigned int data1)
+{
+	unsigned int timeout = TRY_GET_FIFO_TIMEOUT;
+	unsigned long delay_val, udelay;
+	unsigned int check_rx_ack = 0;
+
+	if (dsim->state = DSIM_STATE_ULPS) {
+		dev_err(dsim->dev, "state is ULPS.\n");
+
+		return -EINVAL;
+	}
+
+	delay_val = MHZ / dsim->dsim_config->esc_clk;
+	udelay = 10 * delay_val;
+
+	mdelay(udelay);
+
+	/* only if transfer mode is LPDT, wait SFR becomes empty. */
+	if (dsim->state = DSIM_STATE_STOP) {
+		while (!(s5p_mipi_dsi_get_fifo_state(dsim) &
+				SFR_HEADER_EMPTY)) {
+			if ((timeout--) > 0)
+				mdelay(1);
+			else {
+				dev_err(dsim->dev,
+					"SRF header fifo is not empty.\n");
+				return -EINVAL;
+			}
+		}
+	}
+
+	switch (data_id) {
+	/* short packet types of packet types for command. */
+	case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM:
+	case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM:
+	case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM:
+	case MIPI_DSI_DCS_SHORT_WRITE:
+	case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
+	case MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE:
+		s5p_mipi_dsi_wr_tx_header(dsim, data_id, data0, data1);
+		if (check_rx_ack)
+			/* process response func should be implemented */
+			return 0;
+		else
+			return -EINVAL;
+
+	/* general command */
+	case MIPI_DSI_COLOR_MODE_OFF:
+	case MIPI_DSI_COLOR_MODE_ON:
+	case MIPI_DSI_SHUTDOWN_PERIPHERAL:
+	case MIPI_DSI_TURN_ON_PERIPHERAL:
+		s5p_mipi_dsi_wr_tx_header(dsim, data_id, data0, data1);
+		if (check_rx_ack)
+			/* process response func should be implemented. */
+			return 0;
+		else
+			return -EINVAL;
+
+	/* packet types for video data */
+	case MIPI_DSI_V_SYNC_START:
+	case MIPI_DSI_V_SYNC_END:
+	case MIPI_DSI_H_SYNC_START:
+	case MIPI_DSI_H_SYNC_END:
+	case MIPI_DSI_END_OF_TRANSMISSION:
+		return 0;
+
+	/* short and response packet types for command */
+	case MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM:
+	case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM:
+	case MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM:
+	case MIPI_DSI_DCS_READ:
+		s5p_mipi_dsi_clear_all_interrupt(dsim);
+		s5p_mipi_dsi_wr_tx_header(dsim, data_id, data0, data1);
+		/* process response func should be implemented. */
+		return 0;
+
+	/* long packet type and null packet */
+	case MIPI_DSI_NULL_PACKET:
+	case MIPI_DSI_BLANKING_PACKET:
+		return 0;
+	case MIPI_DSI_GENERIC_LONG_WRITE:
+	case MIPI_DSI_DCS_LONG_WRITE:
+	{
+		unsigned int size, data_cnt = 0, payload = 0;
+
+		size = data1 * 4;
+
+		/* if data count is less then 4, then send 3bytes data.  */
+		if (data1 < 4) {
+			payload = *(u8 *)(data0) |
+				*(u8 *)(data0 + 1) << 8 |
+				*(u8 *)(data0 + 2) << 16;
+
+			s5p_mipi_dsi_wr_tx_data(dsim, payload);
+
+			dev_dbg(dsim->dev, "count = %d payload = %x,%x %x %x\n",
+				data1, payload,
+				*(u8 *)(data0 + data_cnt),
+				*(u8 *)(data0 + (data_cnt + 1)),
+				*(u8 *)(data0 + (data_cnt + 2)));
+		/* in case that data count is more then 4 */
+		} else
+			s5p_mipi_dsi_long_data_wr(dsim, data0, data1);
+
+		/* put data into header fifo */
+		s5p_mipi_dsi_wr_tx_header(dsim, data_id, data1 & 0xff,
+			(data1 & 0xff00) >> 8);
+
+	}
+	if (check_rx_ack)
+		/* process response func should be implemented. */
+		return 0;
+	else
+		return -EINVAL;
+
+	/* packet typo for video data */
+	case MIPI_DSI_PACKED_PIXEL_STREAM_16:
+	case MIPI_DSI_PACKED_PIXEL_STREAM_18:
+	case MIPI_DSI_PIXEL_STREAM_3BYTE_18:
+	case MIPI_DSI_PACKED_PIXEL_STREAM_24:
+		if (check_rx_ack)
+			/* process response func should be implemented. */
+			return 0;
+		else
+			return -EINVAL;
+	default:
+		dev_warn(dsim->dev,
+			"data id %x is not supported current DSI spec.\n",
+			data_id);
+
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+int s5p_mipi_dsi_pll_on(struct mipi_dsim_device *dsim, unsigned int enable)
+{
+	int sw_timeout;
+
+	if (enable) {
+		sw_timeout = 1000;
+
+		s5p_mipi_dsi_clear_interrupt(dsim);
+		s5p_mipi_dsi_enable_pll(dsim, 1);
+		while (1) {
+			sw_timeout--;
+			if (s5p_mipi_dsi_is_pll_stable(dsim))
+				return 0;
+			if (sw_timeout = 0)
+				return -EINVAL;
+		}
+	} else
+		s5p_mipi_dsi_enable_pll(dsim, 0);
+
+	return 0;
+}
+
+unsigned long s5p_mipi_dsi_change_pll(struct mipi_dsim_device *dsim,
+	unsigned int pre_divider, unsigned int main_divider,
+	unsigned int scaler)
+{
+	unsigned long dfin_pll, dfvco, dpll_out;
+	unsigned int i, freq_band = 0xf;
+
+	dfin_pll = (FIN_HZ / pre_divider);
+
+	if (dfin_pll < DFIN_PLL_MIN_HZ || dfin_pll > DFIN_PLL_MAX_HZ) {
+		dev_warn(dsim->dev, "fin_pll range should be 6MHz ~ 12MHz\n");
+		s5p_mipi_dsi_enable_afc(dsim, 0, 0);
+	} else {
+		if (dfin_pll < 7 * MHZ)
+			s5p_mipi_dsi_enable_afc(dsim, 1, 0x1);
+		else if (dfin_pll < 8 * MHZ)
+			s5p_mipi_dsi_enable_afc(dsim, 1, 0x0);
+		else if (dfin_pll < 9 * MHZ)
+			s5p_mipi_dsi_enable_afc(dsim, 1, 0x3);
+		else if (dfin_pll < 10 * MHZ)
+			s5p_mipi_dsi_enable_afc(dsim, 1, 0x2);
+		else if (dfin_pll < 11 * MHZ)
+			s5p_mipi_dsi_enable_afc(dsim, 1, 0x5);
+		else
+			s5p_mipi_dsi_enable_afc(dsim, 1, 0x4);
+	}
+
+	dfvco = dfin_pll * main_divider;
+	dev_dbg(dsim->dev, "dfvco = %lu, dfin_pll = %lu, main_divider = %d\n",
+				dfvco, dfin_pll, main_divider);
+	if (dfvco < DFVCO_MIN_HZ || dfvco > DFVCO_MAX_HZ)
+		dev_warn(dsim->dev, "fvco range should be 500MHz ~ 1000MHz\n");
+
+	dpll_out = dfvco / (1 << scaler);
+	dev_dbg(dsim->dev, "dpll_out = %lu, dfvco = %lu, scaler = %d\n",
+		dpll_out, dfvco, scaler);
+
+	for (i = 0; i < ARRAY_SIZE(dpll_table); i++) {
+		if (dpll_out < dpll_table[i] * MHZ) {
+			freq_band = i;
+			break;
+		}
+	}
+
+	dev_dbg(dsim->dev, "freq_band = %d\n", freq_band);
+
+	s5p_mipi_dsi_pll_freq(dsim, pre_divider, main_divider, scaler);
+
+	s5p_mipi_dsi_hs_zero_ctrl(dsim, 0);
+	s5p_mipi_dsi_prep_ctrl(dsim, 0);
+
+	/* Freq Band */
+	s5p_mipi_dsi_pll_freq_band(dsim, freq_band);
+
+	/* Stable time */
+	s5p_mipi_dsi_pll_stable_time(dsim, dsim->dsim_config->pll_stable_time);
+
+	/* Enable PLL */
+	dev_dbg(dsim->dev, "FOUT of mipi dphy pll is %luMHz\n",
+		(dpll_out / MHZ));
+
+	return dpll_out;
+}
+
+int s5p_mipi_dsi_set_clock(struct mipi_dsim_device *dsim,
+	unsigned int byte_clk_sel, unsigned int enable)
+{
+	unsigned int esc_div;
+	unsigned long esc_clk_error_rate;
+
+	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) {
+			dsim->hs_clk = s5p_mipi_dsi_change_pll(dsim,
+				dsim->dsim_config->p, dsim->dsim_config->m,
+				dsim->dsim_config->s);
+			if (dsim->hs_clk = 0) {
+				dev_err(dsim->dev,
+					"failed to get hs clock.\n");
+				return -EINVAL;
+			}
+
+			dsim->byte_clk = dsim->hs_clk / 8;
+			s5p_mipi_dsi_enable_pll_bypass(dsim, 0);
+			s5p_mipi_dsi_pll_on(dsim, 1);
+		/* DPHY : D-PHY clock out, DSIM link : external clock out */
+		} else if (byte_clk_sel = DSIM_EXT_CLK_DIV8)
+			dev_warn(dsim->dev,
+				"this project is not support \
+				external clock source for MIPI DSIM\n");
+		else if (byte_clk_sel = DSIM_EXT_CLK_BYPASS)
+			dev_warn(dsim->dev,
+				"this project is not support \
+				external clock source for MIPI DSIM\n");
+
+		/* escape clock divider */
+		esc_div = dsim->byte_clk / (dsim->dsim_config->esc_clk);
+		dev_dbg(dsim->dev,
+			"esc_div = %d, byte_clk = %lu, esc_clk = %lu\n",
+			esc_div, dsim->byte_clk, dsim->dsim_config->esc_clk);
+		if ((dsim->byte_clk / esc_div) >= (20 * MHZ) ||
+				(dsim->byte_clk / esc_div) >
+					dsim->dsim_config->esc_clk)
+			esc_div += 1;
+
+		dsim->escape_clk = dsim->byte_clk / esc_div;
+		dev_dbg(dsim->dev,
+			"escape_clk = %lu, byte_clk = %lu, esc_div = %d\n",
+			dsim->escape_clk, dsim->byte_clk, esc_div);
+
+		/* enable escape clock. */
+		s5p_mipi_dsi_enable_byte_clock(dsim, DSIM_ESCCLK_ON);
+
+		/* enable byte clk and escape clock */
+		s5p_mipi_dsi_set_esc_clk_prs(dsim, 1, esc_div);
+		/* escape clock on lane */
+		s5p_mipi_dsi_enable_esc_clk_on_lane(dsim,
+			(DSIM_LANE_CLOCK | dsim->data_lane), 1);
+
+		dev_dbg(dsim->dev, "byte clock is %luMHz\n",
+			(dsim->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",
+			((dsim->byte_clk / esc_div) / MHZ));
+
+		if ((dsim->byte_clk / esc_div) > dsim->escape_clk) {
+			esc_clk_error_rate = dsim->escape_clk /
+				(dsim->byte_clk / esc_div);
+			dev_warn(dsim->dev, "error rate is %lu over.\n",
+				(esc_clk_error_rate / 100));
+		} else if ((dsim->byte_clk / esc_div) < (dsim->escape_clk)) {
+			esc_clk_error_rate = (dsim->byte_clk / esc_div) /
+				dsim->escape_clk;
+			dev_warn(dsim->dev, "error rate is %lu under.\n",
+				(esc_clk_error_rate / 100));
+		}
+	} else {
+		s5p_mipi_dsi_enable_esc_clk_on_lane(dsim,
+			(DSIM_LANE_CLOCK | dsim->data_lane), 0);
+		s5p_mipi_dsi_set_esc_clk_prs(dsim, 0, 0);
+
+		/* disable escape clock. */
+		s5p_mipi_dsi_enable_byte_clock(dsim, DSIM_ESCCLK_OFF);
+
+		if (byte_clk_sel = DSIM_PLL_OUT_DIV8)
+			s5p_mipi_dsi_pll_on(dsim, 0);
+	}
+
+	return 0;
+}
+
+int s5p_mipi_dsi_init_dsim(struct mipi_dsim_device *dsim)
+{
+	if (dsim->pd->init_d_phy)
+		dsim->pd->init_d_phy(dsim);
+
+	dsim->state = DSIM_STATE_INIT;
+
+	switch (dsim->dsim_config->e_no_data_lane) {
+	case DSIM_DATA_LANE_1:
+		dsim->data_lane = DSIM_LANE_DATA0;
+		break;
+	case DSIM_DATA_LANE_2:
+		dsim->data_lane = DSIM_LANE_DATA0 | DSIM_LANE_DATA1;
+		break;
+	case DSIM_DATA_LANE_3:
+		dsim->data_lane = DSIM_LANE_DATA0 | DSIM_LANE_DATA1 |
+			DSIM_LANE_DATA2;
+		break;
+	case DSIM_DATA_LANE_4:
+		dsim->data_lane = DSIM_LANE_DATA0 | DSIM_LANE_DATA1 |
+			DSIM_LANE_DATA2 | DSIM_LANE_DATA3;
+		break;
+	default:
+		dev_info(dsim->dev, "data lane is invalid.\n");
+		return -EINVAL;
+	};
+
+	s5p_mipi_dsi_sw_reset(dsim);
+	s5p_mipi_dsi_dp_dn_swap(dsim, 0);
+
+	return 0;
+}
+
+int s5p_mipi_dsi_enable_frame_done_int(struct mipi_dsim_device *dsim,
+	unsigned int enable)
+{
+	/* enable only frame done interrupt */
+	s5p_mipi_dsi_set_interrupt_mask(dsim, INTMSK_FRAME_DONE, enable);
+
+	return 0;
+}
+
+int s5p_mipi_dsi_set_display_mode(struct mipi_dsim_device *dsim,
+	struct mipi_dsim_config *dsim_config)
+{
+	struct fb_videomode *lcd_video = NULL;
+	struct s3c_fb_pd_win *pd;
+	unsigned int width = 0, height = 0;
+
+	pd = (struct s3c_fb_pd_win *)dsim->dsim_config->lcd_panel_info;
+	lcd_video = (struct fb_videomode *)&pd->win_mode;
+
+	width = lcd_video->xres;
+	height = lcd_video->yres;
+
+	/* in case of VIDEO MODE (RGB INTERFACE) */
+	if (dsim->dsim_config->e_interface = (u32) DSIM_VIDEO) {
+		if (dsim->dsim_config->auto_vertical_cnt = 0) {
+			s5p_mipi_dsi_set_main_disp_vporch(dsim,
+				lcd_video->upper_margin,
+				lcd_video->lower_margin, 0);
+			s5p_mipi_dsi_set_main_disp_hporch(dsim,
+				lcd_video->left_margin,
+				lcd_video->right_margin);
+			s5p_mipi_dsi_set_main_disp_sync_area(dsim,
+				lcd_video->vsync_len,
+				lcd_video->hsync_len);
+		}
+	}
+
+	s5p_mipi_dsi_set_main_disp_resol(dsim, height, width);
+
+	s5p_mipi_dsi_display_config(dsim, dsim->dsim_config);
+
+	return 0;
+}
+
+int s5p_mipi_dsi_init_link(struct mipi_dsim_device *dsim)
+{
+	unsigned int time_out = 100;
+
+	switch (dsim->state) {
+	case DSIM_STATE_INIT:
+		s5p_mipi_dsi_sw_reset(dsim);
+
+		s5p_mipi_dsi_init_fifo_pointer(dsim, 0x1f);
+
+		/* dsi configuration */
+		s5p_mipi_dsi_init_config(dsim);
+		s5p_mipi_dsi_enable_lane(dsim, DSIM_LANE_CLOCK, 1);
+		s5p_mipi_dsi_enable_lane(dsim, dsim->data_lane, 1);
+
+		/* set clock configuration */
+		s5p_mipi_dsi_set_clock(dsim, dsim->dsim_config->e_byte_clk, 1);
+
+		/* check clock and data lane state are stop state */
+		while (!(s5p_mipi_dsi_is_lane_state(dsim))) {
+			time_out--;
+			if (time_out = 0) {
+				dev_err(dsim->dev,
+					"DSI Master is not stop state.\n");
+				dev_err(dsim->dev,
+					"Check initialization process\n");
+
+				return -EINVAL;
+			}
+		}
+
+		if (time_out != 0) {
+			dev_info(dsim->dev,
+				"DSI Master driver has been completed.\n");
+			dev_info(dsim->dev, "DSI Master state is stop state\n");
+		}
+
+		dsim->state = DSIM_STATE_STOP;
+
+		/* BTA sequence counters */
+		s5p_mipi_dsi_set_stop_state_counter(dsim,
+			dsim->dsim_config->stop_holding_cnt);
+		s5p_mipi_dsi_set_bta_timeout(dsim,
+			dsim->dsim_config->bta_timeout);
+		s5p_mipi_dsi_set_lpdr_timeout(dsim,
+			dsim->dsim_config->rx_timeout);
+
+		return 0;
+	default:
+		dev_info(dsim->dev, "DSI Master is already init.\n");
+		return 0;
+	}
+
+	return 0;
+}
+
+int s5p_mipi_dsi_set_hs_enable(struct mipi_dsim_device *dsim)
+{
+	if (dsim->state = DSIM_STATE_STOP) {
+		if (dsim->e_clk_src != DSIM_EXT_CLK_BYPASS) {
+			dsim->state = DSIM_STATE_HSCLKEN;
+
+			 /* set LCDC and CPU transfer mode to HS. */
+			s5p_mipi_dsi_set_lcdc_transfer_mode(dsim, 0);
+			s5p_mipi_dsi_set_cpu_transfer_mode(dsim, 0);
+
+			s5p_mipi_dsi_enable_hs_clock(dsim, 1);
+
+			return 0;
+		} else
+			dev_warn(dsim->dev,
+				"clock source is external bypass.\n");
+	} else
+		dev_warn(dsim->dev, "DSIM is not stop state.\n");
+
+	return 0;
+}
+
+int s5p_mipi_dsi_set_data_transfer_mode(struct mipi_dsim_device *dsim,
+		unsigned int mode)
+{
+	if (mode) {
+		if (dsim->state != DSIM_STATE_HSCLKEN) {
+			dev_err(dsim->dev, "HS Clock lane is not enabled.\n");
+			return -EINVAL;
+		}
+
+		s5p_mipi_dsi_set_lcdc_transfer_mode(dsim, 0);
+	} else {
+		if (dsim->state = DSIM_STATE_INIT || dsim->state =
+			DSIM_STATE_ULPS) {
+			dev_err(dsim->dev,
+				"DSI Master is not STOP or HSDT state.\n");
+			return -EINVAL;
+		}
+
+		s5p_mipi_dsi_set_cpu_transfer_mode(dsim, 0);
+	}
+
+	return 0;
+}
+
+int s5p_mipi_dsi_get_frame_done_status(struct mipi_dsim_device *dsim)
+{
+	return _s5p_mipi_dsi_get_frame_done_status(dsim);
+}
+
+int s5p_mipi_dsi_clear_frame_done(struct mipi_dsim_device *dsim)
+{
+	_s5p_mipi_dsi_clear_frame_done(dsim);
+
+	return 0;
+}
+
+MODULE_AUTHOR("InKi Dae <inki.dae@samsung.com>");
+MODULE_DESCRIPTION("Samusung MIPI-DSIM common driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/s5p_mipi_dsi_common.h b/drivers/video/s5p_mipi_dsi_common.h
new file mode 100644
index 0000000..040d70e
--- /dev/null
+++ b/drivers/video/s5p_mipi_dsi_common.h
@@ -0,0 +1,38 @@
+/* linux/drivers/video/s5p_mipi_dsi_common.h
+ *
+ * Header file for Samsung MIPI-DSI common driver.
+ *
+ * Copyright (c) 2009 Samsung Electronics
+ * InKi Dae <inki.dae@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef _S5P_MIPI_DSI_COMMON_H
+#define _S5P_MIPI_DSI_COMMON_H
+
+int s5p_mipi_dsi_wr_data(struct mipi_dsim_device *dsim, unsigned int data_id,
+	unsigned int data0, unsigned int data1);
+int s5p_mipi_dsi_pll_on(struct mipi_dsim_device *dsim, unsigned int enable);
+unsigned long s5p_mipi_dsi_change_pll(struct mipi_dsim_device *dsim,
+	unsigned int pre_divider, unsigned int main_divider,
+	unsigned int scaler);
+int s5p_mipi_dsi_set_clock(struct mipi_dsim_device *dsim,
+	unsigned int byte_clk_sel, unsigned int enable);
+int s5p_mipi_dsi_init_dsim(struct mipi_dsim_device *dsim);
+int s5p_mipi_dsi_set_display_mode(struct mipi_dsim_device *dsim,
+			struct mipi_dsim_config *dsim_info);
+int s5p_mipi_dsi_init_link(struct mipi_dsim_device *dsim);
+int s5p_mipi_dsi_set_hs_enable(struct mipi_dsim_device *dsim);
+int s5p_mipi_dsi_set_data_transfer_mode(struct mipi_dsim_device *dsim,
+		unsigned int mode);
+int s5p_mipi_dsi_enable_frame_done_int(struct mipi_dsim_device *dsim,
+	unsigned int enable);
+int s5p_mipi_dsi_get_frame_done_status(struct mipi_dsim_device *dsim);
+int s5p_mipi_dsi_clear_frame_done(struct mipi_dsim_device *dsim);
+
+extern struct fb_info *registered_fb[FB_MAX] __read_mostly;
+
+#endif /* _S5P_MIPI_DSI_COMMON_H */
diff --git a/drivers/video/s5p_mipi_dsi_lowlevel.c b/drivers/video/s5p_mipi_dsi_lowlevel.c
new file mode 100644
index 0000000..8afea36
--- /dev/null
+++ b/drivers/video/s5p_mipi_dsi_lowlevel.c
@@ -0,0 +1,553 @@
+/* linux/drivers/video/s5p_mipi_dsi_lowlevel.c
+ *
+ * Samsung MIPI-DSI lowlevel driver.
+ *
+ * InKi Dae, <inki.dae@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/ctype.h>
+#include <linux/io.h>
+
+#include <mach/map.h>
+
+#include <plat/dsim.h>
+#include <plat/regs-dsim.h>
+
+void s5p_mipi_dsi_func_reset(struct mipi_dsim_device *dsim)
+{
+	unsigned int reg;
+
+	reg = readl(dsim->reg_base + S5P_DSIM_SWRST);
+
+	reg |= DSIM_FUNCRST;
+
+	writel(reg, dsim->reg_base + S5P_DSIM_SWRST);
+}
+
+void s5p_mipi_dsi_sw_reset(struct mipi_dsim_device *dsim)
+{
+	unsigned int reg;
+
+	reg = readl(dsim->reg_base + S5P_DSIM_SWRST);
+
+	reg |= DSIM_SWRST;
+
+	writel(reg, dsim->reg_base + S5P_DSIM_SWRST);
+}
+
+void s5p_mipi_dsi_set_interrupt_mask(struct mipi_dsim_device *dsim,
+		unsigned int mode, unsigned int mask)
+{
+	unsigned int reg = readl(dsim->reg_base + S5P_DSIM_INTMSK);
+
+	if (mask)
+		reg |= mode;
+	else
+		reg &= ~mode;
+
+	writel(reg, dsim->reg_base + S5P_DSIM_INTMSK);
+}
+
+void s5p_mipi_dsi_init_fifo_pointer(struct mipi_dsim_device *dsim,
+		unsigned int cfg)
+{
+	unsigned int reg;
+
+	reg = readl(dsim->reg_base + S5P_DSIM_FIFOCTRL);
+
+	writel(reg & ~(cfg), dsim->reg_base + S5P_DSIM_FIFOCTRL);
+	mdelay(10);
+	reg |= cfg;
+
+	writel(reg, dsim->reg_base + S5P_DSIM_FIFOCTRL);
+}
+
+/*
+ * this function set PLL P, M and S value in D-PHY
+ */
+void s5p_mipi_dsi_set_phy_tunning(struct mipi_dsim_device *dsim,
+		unsigned int value)
+{
+	writel(DSIM_AFC_CTL(value), dsim->reg_base + S5P_DSIM_PHYACCHR);
+}
+
+void s5p_mipi_dsi_set_main_disp_resol(struct mipi_dsim_device *dsim,
+	unsigned int vert_resol, unsigned int hori_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(vert_resol) | DSIM_MAIN_HRESOL(hori_resol);
+
+	reg |= DSIM_MAIN_STAND_BY;
+	writel(reg, dsim->reg_base + S5P_DSIM_MDRESOL);
+}
+
+void s5p_mipi_dsi_set_main_disp_vporch(struct mipi_dsim_device *dsim,
+	unsigned int cmd_allow, unsigned int vfront, unsigned int vback)
+{
+	unsigned int reg;
+
+	reg = (readl(dsim->reg_base + S5P_DSIM_MVPORCH)) &
+		~(DSIM_CMD_ALLOW_MASK) & ~(DSIM_STABLE_VFP_MASK) &
+		~(DSIM_MAIN_VBP_MASK);
+
+	reg |= ((cmd_allow & 0xf) << DSIM_CMD_ALLOW_SHIFT) |
+		((vfront & 0x7ff) << DSIM_STABLE_VFP_SHIFT) |
+		((vback & 0x7ff) << DSIM_MAIN_VBP_SHIFT);
+
+	writel(reg, dsim->reg_base + S5P_DSIM_MVPORCH);
+}
+
+void s5p_mipi_dsi_set_main_disp_hporch(struct mipi_dsim_device *dsim,
+	unsigned int front, unsigned int back)
+{
+	unsigned int reg;
+
+	reg = (readl(dsim->reg_base + S5P_DSIM_MHPORCH)) &
+		~(DSIM_MAIN_HFP_MASK) & ~(DSIM_MAIN_HBP_MASK);
+
+	reg |= (front << DSIM_MAIN_HFP_SHIFT) | (back << DSIM_MAIN_HBP_SHIFT);
+
+	writel(reg, dsim->reg_base + S5P_DSIM_MHPORCH);
+}
+
+void s5p_mipi_dsi_set_main_disp_sync_area(struct mipi_dsim_device *dsim,
+	unsigned int vert, unsigned int hori)
+{
+	unsigned int reg;
+
+	reg = (readl(dsim->reg_base + S5P_DSIM_MSYNC)) &
+		~(DSIM_MAIN_VSA_MASK) & ~(DSIM_MAIN_HSA_MASK);
+
+	reg |= ((vert & 0x3ff) << DSIM_MAIN_VSA_SHIFT) |
+		(hori << DSIM_MAIN_HSA_SHIFT);
+
+	writel(reg, dsim->reg_base + S5P_DSIM_MSYNC);
+}
+
+void s5p_mipi_dsi_set_sub_disp_resol(struct mipi_dsim_device *dsim,
+	unsigned int vert, unsigned int hori)
+{
+	unsigned int reg;
+
+	reg = (readl(dsim->reg_base + S5P_DSIM_SDRESOL)) &
+		~(DSIM_SUB_STANDY_MASK);
+
+	writel(reg, dsim->reg_base + S5P_DSIM_SDRESOL);
+
+	reg &= ~(DSIM_SUB_VRESOL_MASK) | ~(DSIM_SUB_HRESOL_MASK);
+	reg |= ((vert & 0x7ff) << DSIM_SUB_VRESOL_SHIFT) |
+		((hori & 0x7ff) << DSIM_SUB_HRESOL_SHIFT);
+	writel(reg, dsim->reg_base + S5P_DSIM_SDRESOL);
+
+	reg |= (1 << DSIM_SUB_STANDY_SHIFT);
+	writel(reg, dsim->reg_base + S5P_DSIM_SDRESOL);
+}
+
+void s5p_mipi_dsi_init_config(struct mipi_dsim_device *dsim)
+{
+	struct mipi_dsim_config *dsim_config = dsim->dsim_config;
+
+	unsigned int cfg = (readl(dsim->reg_base + S5P_DSIM_CONFIG)) &
+		~(1 << 28) & ~(0x1f << 20) & ~(0x3 << 5);
+
+	cfg =	(dsim_config->auto_flush << 29) |
+		(dsim_config->eot_disable << 28) |
+		(dsim_config->auto_vertical_cnt << DSIM_AUTO_MODE_SHIFT) |
+		(dsim_config->hse << DSIM_HSE_MODE_SHIFT) |
+		(dsim_config->hfp << DSIM_HFP_MODE_SHIFT) |
+		(dsim_config->hbp << DSIM_HBP_MODE_SHIFT) |
+		(dsim_config->hsa << DSIM_HSA_MODE_SHIFT) |
+		(dsim_config->e_no_data_lane << DSIM_NUM_OF_DATALANE_SHIFT);
+
+	writel(cfg, dsim->reg_base + S5P_DSIM_CONFIG);
+}
+
+void s5p_mipi_dsi_display_config(struct mipi_dsim_device *dsim,
+				struct mipi_dsim_config *dsim_config)
+{
+	u32 reg = (readl(dsim->reg_base + S5P_DSIM_CONFIG)) &
+		~(0x3 << 26) & ~(1 << 25) & ~(0x3 << 18) & ~(0x7 << 12) &
+		~(0x3 << 16) & ~(0x7 << 8);
+
+	if (dsim_config->e_interface = DSIM_VIDEO)
+		reg |= (1 << 25);
+	else if (dsim_config->e_interface = DSIM_COMMAND)
+		reg &= ~(1 << 25);
+	else {
+		dev_err(dsim->dev, "this ddi is not MIPI interface.\n");
+		return;
+	}
+
+	/* main lcd */
+	reg |= ((u8) (dsim_config->e_burst_mode) & 0x3) << 26 |
+		((u8) (dsim_config->e_virtual_ch) & 0x3) << 18 |
+		((u8) (dsim_config->e_pixel_format) & 0x7) << 12;
+
+	writel(reg, dsim->reg_base + S5P_DSIM_CONFIG);
+}
+
+void s5p_mipi_dsi_enable_lane(struct mipi_dsim_device *dsim, unsigned int lane,
+	unsigned int enable)
+{
+	unsigned int reg;
+
+	reg = readl(dsim->reg_base + S5P_DSIM_CONFIG);
+
+	if (enable)
+		reg |= DSIM_LANE_ENx(lane);
+	else
+		reg &= ~DSIM_LANE_ENx(lane);
+
+	writel(reg, dsim->reg_base + S5P_DSIM_CONFIG);
+}
+
+
+void s5p_mipi_dsi_set_data_lane_number(struct mipi_dsim_device *dsim,
+	unsigned int count)
+{
+	unsigned int cfg;
+
+	/* get the data lane number. */
+	cfg = DSIM_NUM_OF_DATA_LANE(count);
+
+	writel(cfg, dsim->reg_base + S5P_DSIM_CONFIG);
+}
+
+void s5p_mipi_dsi_enable_afc(struct mipi_dsim_device *dsim, unsigned int enable,
+	unsigned int afc_code)
+{
+	unsigned int reg = readl(dsim->reg_base + S5P_DSIM_PHYACCHR);
+
+	if (enable) {
+		reg |= (1 << 14);
+		reg &= ~(0x7 << 5);
+		reg |= (afc_code & 0x7) << 5;
+	} else
+		reg &= ~(1 << 14);
+
+	writel(reg, dsim->reg_base + S5P_DSIM_PHYACCHR);
+}
+
+void s5p_mipi_dsi_enable_pll_bypass(struct mipi_dsim_device *dsim,
+	unsigned int enable)
+{
+	unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_CLKCTRL)) &
+		~(DSIM_PLL_BYPASS_EXTERNAL);
+
+	reg |= enable << DSIM_PLL_BYPASS_SHIFT;
+
+	writel(reg, dsim->reg_base + S5P_DSIM_CLKCTRL);
+}
+
+void s5p_mipi_dsi_set_pll_pms(struct mipi_dsim_device *dsim, unsigned int p,
+	unsigned int m, unsigned int s)
+{
+	unsigned int reg = readl(dsim->reg_base + S5P_DSIM_PLLCTRL);
+
+	reg |= ((p & 0x3f) << 13) | ((m & 0x1ff) << 4) | ((s & 0x7) << 1);
+
+	writel(reg, dsim->reg_base + S5P_DSIM_PLLCTRL);
+}
+
+void s5p_mipi_dsi_pll_freq_band(struct mipi_dsim_device *dsim,
+		unsigned int freq_band)
+{
+	unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_PLLCTRL)) &
+		~(0x1f << DSIM_FREQ_BAND_SHIFT);
+
+	reg |= ((freq_band & 0x1f) << DSIM_FREQ_BAND_SHIFT);
+
+	writel(reg, dsim->reg_base + S5P_DSIM_PLLCTRL);
+}
+
+void s5p_mipi_dsi_pll_freq(struct mipi_dsim_device *dsim,
+		unsigned int pre_divider, unsigned int main_divider,
+		unsigned int scaler)
+{
+	unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_PLLCTRL)) &
+		~(0x7ffff << 1);
+
+	reg |= (pre_divider & 0x3f) << 13 | (main_divider & 0x1ff) << 4 |
+		(scaler & 0x7) << 1;
+
+	writel(reg, dsim->reg_base + S5P_DSIM_PLLCTRL);
+}
+
+void s5p_mipi_dsi_pll_stable_time(struct mipi_dsim_device *dsim,
+	unsigned int lock_time)
+{
+	writel(lock_time, dsim->reg_base + S5P_DSIM_PLLTMR);
+}
+
+void s5p_mipi_dsi_enable_pll(struct mipi_dsim_device *dsim, unsigned int enable)
+{
+	unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_PLLCTRL)) &
+		~(0x1 << DSIM_PLL_EN_SHIFT);
+
+	reg |= ((enable & 0x1) << DSIM_PLL_EN_SHIFT);
+
+	writel(reg, dsim->reg_base + S5P_DSIM_PLLCTRL);
+}
+
+void s5p_mipi_dsi_set_byte_clock_src(struct mipi_dsim_device *dsim,
+		unsigned int src)
+{
+	unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_CLKCTRL)) &
+		~(0x3 << DSIM_BYTE_CLK_SRC_SHIFT);
+
+	reg |= ((unsigned int) src) << DSIM_BYTE_CLK_SRC_SHIFT;
+
+	writel(reg, dsim->reg_base + S5P_DSIM_CLKCTRL);
+}
+
+void s5p_mipi_dsi_enable_byte_clock(struct mipi_dsim_device *dsim,
+		unsigned int enable)
+{
+	unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_CLKCTRL)) &
+		~(1 << DSIM_BYTE_CLKEN_SHIFT);
+
+	reg |= enable << DSIM_BYTE_CLKEN_SHIFT;
+
+	writel(reg, dsim->reg_base + S5P_DSIM_CLKCTRL);
+}
+
+void s5p_mipi_dsi_set_esc_clk_prs(struct mipi_dsim_device *dsim,
+		unsigned int enable, unsigned int prs_val)
+{
+	unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_CLKCTRL)) &
+		~(1 << DSIM_ESC_CLKEN_SHIFT) & ~(0xffff);
+
+	reg |= enable << DSIM_ESC_CLKEN_SHIFT;
+	if (enable)
+		reg |= prs_val;
+
+	writel(reg, dsim->reg_base + S5P_DSIM_CLKCTRL);
+}
+
+void s5p_mipi_dsi_enable_esc_clk_on_lane(struct mipi_dsim_device *dsim,
+		unsigned int lane_sel, unsigned int enable)
+{
+	unsigned int reg = readl(dsim->reg_base + S5P_DSIM_CLKCTRL);
+
+	if (enable)
+		reg |= DSIM_LANE_ESC_CLKEN(lane_sel);
+	else
+
+		reg &= ~DSIM_LANE_ESC_CLKEN(lane_sel);
+
+	writel(reg, dsim->reg_base + S5P_DSIM_CLKCTRL);
+}
+
+void s5p_mipi_dsi_force_dphy_stop_state(struct mipi_dsim_device *dsim,
+	unsigned int enable)
+{
+	unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_ESCMODE)) &
+		~(0x1 << DSIM_FORCE_STOP_STATE_SHIFT);
+
+	reg |= ((enable & 0x1) << DSIM_FORCE_STOP_STATE_SHIFT);
+
+	writel(reg, dsim->reg_base + S5P_DSIM_ESCMODE);
+}
+
+unsigned int s5p_mipi_dsi_is_lane_state(struct mipi_dsim_device *dsim)
+{
+	unsigned int reg = readl(dsim->reg_base + S5P_DSIM_STATUS);
+
+	/**
+	 * check clock and data lane states.
+	 * if MIPI-DSI controller was enabled at bootloader then
+	 * TX_READY_HS_CLK is enabled otherwise STOP_STATE_CLK.
+	 * so it should be checked for two case.
+	 */
+	if ((reg & DSIM_STOP_STATE_DAT(0xf)) &&
+			((reg & DSIM_STOP_STATE_CLK) ||
+			 (reg & DSIM_TX_READY_HS_CLK)))
+		return 1;
+	else
+		return 0;
+
+	return 0;
+}
+
+void s5p_mipi_dsi_set_stop_state_counter(struct mipi_dsim_device *dsim,
+		unsigned int cnt_val)
+{
+	unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_ESCMODE)) &
+		~(0x7ff << DSIM_STOP_STATE_CNT_SHIFT);
+
+	reg |= ((cnt_val & 0x7ff) << DSIM_STOP_STATE_CNT_SHIFT);
+
+	writel(reg, dsim->reg_base + S5P_DSIM_ESCMODE);
+}
+
+void s5p_mipi_dsi_set_bta_timeout(struct mipi_dsim_device *dsim,
+		unsigned int timeout)
+{
+	unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_TIMEOUT)) &
+		~(0xff << DSIM_BTA_TOUT_SHIFT);
+
+	reg |= (timeout << DSIM_BTA_TOUT_SHIFT);
+
+	writel(reg, dsim->reg_base + S5P_DSIM_TIMEOUT);
+}
+
+void s5p_mipi_dsi_set_lpdr_timeout(struct mipi_dsim_device *dsim,
+		unsigned int timeout)
+{
+	unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_TIMEOUT)) &
+		~(0xffff << DSIM_LPDR_TOUT_SHIFT);
+
+	reg |= (timeout << DSIM_LPDR_TOUT_SHIFT);
+
+	writel(reg, dsim->reg_base + S5P_DSIM_TIMEOUT);
+}
+
+void s5p_mipi_dsi_set_cpu_transfer_mode(struct mipi_dsim_device *dsim,
+		unsigned int lp)
+{
+	unsigned int reg = readl(dsim->reg_base + S5P_DSIM_ESCMODE);
+
+	reg &= ~DSIM_CMD_LPDT_LP;
+
+	reg |= lp << DSIM_CMD_LPDT_SHIFT;
+
+	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;
+
+	reg |= lp << DSIM_TX_LPDT_SHIFT;
+
+	writel(reg, dsim->reg_base + S5P_DSIM_ESCMODE);
+}
+
+void s5p_mipi_dsi_enable_hs_clock(struct mipi_dsim_device *dsim,
+		unsigned int enable)
+{
+	unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_CLKCTRL)) &
+		~(1 << DSIM_TX_REQUEST_HSCLK_SHIFT);
+
+	reg |= enable << DSIM_TX_REQUEST_HSCLK_SHIFT;
+
+	writel(reg, dsim->reg_base + S5P_DSIM_CLKCTRL);
+}
+
+void s5p_mipi_dsi_dp_dn_swap(struct mipi_dsim_device *dsim,
+		unsigned int swap_en)
+{
+	unsigned int reg = readl(dsim->reg_base + S5P_DSIM_PHYACCHR1);
+
+	reg &= ~(0x3 << 0);
+	reg |= (swap_en & 0x3) << 0;
+
+	writel(reg, dsim->reg_base + S5P_DSIM_PHYACCHR1);
+}
+
+void s5p_mipi_dsi_hs_zero_ctrl(struct mipi_dsim_device *dsim,
+		unsigned int hs_zero)
+{
+	unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_PLLCTRL)) &
+		~(0xf << 28);
+
+	reg |= ((hs_zero & 0xf) << 28);
+
+	writel(reg, dsim->reg_base + S5P_DSIM_PLLCTRL);
+}
+
+void s5p_mipi_dsi_prep_ctrl(struct mipi_dsim_device *dsim, unsigned int prep)
+{
+	unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_PLLCTRL)) &
+		~(0x7 << 20);
+
+	reg |= ((prep & 0x7) << 20);
+
+	writel(reg, dsim->reg_base + S5P_DSIM_PLLCTRL);
+}
+
+void s5p_mipi_dsi_clear_interrupt(struct mipi_dsim_device *dsim)
+{
+	unsigned int reg = readl(dsim->reg_base + S5P_DSIM_INTSRC);
+
+	reg |= INTSRC_PLL_STABLE;
+
+	writel(reg, dsim->reg_base + S5P_DSIM_INTSRC);
+}
+
+void s5p_mipi_dsi_clear_all_interrupt(struct mipi_dsim_device *dsim)
+{
+	unsigned int reg = readl(dsim->reg_base + S5P_DSIM_INTSRC);
+
+	reg |= 0xffffffff;
+
+	writel(reg, dsim->reg_base + S5P_DSIM_INTSRC);
+}
+
+unsigned int s5p_mipi_dsi_is_pll_stable(struct mipi_dsim_device *dsim)
+{
+	unsigned int reg;
+
+	reg = readl(dsim->reg_base + S5P_DSIM_STATUS);
+
+	return reg & (1 << 31) ? 1 : 0;
+}
+
+unsigned int s5p_mipi_dsi_get_fifo_state(struct mipi_dsim_device *dsim)
+{
+	unsigned int ret;
+
+	ret = readl(dsim->reg_base + S5P_DSIM_FIFOCTRL) & ~(0x1f);
+
+	return ret;
+}
+
+void s5p_mipi_dsi_wr_tx_header(struct mipi_dsim_device *dsim,
+	unsigned int di, unsigned int data0, unsigned int data1)
+{
+	unsigned int reg = (data1 << 16) | (data0 << 8) | ((di & 0x3f) << 0);
+
+	writel(reg, dsim->reg_base + S5P_DSIM_PKTHDR);
+}
+
+unsigned int _s5p_mipi_dsi_get_frame_done_status(struct mipi_dsim_device *dsim)
+{
+	unsigned int reg = readl(dsim->reg_base + S5P_DSIM_INTSRC);
+
+	return (reg & INTSRC_FRAME_DONE) ? 1 : 0;
+}
+
+void _s5p_mipi_dsi_clear_frame_done(struct mipi_dsim_device *dsim)
+{
+	unsigned int reg = readl(dsim->reg_base + S5P_DSIM_INTSRC);
+
+	writel(reg | INTSRC_FRAME_DONE, dsim->reg_base +
+		S5P_DSIM_INTSRC);
+}
+
+void s5p_mipi_dsi_wr_tx_data(struct mipi_dsim_device *dsim,
+		unsigned int tx_data)
+{
+	writel(tx_data, dsim->reg_base + S5P_DSIM_PAYLOAD);
+}
diff --git a/drivers/video/s5p_mipi_dsi_lowlevel.h b/drivers/video/s5p_mipi_dsi_lowlevel.h
new file mode 100644
index 0000000..ed3f91c
--- /dev/null
+++ b/drivers/video/s5p_mipi_dsi_lowlevel.h
@@ -0,0 +1,98 @@
+/* linux/drivers/video/s5p_mipi_dsi_lowlevel.h
+ *
+ * Header file for Samsung MIPI-DSI lowlevel driver.
+ *
+ * Copyright (c) 2009 Samsung Electronics
+ * InKi Dae <inki.dae@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef _S5P_MIPI_DSI_LOWLEVEL_H
+#define _S5P_MIPI_DSI_LOWLEVEL_H
+
+void s5p_mipi_dsi_func_reset(struct mipi_dsim_device *dsim);
+void s5p_mipi_dsi_sw_reset(struct mipi_dsim_device *dsim);
+void s5p_mipi_dsi_set_interrupt_mask(struct mipi_dsim_device *dsim,
+	unsigned int mode, unsigned int mask);
+void s5p_mipi_dsi_set_data_lane_number(struct mipi_dsim_device *dsim,
+					unsigned int count);
+void s5p_mipi_dsi_init_fifo_pointer(struct mipi_dsim_device *dsim,
+					unsigned int cfg);
+void s5p_mipi_dsi_set_phy_tunning(struct mipi_dsim_device *dsim,
+				unsigned int value);
+void s5p_mipi_dsi_set_phy_tunning(struct mipi_dsim_device *dsim,
+				unsigned int value);
+void s5p_mipi_dsi_set_main_disp_resol(struct mipi_dsim_device *dsim,
+		unsigned int vert_resol, unsigned int hori_resol);
+void s5p_mipi_dsi_set_main_disp_vporch(struct mipi_dsim_device *dsim,
+	unsigned int cmd_allow, unsigned int vfront, unsigned int vback);
+void s5p_mipi_dsi_set_main_disp_hporch(struct mipi_dsim_device *dsim,
+			unsigned int front, unsigned int back);
+void s5p_mipi_dsi_set_main_disp_sync_area(struct mipi_dsim_device *dsim,
+				unsigned int vert, unsigned int hori);
+void s5p_mipi_dsi_set_sub_disp_resol(struct mipi_dsim_device *dsim,
+				unsigned int vert, unsigned int hori);
+void s5p_mipi_dsi_init_config(struct mipi_dsim_device *dsim);
+void s5p_mipi_dsi_display_config(struct mipi_dsim_device *dsim,
+				struct mipi_dsim_config *dsim_config);
+void s5p_mipi_dsi_set_data_lane_number(struct mipi_dsim_device *dsim,
+				unsigned int count);
+void s5p_mipi_dsi_enable_lane(struct mipi_dsim_device *dsim, unsigned int lane,
+				unsigned int enable);
+void s5p_mipi_dsi_enable_afc(struct mipi_dsim_device *dsim, unsigned int enable,
+				unsigned int afc_code);
+void s5p_mipi_dsi_enable_pll_bypass(struct mipi_dsim_device *dsim,
+				unsigned int enable);
+void s5p_mipi_dsi_set_pll_pms(struct mipi_dsim_device *dsim, unsigned int p,
+				unsigned int m, unsigned int s);
+void s5p_mipi_dsi_pll_freq_band(struct mipi_dsim_device *dsim,
+				unsigned int freq_band);
+void s5p_mipi_dsi_pll_freq(struct mipi_dsim_device *dsim,
+			unsigned int pre_divider, unsigned int main_divider,
+			unsigned int scaler);
+void s5p_mipi_dsi_pll_stable_time(struct mipi_dsim_device *dsim,
+			unsigned int lock_time);
+void s5p_mipi_dsi_enable_pll(struct mipi_dsim_device *dsim,
+					unsigned int enable);
+void s5p_mipi_dsi_set_byte_clock_src(struct mipi_dsim_device *dsim,
+					unsigned int src);
+void s5p_mipi_dsi_enable_byte_clock(struct mipi_dsim_device *dsim,
+					unsigned int enable);
+void s5p_mipi_dsi_set_esc_clk_prs(struct mipi_dsim_device *dsim,
+				unsigned int enable, unsigned int prs_val);
+void s5p_mipi_dsi_enable_esc_clk_on_lane(struct mipi_dsim_device *dsim,
+				unsigned int lane_sel, unsigned int enable);
+void s5p_mipi_dsi_force_dphy_stop_state(struct mipi_dsim_device *dsim,
+				unsigned int enable);
+unsigned int s5p_mipi_dsi_is_lane_state(struct mipi_dsim_device *dsim);
+void s5p_mipi_dsi_set_stop_state_counter(struct mipi_dsim_device *dsim,
+				unsigned int cnt_val);
+void s5p_mipi_dsi_set_bta_timeout(struct mipi_dsim_device *dsim,
+				unsigned int timeout);
+void s5p_mipi_dsi_set_lpdr_timeout(struct mipi_dsim_device *dsim,
+				unsigned int timeout);
+void s5p_mipi_dsi_set_lcdc_transfer_mode(struct mipi_dsim_device *dsim,
+					unsigned int lp);
+void s5p_mipi_dsi_set_cpu_transfer_mode(struct mipi_dsim_device *dsim,
+					unsigned int lp);
+void s5p_mipi_dsi_enable_hs_clock(struct mipi_dsim_device *dsim,
+				unsigned int enable);
+void s5p_mipi_dsi_dp_dn_swap(struct mipi_dsim_device *dsim,
+				unsigned int swap_en);
+void s5p_mipi_dsi_hs_zero_ctrl(struct mipi_dsim_device *dsim,
+				unsigned int hs_zero);
+void s5p_mipi_dsi_prep_ctrl(struct mipi_dsim_device *dsim, unsigned int prep);
+void s5p_mipi_dsi_clear_interrupt(struct mipi_dsim_device *dsim);
+void s5p_mipi_dsi_clear_all_interrupt(struct mipi_dsim_device *dsim);
+unsigned int s5p_mipi_dsi_is_pll_stable(struct mipi_dsim_device *dsim);
+unsigned int s5p_mipi_dsi_get_fifo_state(struct mipi_dsim_device *dsim);
+unsigned int _s5p_mipi_dsi_get_frame_done_status(struct mipi_dsim_device *dsim);
+void _s5p_mipi_dsi_clear_frame_done(struct mipi_dsim_device *dsim);
+void s5p_mipi_dsi_wr_tx_header(struct mipi_dsim_device *dsim, unsigned int di,
+				unsigned int data0, unsigned int data1);
+void s5p_mipi_dsi_wr_tx_data(struct mipi_dsim_device *dsim,
+			unsigned int tx_data);
+
+#endif /* _S5P_MIPI_DSI_LOWLEVEL_H */
-- 
1.7.0.4


^ permalink raw reply related

* [PATCH 1/2] s5pc110: add clock gate for MIPI-DSI controller.
From: Inki Dae @ 2011-01-05 10:34 UTC (permalink / raw)
  To: linux-arm-kernel

the clock gate for MIPI-DSI controller is placed at CLK_GATE_IP1[2]
so it adds a clock object to clock framework for MIPI-DSI clock gating.

Signed-off-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 arch/arm/mach-s5pv210/clock.c |    6 ++++++
 1 files changed, 6 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-s5pv210/clock.c b/arch/arm/mach-s5pv210/clock.c
index dab6ef3..a8d5235 100644
--- a/arch/arm/mach-s5pv210/clock.c
+++ b/arch/arm/mach-s5pv210/clock.c
@@ -365,6 +365,12 @@ static struct clk init_clocks_disable[] = {
 		.enable		= s5pv210_clk_ip1_ctrl,
 		.ctrlbit	= (1<<0),
 	}, {
+		.name		= "dsim",
+		.id		= -1,
+		.parent		= &clk_hclk_dsys.clk,
+		.enable		= s5pv210_clk_ip1_ctrl,
+		.ctrlbit	= (1<<2),
+	}, {
 		.name		= "cfcon",
 		.id		= 0,
 		.parent		= &clk_hclk_psys.clk,
-- 
1.7.0.4


^ permalink raw reply related

* [PATCH 0/2] add Samsung SoC based MIPI-DSI support.
From: daeinki @ 2011-01-05 10:31 UTC (permalink / raw)
  To: linux-arm-kernel

Hello, all.

S5PC110 and S5PC210 SoC platform have one or two MIPI-DSI controller.
MIPI-DSI controller can be used to connect MIPI-DSI based LCD Panel.
this patch adds MIPI-DSI controller driver.

to use this driver, MIPI-DSI based LCD panel driver have to register
mipi_dsim_lcd_driver object to MIPI-DSI driver and then when MIPI-DSI
driver is probed, probe callback of LCD panel driver registered would be
called.

this patch includes just only MIPI-DSI driver because now mainline
kernel has no any machine support with MIPI-DSI based LCD panel so this
driver has been tested locally. I will have patch work for it and send
it including machine specific codes in the future.

The patch series contains:

[PATCH 1/2] s5pc110: add clock gate for MIPI-DSI controller.
[PATCH 2/2] s5pc110: add MIPI-DSI controller driver.

thank you.

^ permalink raw reply

* [PATCH] fbdev: sh_mobile_lcdcfb: Enable 32 bpp and 24 bpp support
From: Magnus Damm @ 2011-01-05 10:21 UTC (permalink / raw)
  To: linux-fbdev

From: Magnus Damm <damm@opensource.se>

This patch extends the LCDC driver with 24 bpp
and 32 bpp support.

These modes have been kept disabled earlier due
to dependencies between the potential two LCDC
channels that are exported as two separate
framebuffer devices. The dependency boils down
to a byte swap register that is shared between
multiple channels.

With this patch applied all single channel LCDC
hardware can chose freely from 16, 24 and 32 bpp.
Dual channel LCDC must stick to the same setup
for both channels.

Without this patch only 16 bpp is fully supported.

Signed-off-by: Magnus Damm <damm@opensource.se>
---

 Suitable for the common/fbdev branch in sh-2.6 git.

 drivers/video/sh_mobile_lcdcfb.c |   74 ++++++++++++++++++++++++++++++++------
 1 file changed, 63 insertions(+), 11 deletions(-)

--- 0004/drivers/video/sh_mobile_lcdcfb.c
+++ work/drivers/video/sh_mobile_lcdcfb.c	2011-01-05 19:03:07.000000000 +0900
@@ -139,6 +139,7 @@ struct sh_mobile_lcdc_priv {
 	struct notifier_block notifier;
 	unsigned long saved_shared_regs[NR_SHARED_REGS];
 	int started;
+	int forced_bpp; /* 2 channel LCDC must share bpp setting */
 };
 
 static bool banked(int reg_nr)
@@ -461,13 +462,18 @@ static int sh_mobile_lcdc_start(struct s
 	struct sh_mobile_lcdc_chan *ch;
 	struct sh_mobile_lcdc_board_cfg	*board_cfg;
 	unsigned long tmp;
+	int bpp = 0;
 	int k, m;
 	int ret = 0;
 
 	/* enable clocks before accessing the hardware */
-	for (k = 0; k < ARRAY_SIZE(priv->ch); k++)
-		if (priv->ch[k].enabled)
+	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
+		if (priv->ch[k].enabled) {
 			sh_mobile_lcdc_clk_on(priv);
+			if (!bpp)
+				bpp = priv->ch[k].info->var.bits_per_pixel;
+		}
+	}
 
 	/* reset */
 	lcdc_write(priv, _LDCNT2R, lcdc_read(priv, _LDCNT2R) | LCDC_RESET);
@@ -535,7 +541,17 @@ static int sh_mobile_lcdc_start(struct s
 	}
 
 	/* word and long word swap */
-	lcdc_write(priv, _LDDDSR, lcdc_read(priv, _LDDDSR) | 6);
+	switch (bpp) {
+	case 16:
+		lcdc_write(priv, _LDDDSR, lcdc_read(priv, _LDDDSR) | 6);
+		break;
+	case 24:
+		lcdc_write(priv, _LDDDSR, lcdc_read(priv, _LDDDSR) | 7);
+		break;
+	case 32:
+		lcdc_write(priv, _LDDDSR, lcdc_read(priv, _LDDDSR) | 4);
+		break;
+	}
 
 	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
 		ch = &priv->ch[k];
@@ -546,7 +562,16 @@ static int sh_mobile_lcdc_start(struct s
 		/* set bpp format in PKF[4:0] */
 		tmp = lcdc_read_chan(ch, LDDFR);
 		tmp &= ~0x0001001f;
-		tmp |= (ch->info->var.bits_per_pixel = 16) ? 3 : 0;
+		switch (ch->info->var.bits_per_pixel) {
+		case 16:
+			tmp |= 0x03;
+			break;
+		case 24:
+			tmp |= 0x0b;
+			break;
+		case 32:
+			break;
+		}
 		lcdc_write_chan(ch, LDDFR, tmp);
 
 		/* point out our frame buffer */
@@ -913,6 +938,7 @@ static int sh_mobile_open(struct fb_info
 static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 {
 	struct sh_mobile_lcdc_chan *ch = info->par;
+	struct sh_mobile_lcdc_priv *p = ch->lcdc;
 
 	if (var->xres > MAX_XRES || var->yres > MAX_YRES ||
 	    var->xres * var->yres * (ch->cfg.bpp / 8) * 2 > info->fix.smem_len) {
@@ -922,6 +948,20 @@ static int sh_mobile_check_var(struct fb
 			 PICOS2KHZ(var->pixclock));
 		return -EINVAL;
 	}
+
+	/* only accept the forced_bpp for dual channel configurations */
+	if (p->forced_bpp && p->forced_bpp != var->bits_per_pixel)
+		return -EINVAL;
+
+	switch (var->bits_per_pixel) {
+	case 16: /* PKF[4:0] = 00011 - RGB 565 */
+	case 24: /* PKF[4:0] = 01011 - RGB 888 */
+	case 32: /* PKF[4:0] = 00000 - RGBA 888 */
+		break;
+	default:
+		return -EINVAL;
+	}
+
 	return 0;
 }
 
@@ -954,19 +994,27 @@ static int sh_mobile_lcdc_set_bpp(struct
 		var->transp.length = 0;
 		break;
 
-	case 32: /* PKF[4:0] = 00000 - RGB 888
-		  * sh7722 pdf says 00RRGGBB but reality is GGBB00RR
-		  * this may be because LDDDSR has word swap enabled..
-		  */
-		var->red.offset = 0;
+	case 24: /* PKF[4:0] = 01011 - RGB 888 */
+		var->red.offset = 16;
 		var->red.length = 8;
-		var->green.offset = 24;
+		var->green.offset = 8;
 		var->green.length = 8;
-		var->blue.offset = 16;
+		var->blue.offset = 0;
 		var->blue.length = 8;
 		var->transp.offset = 0;
 		var->transp.length = 0;
 		break;
+
+	case 32: /* PKF[4:0] = 00000 - RGBA 888 */
+		var->red.offset = 16;
+		var->red.length = 8;
+		var->green.offset = 8;
+		var->green.length = 8;
+		var->blue.offset = 0;
+		var->blue.length = 8;
+		var->transp.offset = 24;
+		var->transp.length = 8;
+		break;
 	default:
 		return -EINVAL;
 	}
@@ -1170,6 +1218,10 @@ static int __devinit sh_mobile_lcdc_prob
 		goto err1;
 	}
 
+	/* for dual channel LCDC (MAIN + SUB) force shared bpp setting */
+	if (j = 2)
+		priv->forced_bpp = pdata->ch[0].bpp;
+
 	priv->base = ioremap_nocache(res->start, resource_size(res));
 	if (!priv->base)
 		goto err1;

^ permalink raw reply

* Re: [PATCH 0/2 v2] runtime PM for the sh-mobile MIPI DSI driver
From: Paul Mundt @ 2011-01-05  8:33 UTC (permalink / raw)
  To: linux-fbdev
In-Reply-To: <Pine.LNX.4.64.1012271115470.669@axis700.grange>

On Mon, Dec 27, 2010 at 11:23:02AM +0100, Guennadi Liakhovetski wrote:
> This is v2 of the patch series, implementing runtime-pm for the sh-mobile 
> mipi-dsi driver and removing the static clock configuration on the AP4EVB 
> board.

On Wed, Dec 29, 2010 at 09:12:18AM +0100, Guennadi Liakhovetski wrote:
> These patches teach the sh-mobile MIPI DSI driver to use platform data to 
> support different SoC with register layout variations and different LCD 
> panels. Two of these patches affect the actual driver and one - currently 
> its only user - the ap4evb board. To avoid compilation and run-time 
> regressions we have to first add new gields to the header, then set them 
> in the affected platform, and only then modify the driver to use them. 
> This produces an unpleasant dependency chain. Alternatively, all these 
> patches could be merged into one, but that would span multiple subsystems. 
> I leave it to the maintainer to decide:)

I've merged both of these patch series in to the common/fdev-mipi branch
in the SH/R-Mobile tree and then merged that topic branch in to the fbdev
tree. Both needed a bit of mangling to merge on top of Magnus's earlier
patches, so you may want to verify that I haven't broken anything
accidentally.

^ permalink raw reply

* Re: Using s3virge card in Sun Blade 2000
From: Alex Buell @ 2011-01-04 20:38 UTC (permalink / raw)
  To: David Miller; +Cc: linux-fbdev, linux-kernel
In-Reply-To: <20110104.121958.232738534.davem@davemloft.net>

On Tue, 2011-01-04 at 12:19 -0800, David Miller wrote:

> First of all, the machine dies because those illegal I/O accesses
> generate an unrecoverable asynchronous memory error, we cannot recover
> from it so we have to panic the entire machine.
> 
> Secondly, the keyboard doesn't work because I never implemented the
> monstrous amount of code necessary to allow USB keyboard to work with
> OpenPROM after booting up.
> 
> You have to essentially reset the entire USB host controller, unload
> all of the pending queued URBs in the host controller, put it into a
> quiescent state, and then asynchronously process all USB keyboard
> device events via USB host controller polling implemented via OpenPROM
> backcalls into the kernel, and from there feed the characters to
> OpenPROM so it can see the keypresses.  Upon return from OpenPROM you
> have to reload all of the unloaded URBs back onto the USB host
> controller queues so the kernel can use USB again.
> 
> I never considered this enormous amount of work worth doing, the
> payback is just too small.

Thank you for that explanation, it's much appreciated.
-- 
Tactical Nuclear Kittens

^ permalink raw reply

* Re: Using s3virge card in Sun Blade 2000
From: David Miller @ 2011-01-04 20:19 UTC (permalink / raw)
  To: alex.buell; +Cc: linux-fbdev, linux-kernel
In-Reply-To: <1294171877.17576.24.camel@lithium>

From: Alex Buell <alex.buell@munted.org.uk>
Date: Tue, 04 Jan 2011 20:11:17 +0000

> I'm already doing that. In the instances where it results in a crash and
> reboots are impossible, dropping into the OpenPROM results in a total
> system freeze, cannot type anything in, this means a big red switch
> time. Solaris didn't have this problem. Any ideas why Linux does this to
> the OpenPROM? 

First of all, the machine dies because those illegal I/O accesses
generate an unrecoverable asynchronous memory error, we cannot recover
from it so we have to panic the entire machine.

Secondly, the keyboard doesn't work because I never implemented the
monstrous amount of code necessary to allow USB keyboard to work with
OpenPROM after booting up.

You have to essentially reset the entire USB host controller, unload
all of the pending queued URBs in the host controller, put it into a
quiescent state, and then asynchronously process all USB keyboard
device events via USB host controller polling implemented via OpenPROM
backcalls into the kernel, and from there feed the characters to
OpenPROM so it can see the keypresses.  Upon return from OpenPROM you
have to reload all of the unloaded URBs back onto the USB host
controller queues so the kernel can use USB again.

I never considered this enormous amount of work worth doing, the
payback is just too small.

^ permalink raw reply

* Re: Using s3virge card in Sun Blade 2000
From: Alex Buell @ 2011-01-04 20:11 UTC (permalink / raw)
  To: David Miller; +Cc: linux-fbdev, linux-kernel
In-Reply-To: <20110104.092637.226761806.davem@davemloft.net>

On Tue, 2011-01-04 at 09:26 -0800, David Miller wrote:
> From: Alex Buell <alex.buell@munted.org.uk>
> Date: Tue, 04 Jan 2011 15:57:07 +0000
> 
> > On Mon, 2011-01-03 at 14:36 -0800, David Miller wrote:
> >> From: Alex Buell <alex.buell@munted.org.uk>
> >> Date: Mon, 03 Jan 2011 21:36:13 +0000
> >> 
> >> > Those are 32 bit addresses, so I suppose I should be getting the base
> >> > address for the registers accesses from region 1, right? 
> >> 
> >> Yes, and pre-computed addresses exist in pci_region_start(pdev, 1).
> > 
> > Do you have any tips for reducing the amount of reboots I have to do
> > whenever I try loading the s3fb module after changing code? 
> 
> You should build s3fb as a module, block it from auto-loading in
> /etc/modules.conf, and then load it explicitly by hand as you
> make changes and recompile.

I'm already doing that. In the instances where it results in a crash and
reboots are impossible, dropping into the OpenPROM results in a total
system freeze, cannot type anything in, this means a big red switch
time. Solaris didn't have this problem. Any ideas why Linux does this to
the OpenPROM? 
-- 
Tactical Nuclear Kittens

^ permalink raw reply

* Re: Using s3virge card in Sun Blade 2000
From: David Miller @ 2011-01-04 17:26 UTC (permalink / raw)
  To: alex.buell; +Cc: linux-fbdev, linux-kernel
In-Reply-To: <1294156627.17576.21.camel@lithium>

From: Alex Buell <alex.buell@munted.org.uk>
Date: Tue, 04 Jan 2011 15:57:07 +0000

> On Mon, 2011-01-03 at 14:36 -0800, David Miller wrote:
>> From: Alex Buell <alex.buell@munted.org.uk>
>> Date: Mon, 03 Jan 2011 21:36:13 +0000
>> 
>> > Those are 32 bit addresses, so I suppose I should be getting the base
>> > address for the registers accesses from region 1, right? 
>> 
>> Yes, and pre-computed addresses exist in pci_region_start(pdev, 1).
> 
> Do you have any tips for reducing the amount of reboots I have to do
> whenever I try loading the s3fb module after changing code? 

You should build s3fb as a module, block it from auto-loading in
/etc/modules.conf, and then load it explicitly by hand as you
make changes and recompile.

^ permalink raw reply

* Re: Using s3virge card in Sun Blade 2000
From: Alex Buell @ 2011-01-04 15:57 UTC (permalink / raw)
  To: David Miller; +Cc: linux-fbdev, linux-kernel
In-Reply-To: <20110103.143625.193710368.davem@davemloft.net>

On Mon, 2011-01-03 at 14:36 -0800, David Miller wrote:
> From: Alex Buell <alex.buell@munted.org.uk>
> Date: Mon, 03 Jan 2011 21:36:13 +0000
> 
> > Those are 32 bit addresses, so I suppose I should be getting the base
> > address for the registers accesses from region 1, right? 
> 
> Yes, and pre-computed addresses exist in pci_region_start(pdev, 1).

Do you have any tips for reducing the amount of reboots I have to do
whenever I try loading the s3fb module after changing code? 
-- 
Tactical Nuclear Kittens

^ permalink raw reply

* RE: [PATCH v6] viafb: I2C/DDC legacy & detect output device if
From: Janorkar, Mayuresh @ 2011-01-04 14:49 UTC (permalink / raw)
  To: linux-fbdev
In-Reply-To: <4D232EF2.2020700@bspu.unibel.by>

minor comments:

> -----Original Message-----
> From: linux-fbdev-owner@vger.kernel.org [mailto:linux-fbdev-
> owner@vger.kernel.org] On Behalf Of Dzianis Kahanovich
> Sent: Tuesday, January 04, 2011 8:00 PM
> To: Florian Tobias Schandinat
> Cc: Paul Mundt; Joseph Chan; linux-fbdev@vger.kernel.org
> Subject: [PATCH v6] viafb: I2C/DDC legacy & detect output device if
> viafb_active_dev unset
> 
> Adding output device detection. Including legacy I2C/DDC code, currently
> safe
> mostly for LCD, think "unknown" device as forced CRT. Detect whole output
> config
> if "viafb_active_dev" unset, or undetected else LCDs in other cases. Also
> early
> viafb_crt_enable if CRT ON - to force CRT DDC detection and multi-out in
> textmode as positive side-effect.
> 
> v5 - check adapter->algo_data (against multiple viafb_find_i2c_adapter()
> behaviours).
> v6 - fix CRT ON/OFF.
> 
> Signed-off-by: Dzianis Kahanovich <mahatma@eu.by>
> ---
> ---
[Mayuresh]: Why two separators?? Generally only one separator (---) is used.

 a/drivers/video/via/viafbdev.c	2011-01-04 13:10:20.000000000 +0200
> +++ b/drivers/video/via/viafbdev.c	2011-01-04 13:12:34.000000000 +0200
> @@ -1670,6 +1670,119 @@ static int parse_mode(const char *str, u
>  	return 0;
>  }
> 
> +/* Add devices, detected only via i2c legacy.
> +   Really there may be CRT too, but unless I got no CRT DDC - LCD only.
> +   Possible CRT may be found as "unknown" to keep CRT ON.
> +   Set LCD/DVI/CRT if viafb_active_dev unset. */


[Mayuresh]: Multi line comments?

> +static void viafb_detect_dev(struct viafb_dev *vdev)
> +{
> +	u8 *edid;
> +	struct fb_var_screeninfo var;
> +	int i, t, ndev = 0, nlcd = 0, unknown = 0;
> +	struct i2c_adapter *adapter;
> +	struct lvds_setting_information *inf;
> +
> +	/* FIXME: viaparinfo1->chip_info looks equal to viaparinfo */
> +	if (viaparinfo->chip_info->tmds_chip_info.tmds_chip_name) {
> +		ndev++;
> +		if (!viafb_active_dev)
> +			viafb_DVI_ON = STATE_ON;
> +	}
> +	if (viaparinfo->chip_info->lvds_chip_info.lvds_chip_name) {
> +		ndev++;
> +		nlcd = 1;
> +		if (!viafb_active_dev)
> +			viafb_LCD_ON = STATE_ON;
> +	}
> +	if (viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name) {
> +		ndev++;
> +		nlcd = 2;
> +		if (!viafb_active_dev)
> +			viafb_LCD2_ON = STATE_ON;
> +	}
> +	/* enabling CRT in textmode is at least no bad */
> +	if (viafb_CRT_ON) {
> +		ndev++;
> +		via_set_state(VIA_CRT, VIA_STATE_ON);
> +	}
> +	for (i = 0; i < VIAFB_NUM_PORTS; i++) {
> +		t = vdev->port_cfg[i].type;
> +		/* detect only i2c ports, undetected in other places */
> +		if ((viaparinfo && viaparinfo->chip_info && (
> +		    (viaparinfo->chip_info->tmds_chip_info.tmds_chip_name &&
> +		    viaparinfo->chip_info->tmds_chip_info.i2c_port = t) ||
> +		    (viaparinfo->chip_info->lvds_chip_info.lvds_chip_name &&
> +		    viaparinfo->chip_info->lvds_chip_info.i2c_port = t) ||
> +		    (viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name &&
> +		    viaparinfo->chip_info->lvds_chip_info2.i2c_port = t)
> +		    )) || (viaparinfo1 && viaparinfo1->chip_info && (
> +		    (viaparinfo1->chip_info->tmds_chip_info.tmds_chip_name &&
> +		    viaparinfo1->chip_info->tmds_chip_info.i2c_port = t) ||
> +		    (viaparinfo1->chip_info->lvds_chip_info.lvds_chip_name &&
> +		    viaparinfo1->chip_info->lvds_chip_info.i2c_port = t) ||
> +		    (viaparinfo1->chip_info->lvds_chip_info2.lvds_chip_name &&
> +		    viaparinfo1->chip_info->lvds_chip_info2.i2c_port = t)
> +		    )) || !(adapter = viafb_find_i2c_adapter(i)) ||
> +		    !adapter->algo_data || !(edid = fb_ddc_read(adapter)))
[Mayuresh]: Does not look readable.
How about writing a function to check if these pointers are available and pass viaparinfo and viaparinfo1 to it. You can keep a check for adapter and edid here.

> +			continue;
> +		memset(&var, 0, sizeof(var));
> +		if (fb_parse_edid(edid, &var))
> +			goto free_edid;
> +		printk(KERN_INFO "viafb: %48s\n", adapter->name);
> +		inf = NULL;
> +		if (!nlcd) {
> +			fb_edid_to_monspecs(edid, &viafbinfo->monspecs);
> +			if (viafbinfo->monspecs.input & FB_DISP_DDI)
> +				inf = viaparinfo->lvds_setting_info;
> +			else
> +				unknown++;
> +		} else if (nlcd > 1) {
> +			printk(KERN_ERR "viafb: too many LCD\n");
> +			unknown++;
> +		} else if (viafb_dual_fb) {
> +			fb_edid_to_monspecs(edid, &viafbinfo1->monspecs);
> +			if (viafbinfo1->monspecs.input & FB_DISP_DDI)
> +				inf = viaparinfo1->lvds_setting_info;
> +			else
> +				unknown++;
> +		} else {
> +			fb_edid_to_monspecs(edid, &viafbinfo->monspecs);
> +			if (viafbinfo->monspecs.input & FB_DISP_DDI)
> +				inf = viaparinfo->lvds_setting_info2;
> +			else
> +				unknown++;
> +		}
> +		if (inf) {
> +			if (!viafb_active_dev) {
> +				if (nlcd)
> +					viafb_LCD2_ON = STATE_ON;
> +				else
> +					viafb_LCD_ON = STATE_ON;
> +			}
> +			nlcd++;
> +			if (var.xres)
> +				inf->lcd_panel_hres = var.xres;
> +			if (var.yres)
> +				inf->lcd_panel_vres = var.yres;
> +		}
> +		ndev++;
> +free_edid:
> +		kfree(edid);
> +	}
> +	if (!viafb_active_dev) {
> +		/* prefer CRT OFF if other devices */
> +		if (!unknown && ndev > 1) {
> +			viafb_CRT_ON = STATE_OFF;
> +			via_set_state(VIA_CRT, VIA_STATE_OFF);
> +		}
> +		viafb_DeviceStatus = viafb_primary_dev > +		    viafb_CRT_ON ? CRT_Device :
> +		    viafb_DVI_ON ? DVI_Device :
> +		    viafb_LCD_ON ? LCD_Device : None_Device;
> +		viafb_set_iga_path();
> +	}
> +}
> +
> 
>  #ifdef CONFIG_PM
>  static int viafb_suspend(void *unused)
> @@ -1891,6 +2004,7 @@ int __devinit via_fb_pci_probe(struct vi
> 
>  	viafb_init_proc(viaparinfo->shared);
>  	viafb_init_dac(IGA2);
> +	viafb_detect_dev(vdev);
> 
>  #ifdef CONFIG_PM
>  	viafb_pm_register(&viafb_fb_pm_hooks);
> --
> --
> To unsubscribe from this list: send the line "unsubscribe linux-fbdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* [PATCH v6] viafb: I2C/DDC legacy & detect output device if viafb_active_dev
From: Dzianis Kahanovich @ 2011-01-04 14:30 UTC (permalink / raw)
  To: linux-fbdev

Adding output device detection. Including legacy I2C/DDC code, currently safe
mostly for LCD, think "unknown" device as forced CRT. Detect whole output config
if "viafb_active_dev" unset, or undetected else LCDs in other cases. Also early
viafb_crt_enable if CRT ON - to force CRT DDC detection and multi-out in
textmode as positive side-effect.

v5 - check adapter->algo_data (against multiple viafb_find_i2c_adapter()
behaviours).
v6 - fix CRT ON/OFF.

Signed-off-by: Dzianis Kahanovich <mahatma@eu.by>
---
--- a/drivers/video/via/viafbdev.c	2011-01-04 13:10:20.000000000 +0200
+++ b/drivers/video/via/viafbdev.c	2011-01-04 13:12:34.000000000 +0200
@@ -1670,6 +1670,119 @@ static int parse_mode(const char *str, u
 	return 0;
 }

+/* Add devices, detected only via i2c legacy.
+   Really there may be CRT too, but unless I got no CRT DDC - LCD only.
+   Possible CRT may be found as "unknown" to keep CRT ON.
+   Set LCD/DVI/CRT if viafb_active_dev unset. */
+static void viafb_detect_dev(struct viafb_dev *vdev)
+{
+	u8 *edid;
+	struct fb_var_screeninfo var;
+	int i, t, ndev = 0, nlcd = 0, unknown = 0;
+	struct i2c_adapter *adapter;
+	struct lvds_setting_information *inf;
+
+	/* FIXME: viaparinfo1->chip_info looks equal to viaparinfo */
+	if (viaparinfo->chip_info->tmds_chip_info.tmds_chip_name) {
+		ndev++;
+		if (!viafb_active_dev)
+			viafb_DVI_ON = STATE_ON;
+	}
+	if (viaparinfo->chip_info->lvds_chip_info.lvds_chip_name) {
+		ndev++;
+		nlcd = 1;
+		if (!viafb_active_dev)
+			viafb_LCD_ON = STATE_ON;
+	}
+	if (viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name) {
+		ndev++;
+		nlcd = 2;
+		if (!viafb_active_dev)
+			viafb_LCD2_ON = STATE_ON;
+	}
+	/* enabling CRT in textmode is at least no bad */
+	if (viafb_CRT_ON) {
+		ndev++;
+		via_set_state(VIA_CRT, VIA_STATE_ON);
+	}
+	for (i = 0; i < VIAFB_NUM_PORTS; i++) {
+		t = vdev->port_cfg[i].type;
+		/* detect only i2c ports, undetected in other places */
+		if ((viaparinfo && viaparinfo->chip_info && (
+		    (viaparinfo->chip_info->tmds_chip_info.tmds_chip_name &&
+		    viaparinfo->chip_info->tmds_chip_info.i2c_port = t) ||
+		    (viaparinfo->chip_info->lvds_chip_info.lvds_chip_name &&
+		    viaparinfo->chip_info->lvds_chip_info.i2c_port = t) ||
+		    (viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name &&
+		    viaparinfo->chip_info->lvds_chip_info2.i2c_port = t)
+		    )) || (viaparinfo1 && viaparinfo1->chip_info && (
+		    (viaparinfo1->chip_info->tmds_chip_info.tmds_chip_name &&
+		    viaparinfo1->chip_info->tmds_chip_info.i2c_port = t) ||
+		    (viaparinfo1->chip_info->lvds_chip_info.lvds_chip_name &&
+		    viaparinfo1->chip_info->lvds_chip_info.i2c_port = t) ||
+		    (viaparinfo1->chip_info->lvds_chip_info2.lvds_chip_name &&
+		    viaparinfo1->chip_info->lvds_chip_info2.i2c_port = t)
+		    )) || !(adapter = viafb_find_i2c_adapter(i)) ||
+		    !adapter->algo_data || !(edid = fb_ddc_read(adapter)))
+			continue;
+		memset(&var, 0, sizeof(var));
+		if (fb_parse_edid(edid, &var))
+			goto free_edid;
+		printk(KERN_INFO "viafb: %48s\n", adapter->name);
+		inf = NULL;
+		if (!nlcd) {
+			fb_edid_to_monspecs(edid, &viafbinfo->monspecs);
+			if (viafbinfo->monspecs.input & FB_DISP_DDI)
+				inf = viaparinfo->lvds_setting_info;
+			else
+				unknown++;
+		} else if (nlcd > 1) {
+			printk(KERN_ERR "viafb: too many LCD\n");
+			unknown++;
+		} else if (viafb_dual_fb) {
+			fb_edid_to_monspecs(edid, &viafbinfo1->monspecs);
+			if (viafbinfo1->monspecs.input & FB_DISP_DDI)
+				inf = viaparinfo1->lvds_setting_info;
+			else
+				unknown++;
+		} else {
+			fb_edid_to_monspecs(edid, &viafbinfo->monspecs);
+			if (viafbinfo->monspecs.input & FB_DISP_DDI)
+				inf = viaparinfo->lvds_setting_info2;
+			else
+				unknown++;
+		}
+		if (inf) {
+			if (!viafb_active_dev) {
+				if (nlcd)
+					viafb_LCD2_ON = STATE_ON;
+				else
+					viafb_LCD_ON = STATE_ON;
+			}
+			nlcd++;
+			if (var.xres)
+				inf->lcd_panel_hres = var.xres;
+			if (var.yres)
+				inf->lcd_panel_vres = var.yres;
+		}
+		ndev++;
+free_edid:
+		kfree(edid);
+	}
+	if (!viafb_active_dev) {
+		/* prefer CRT OFF if other devices */
+		if (!unknown && ndev > 1) {
+			viafb_CRT_ON = STATE_OFF;
+			via_set_state(VIA_CRT, VIA_STATE_OFF);
+		}
+		viafb_DeviceStatus = viafb_primary_dev +		    viafb_CRT_ON ? CRT_Device :
+		    viafb_DVI_ON ? DVI_Device :
+		    viafb_LCD_ON ? LCD_Device : None_Device;
+		viafb_set_iga_path();
+	}
+}
+

 #ifdef CONFIG_PM
 static int viafb_suspend(void *unused)
@@ -1891,6 +2004,7 @@ int __devinit via_fb_pci_probe(struct vi

 	viafb_init_proc(viaparinfo->shared);
 	viafb_init_dac(IGA2);
+	viafb_detect_dev(vdev);

 #ifdef CONFIG_PM
 	viafb_pm_register(&viafb_fb_pm_hooks);
--

^ permalink raw reply

* [PATCH] via-camera: check viafb_find_i2c_adapter() result to NULL
From: Dzianis Kahanovich @ 2011-01-04 11:42 UTC (permalink / raw)
  To: linux-fbdev

If viafb_find_i2c_adapter() patch still useful - via-camera.c must be fixed too.

Signed-off-by: Dzianis Kahanovich <mahatma@eu.by>
---
--- b/drivers/media/video/via-camera.c	2011-01-04 13:08:18.000000000 +0200
+++ c/drivers/media/video/via-camera.c	2011-01-04 13:35:45.000000000 +0200
@@ -1344,8 +1344,9 @@ static __devinit int viacam_probe(struct
 	 * is OLPC-specific.  0x42 assumption is ov7670-specific.
 	 */
 	sensor_adapter = viafb_find_i2c_adapter(VIA_PORT_31);
-	cam->sensor = v4l2_i2c_new_subdev(&cam->v4l2_dev, sensor_adapter,
-			"ov7670", 0x42 >> 1, NULL);
+	if (sensor_adapter != NULL)
+		cam->sensor = v4l2_i2c_new_subdev(&cam->v4l2_dev,
+			sensor_adapter, "ov7670", 0x42 >> 1, NULL);
 	if (cam->sensor = NULL) {
 		dev_err(&pdev->dev, "Unable to find the sensor!\n");
 		ret = -ENODEV;
--

^ permalink raw reply

* [PATCH v5] viafb: I2C/DDC legacy & detect output device if viafb_active_dev
From: Dzianis Kahanovich @ 2011-01-04 11:22 UTC (permalink / raw)
  To: linux-fbdev

Adding output device detection. Including legacy I2C/DDC code, currently safe
mostly for LCD, think "unknown" device as forced CRT. Detect whole output config
if "viafb_active_dev" unset, or undetected else LCDs in other cases. Also early
viafb_crt_enable if CRT ON - to force CRT DDC detection and multi-out in
textmode as positive side-effect.

v5 - check adapter->algo_data (against multiple viafb_find_i2c_adapter()
behaviours).

Signed-off-by: Dzianis Kahanovich <mahatma@eu.by>
---
--- a/drivers/video/via/viafbdev.c	2011-01-04 13:10:20.000000000 +0200
+++ b/drivers/video/via/viafbdev.c	2011-01-04 13:12:34.000000000 +0200
@@ -1670,6 +1670,119 @@ static int parse_mode(const char *str, u
 	return 0;
 }

+/* Add devices, detected only via i2c legacy.
+   Really there may be CRT too, but unless I got no CRT DDC - LCD only.
+   Possible CRT may be found as "unknown" to keep CRT ON.
+   Set LCD/DVI/CRT if viafb_active_dev unset. */
+static void viafb_detect_dev(struct viafb_dev *vdev)
+{
+	u8 *edid;
+	struct fb_var_screeninfo var;
+	int i, t, ndev = 0, nlcd = 0, unknown = 0;
+	struct i2c_adapter *adapter;
+	struct lvds_setting_information *inf;
+
+	/* FIXME: viaparinfo1->chip_info looks equal to viaparinfo */
+	if (viaparinfo->chip_info->tmds_chip_info.tmds_chip_name) {
+		ndev++;
+		if (!viafb_active_dev)
+			viafb_DVI_ON = STATE_ON;
+	}
+	if (viaparinfo->chip_info->lvds_chip_info.lvds_chip_name) {
+		ndev++;
+		nlcd = 1;
+		if (!viafb_active_dev)
+			viafb_LCD_ON = STATE_ON;
+	}
+	if (viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name) {
+		ndev++;
+		nlcd = 2;
+		if (!viafb_active_dev)
+			viafb_LCD2_ON = STATE_ON;
+	}
+	/* enabling CRT in textmode is at least no bad */
+	if (viafb_CRT_ON) {
+		ndev++;
+		viafb_crt_enable();
+	}
+	for (i = 0; i < VIAFB_NUM_PORTS; i++) {
+		t = vdev->port_cfg[i].type;
+		/* detect only i2c ports, undetected in other places */
+		if ((viaparinfo && viaparinfo->chip_info && (
+		    (viaparinfo->chip_info->tmds_chip_info.tmds_chip_name &&
+		    viaparinfo->chip_info->tmds_chip_info.i2c_port = t) ||
+		    (viaparinfo->chip_info->lvds_chip_info.lvds_chip_name &&
+		    viaparinfo->chip_info->lvds_chip_info.i2c_port = t) ||
+		    (viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name &&
+		    viaparinfo->chip_info->lvds_chip_info2.i2c_port = t)
+		    )) || (viaparinfo1 && viaparinfo1->chip_info && (
+		    (viaparinfo1->chip_info->tmds_chip_info.tmds_chip_name &&
+		    viaparinfo1->chip_info->tmds_chip_info.i2c_port = t) ||
+		    (viaparinfo1->chip_info->lvds_chip_info.lvds_chip_name &&
+		    viaparinfo1->chip_info->lvds_chip_info.i2c_port = t) ||
+		    (viaparinfo1->chip_info->lvds_chip_info2.lvds_chip_name &&
+		    viaparinfo1->chip_info->lvds_chip_info2.i2c_port = t)
+		    )) || !(adapter = viafb_find_i2c_adapter(i)) ||
+		    !adapter->algo_data || !(edid = fb_ddc_read(adapter)))
+			continue;
+		memset(&var, 0, sizeof(var));
+		if (fb_parse_edid(edid, &var))
+			goto free_edid;
+		printk(KERN_INFO "viafb: %48s\n", adapter->name);
+		inf = NULL;
+		if (!nlcd) {
+			fb_edid_to_monspecs(edid, &viafbinfo->monspecs);
+			if (viafbinfo->monspecs.input & FB_DISP_DDI)
+				inf = viaparinfo->lvds_setting_info;
+			else
+				unknown++;
+		} else if (nlcd > 1) {
+			printk(KERN_ERR "viafb: too many LCD\n");
+			unknown++;
+		} else if (viafb_dual_fb) {
+			fb_edid_to_monspecs(edid, &viafbinfo1->monspecs);
+			if (viafbinfo1->monspecs.input & FB_DISP_DDI)
+				inf = viaparinfo1->lvds_setting_info;
+			else
+				unknown++;
+		} else {
+			fb_edid_to_monspecs(edid, &viafbinfo->monspecs);
+			if (viafbinfo->monspecs.input & FB_DISP_DDI)
+				inf = viaparinfo->lvds_setting_info2;
+			else
+				unknown++;
+		}
+		if (inf) {
+			if (!viafb_active_dev) {
+				if (nlcd)
+					viafb_LCD2_ON = STATE_ON;
+				else
+					viafb_LCD_ON = STATE_ON;
+			}
+			nlcd++;
+			if (var.xres)
+				inf->lcd_panel_hres = var.xres;
+			if (var.yres)
+				inf->lcd_panel_vres = var.yres;
+		}
+		ndev++;
+free_edid:
+		kfree(edid);
+	}
+	if (!viafb_active_dev) {
+		/* prefer CRT OFF if other devices */
+		if (!unknown && ndev > 1) {
+			viafb_CRT_ON = STATE_OFF;
+			viafb_crt_disable();
+		}
+		viafb_DeviceStatus = viafb_primary_dev +		    viafb_CRT_ON ? CRT_Device :
+		    viafb_DVI_ON ? DVI_Device :
+		    viafb_LCD_ON ? LCD_Device : None_Device;
+		viafb_set_iga_path();
+	}
+}
+

 #ifdef CONFIG_PM
 static int viafb_suspend(void *unused)
@@ -1891,6 +2004,7 @@ int __devinit via_fb_pci_probe(struct vi

 	viafb_init_proc(viaparinfo->shared);
 	viafb_init_dac(IGA2);
+	viafb_detect_dev(vdev);

 #ifdef CONFIG_PM
 	viafb_pm_register(&viafb_fb_pm_hooks);
--

^ permalink raw reply

* Re: [PATCH] viafb: fix viafb_find_i2c_adapt return value
From: Dzianis Kahanovich @ 2011-01-04 11:16 UTC (permalink / raw)
  To: linux-fbdev
In-Reply-To: <4D0FAB7E.1080704@bspu.unibel.by>

Florian Tobias Schandinat wrote:
> [cc'ed Jon; un-cc'ed Joseph as his email address is no longer valid]
> 
> Dzianis Kahanovich schrieb:
>> viafb_find_i2c_adapt return unverifyed value, "is_active" field still uplevel.
>> Fix it.
> 
> This patch looks useful to me but the viafb camera driver uses this function at
> the moment. It's not a big issue now as 31 will be always I2C but perhaps it
> might be a good idea to patch drivers/media/video/via-camera.c

Oops!

> 
> Jon, do you agree that this patch is useful, at least as long we do not
> dynamically change the configuration?
> 
> 
> Thanks,
> 
> Florian Tobias Schandinat
> 
>>
>> Signed-off-by: Dzianis Kahanovich <mahatma@eu.by>
>> ---
>> --- a/drivers/video/via/via_i2c.c    2010-12-18 06:42:37.000000000 +0200
>> +++ b/drivers/video/via/via_i2c.c    2010-12-20 19:55:17.000000000 +0200
>> @@ -188,7 +188,7 @@ struct i2c_adapter *viafb_find_i2c_adapt
>>  {
>>      struct via_i2c_stuff *stuff = &via_i2c_par[which];
>>
>> -    return &stuff->adapter;
>> +    return stuff->is_active ? &stuff->adapter : NULL;
>>  }
>>  EXPORT_SYMBOL_GPL(viafb_find_i2c_adapter);
>>
>> -- 
>>
>>
> 
> 
> 


-- 
WBR, Dzianis Kahanovich AKA Denis Kaganovich, http://mahatma.bspu.unibel.by/

^ permalink raw reply

* Re: [patch] xenfb: fix xenfb suspend/resume race
From: Ian Campbell @ 2011-01-04 11:15 UTC (permalink / raw)
  To: Konrad Rzeszutek Wilk
  Cc: Joe Jin, jeremy@goop.org, Andrew Morton,
	linux-fbdev@vger.kernel.org, xen-devel@lists.xensource.com,
	linux-kernel@vger.kernel.org, gurudas.pai@oracle.com,
	greg.marsden@oracle.com, guru.anbalagane@oracle.com
In-Reply-To: <20101230164051.GC24313@dumpdata.com>

On Thu, 2010-12-30 at 16:40 +0000, Konrad Rzeszutek Wilk wrote:
> On Thu, Dec 30, 2010 at 08:56:16PM +0800, Joe Jin wrote:
> > Hi,
> 
> Joe,
> 
> Patch looks good, however..
> 
> I am unclear from your description whether the patch fixes
> the problem (I would presume so). Or does it take a long time
> to hit this race?

I also don't see how the patch relates to the stack trace.

Is the issue is that xenfb_send_event is called between xenfb_resume
(which tears down the state, including evtchn->irq binding) and the
probe/connect of the new fb?

I suspect xenfb_resume should set info->update_wanted to 0. This will
defer updates until we have successfully reconnected.

Otherwise, since xenfb_resume also calls xenfb_connect I presume the
call of xenfb_send_event is asynchronous. Which would suggest that some
other locking is missing.

Ian.


> 
> > 
> > when do migration test, we hit the panic as below:
> > <1>BUG: unable to handle kernel paging request at 0000000b819fdb98
> > <1>IP: [<ffffffff812a588f>] notify_remote_via_irq+0x13/0x34
> > <4>PGD 94b10067 PUD 0
> > <0>Oops: 0000 [#1] SMP
> > <0>last sysfs file: /sys/class/misc/autofs/dev
> > <4>CPU 3
> > <4>Modules linked in: autofs4(U) hidp(U) nfs(U) fscache(U) nfs_acl(U)
> > auth_rpcgss(U) rfcomm(U) l2cap(U) bluetooth(U) rfkill(U) lockd(U) sunrpc(U)
> > nf_conntrack_netbios_ns(U) ipt_REJECT(U) nf_conntrack_ipv4(U)
> > nf_defrag_ipv4(U) xt_state(U) nf_conntrack(U) iptable_filter(U) ip_tables(U)
> > ip6t_REJECT(U) xt_tcpudp(U) ip6table_filter(U) ip6_tables(U) x_tables(U)
> > ipv6(U) parport_pc(U) lp(U) parport(U) snd_seq_dummy(U) snd_seq_oss(U)
> > snd_seq_midi_event(U) snd_seq(U) snd_seq_device(U) snd_pcm_oss(U)
> > snd_mixer_oss(U) snd_pcm(U) snd_timer(U) snd(U) soundcore(U)
> > snd_page_alloc(U) joydev(U) xen_netfront(U) pcspkr(U) xen_blkfront(U)
> > uhci_hcd(U) ohci_hcd(U) ehci_hcd(U)
> > Pid: 18, comm: events/3 Not tainted 2.6.32
> > RIP: e030:[<ffffffff812a588f>]  [<ffffffff812a588f>]
> > ify_remote_via_irq+0x13/0x34
> > RSP: e02b:ffff8800e7bf7bd0  EFLAGS: 00010202
> > RAX: ffff8800e61c8000 RBX: ffff8800e62f82c0 RCX: 0000000000000000
> > RDX: 00000000000001e3 RSI: ffff8800e7bf7c68 RDI: 0000000bfffffff4
> > RBP: ffff8800e7bf7be0 R08: 00000000000001e2 R09: ffff8800e62f82c0
> > R10: 0000000000000001 R11: ffff8800e6386110 R12: 0000000000000000
> > R13: 0000000000000007 R14: ffff8800e62f82e0 R15: 0000000000000240
> > FS:  00007f409d3906e0(0000) GS:ffff8800028b8000(0000)
> > GS:0000000000000000
> > CS:  e033 DS: 0000 ES: 0000 CR0: 000000008005003b
> > CR2: 0000000b819fdb98 CR3: 000000003ee3b000 CR4: 0000000000002660
> > DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
> > DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
> > Process events/3 (pid: 18, threadinfo ffff8800e7bf6000, task
> > f8800e7bf4540)
> > Stack:
> >  0000000000000200 ffff8800e61c8000 ffff8800e7bf7c00 ffffffff812712c9
> > <0> ffffffff8100ea5f ffffffff81438d80 ffff8800e7bf7cd0 ffffffff812714ee
> > <0> 0000000000000000 ffffffff81270568 000000000000e030 0000000000010202
> > Call Trace:
> >  [<ffffffff812712c9>] xenfb_send_event+0x5c/0x5e
> >  [<ffffffff8100ea5f>] ? xen_restore_fl_direct_end+0x0/0x1
> >  [<ffffffff81438d80>] ? _spin_unlock_irqrestore+0x16/0x18
> >  [<ffffffff812714ee>] xenfb_refresh+0x1b1/0x1d7
> >  [<ffffffff81270568>] ? sys_imageblit+0x1ac/0x458
> >  [<ffffffff81271786>] xenfb_imageblit+0x2f/0x34
> >  [<ffffffff8126a3e5>] soft_cursor+0x1b5/0x1c8
> >  [<ffffffff8126a137>] bit_cursor+0x4b6/0x4d7
> >  [<ffffffff8100ea5f>] ? xen_restore_fl_direct_end+0x0/0x1
> >  [<ffffffff81438d80>] ? _spin_unlock_irqrestore+0x16/0x18
> >  [<ffffffff81269c81>] ? bit_cursor+0x0/0x4d7
> >  [<ffffffff812656b7>] fb_flashcursor+0xff/0x111
> >  [<ffffffff812655b8>] ? fb_flashcursor+0x0/0x111
> >  [<ffffffff81071812>] worker_thread+0x14d/0x1ed
> >  [<ffffffff81075a8c>] ? autoremove_wake_function+0x0/0x3d
> >  [<ffffffff81438d80>] ? _spin_unlock_irqrestore+0x16/0x18
> >  [<ffffffff810716c5>] ? worker_thread+0x0/0x1ed
> >  [<ffffffff810756e3>] kthread+0x6e/0x76
> >  [<ffffffff81012dea>] child_rip+0xa/0x20
> >  [<ffffffff81011fd1>] ? int_ret_from_sys_call+0x7/0x1b
> >  [<ffffffff8101275d>] ? retint_restore_args+0x5/0x6
> >  [<ffffffff81012de0>] ? child_rip+0x0/0x20
> > Code: 6b ff 0c 8b 87 a4 db 9f 81 66 85 c0 74 08 0f b7 f8 e8 3b ff ff ff c9
> > c3 55 48 89 e5 48 83 ec 10 0f 1f 44 00 00 89 ff 48 6b ff 0c <8b> 87 a4 db 9f
> > 81 66 85 c0 74 14 48 8d 75 f0 0f b7 c0 bf 04 00
> > RIP  [<ffffffff812a588f>] notify_remote_via_irq+0x13/0x34
> >  RSP <ffff8800e7bf7bd0>
> > CR2: 0000000b819fdb98
> > ---[ end trace 098b4b74827595d0 ]---
> > Kernel panic - not syncing: Fatal exception
> > Pid: 18, comm: events/3 Tainted: G      D    2.6.32
> > Call Trace:
> >  [<ffffffff812a029e>] ? card_probe+0x99/0x123
> >  [<ffffffff81056a96>] panic+0xa5/0x162
> >  [<ffffffff8100ea5f>] ? xen_restore_fl_direct_end+0x0/0x1
> >  [<ffffffff81438d80>] ? _spin_unlock_irqrestore+0x16/0x18
> >  [<ffffffff81079824>] ? down_trylock+0x30/0x38
> >  [<ffffffff812a029e>] ? card_probe+0x99/0x123
> >  [<ffffffff8105744c>] ? console_unblank+0x23/0x6f
> >  [<ffffffff81056763>] ? print_oops_end_marker+0x23/0x25
> >  [<ffffffff812a029e>] ? card_probe+0x99/0x123
> >  [<ffffffff81439c76>] oops_end+0xb7/0xc7
> >  [<ffffffff810366de>] no_context+0x1f1/0x200
> >  [<ffffffff812a029e>] ? card_probe+0x99/0x123
> >  [<ffffffff81036931>] __bad_area_nosemaphore+0x183/0x1a6
> >  [<ffffffff812af119>] ? extract_buf+0xbd/0x134
> >  [<ffffffff81030c7b>] ? pvclock_clocksource_read+0x47/0x9e
> >  [<ffffffff810369de>] bad_area_nosemaphore+0x13/0x15
> >  [<ffffffff8143b0ed>] do_page_fault+0x147/0x26c
> >  [<ffffffff81439185>] page_fault+0x25/0x30
> >  [<ffffffff812a588f>] ? notify_remote_via_irq+0x13/0x34
> >  [<ffffffff812712c9>] xenfb_send_event+0x5c/0x5e
> >  [<ffffffff8100ea5f>] ? xen_restore_fl_direct_end+0x0/0x1
> >  [<ffffffff81438d80>] ? _spin_unlock_irqrestore+0x16/0x18
> >  [<ffffffff812714ee>] xenfb_refresh+0x1b1/0x1d7
> >  [<ffffffff81270568>] ? sys_imageblit+0x1ac/0x458
> >  [<ffffffff81271786>] xenfb_imageblit+0x2f/0x34
> >  [<ffffffff8126a3e5>] soft_cursor+0x1b5/0x1c8
> >  [<ffffffff8126a137>] bit_cursor+0x4b6/0x4d7
> >  [<ffffffff8100ea5f>] ? xen_restore_fl_direct_end+0x0/0x1
> >  [<ffffffff81438d80>] ? _spin_unlock_irqrestore+0x16/0x18
> >  [<ffffffff81269c81>] ? bit_cursor+0x0/0x4d7
> >  [<ffffffff812656b7>] fb_flashcursor+0xff/0x111
> >  [<ffffffff812655b8>] ? fb_flashcursor+0x0/0x111
> >  [<ffffffff81071812>] worker_thread+0x14d/0x1ed
> >  [<ffffffff81075a8c>] ? autoremove_wake_function+0x0/0x3d
> >  [<ffffffff81438d80>] ? _spin_unlock_irqrestore+0x16/0x18
> >  [<ffffffff810716c5>] ? worker_thread+0x0/0x1ed
> >  [<ffffffff810756e3>] kthread+0x6e/0x76
> >  [<ffffffff81012dea>] child_rip+0xa/0x20
> >  [<ffffffff81011fd1>] ? int_ret_from_sys_call+0x7/0x1b
> >  [<ffffffff8101275d>] ? retint_restore_args+0x5/0x6
> >  [<ffffffff81012de0>] ? child_rip+0x0/0x20
> >  [<ffffffff81012de0>] ? child_rip+0x0/0x20
> > 
> > Check the source found this maybe caused by kernel tried to used not ready
> > xenfb when resume.
> > 
> > Below is the potential fix, please reivew it
> > 
> > Signed-off-by: Joe Jin <joe.jin@oracle.com>
> > Cc: Ian Campbell <ian.campbell@citrix.com>
> > Cc: Jeremy Fitzhardinge <jeremy@goop.org>
> > Cc: Andrew Morton <akpm@linux-foundation.org>
> > 
> > ---
> >  xen-fbfront.c |   19 +++++++++++--------
> >  1 file changed, 11 insertions(+), 8 deletions(-)
> > 
> > diff --git a/drivers/video/xen-fbfront.c b/drivers/video/xen-fbfront.c
> > index dc72563..367fb1c 100644
> > --- a/drivers/video/xen-fbfront.c
> > +++ b/drivers/video/xen-fbfront.c
> > @@ -561,26 +561,24 @@ static void xenfb_init_shared_page(struct xenfb_info *info,
> >  static int xenfb_connect_backend(struct xenbus_device *dev,
> >  				 struct xenfb_info *info)
> >  {
> > -	int ret, evtchn;
> > +	int ret, evtchn, irq;
> >  	struct xenbus_transaction xbt;
> >  
> >  	ret = xenbus_alloc_evtchn(dev, &evtchn);
> >  	if (ret)
> >  		return ret;
> > -	ret = bind_evtchn_to_irqhandler(evtchn, xenfb_event_handler,
> > +	irq = bind_evtchn_to_irqhandler(evtchn, xenfb_event_handler,
> >  					0, dev->devicetype, info);
> > -	if (ret < 0) {
> > +	if (irq < 0) {
> >  		xenbus_free_evtchn(dev, evtchn);
> >  		xenbus_dev_fatal(dev, ret, "bind_evtchn_to_irqhandler");
> > -		return ret;
> > +		return irq;
> >  	}
> > -	info->irq = ret;
> > -
> >   again:
> >  	ret = xenbus_transaction_start(&xbt);
> >  	if (ret) {
> >  		xenbus_dev_fatal(dev, ret, "starting transaction");
> > -		return ret;
> > +		goto unbind_irq;
> >  	}
> >  	ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu",
> >  			    virt_to_mfn(info->page));
> > @@ -602,15 +600,20 @@ static int xenfb_connect_backend(struct xenbus_device *dev,
> >  		if (ret = -EAGAIN)
> >  			goto again;
> >  		xenbus_dev_fatal(dev, ret, "completing transaction");
> > -		return ret;
> > +		goto unbind_irq;
> >  	}
> >  
> >  	xenbus_switch_state(dev, XenbusStateInitialised);
> > +	info->irq = irq;
> >  	return 0;
> >  
> >   error_xenbus:
> >  	xenbus_transaction_end(xbt, 1);
> >  	xenbus_dev_fatal(dev, ret, "writing xenstore");
> > + unbind_irq:
> > +	printk(KERN_ERR "xenfb_connect_backend failed!\n");
> > +	unbind_from_irqhandler(irq, info);
> > +	xenbus_free_evtchn(dev, evtchn);
> >  	return ret;
> >  }
> >  
> > 
> > 
> > -- 
> > Oracle <http://www.oracle.com>
> > Joe Jin | Team Leader, Software Development | +8610.8278.6295
> > ORACLE | Linux and Virtualization
> > Incubator Building 2-A ZPark | Beijing China, 100094
> > 
> > 
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > Please read the FAQ at  http://www.tux.org/lkml/



^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox