* Re: [PATCH v6 1/2] video: support MIPI-DSI controller driver
From: Kyungmin Park @ 2012-01-19 0:15 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20120118130550.0bdb227e.akpm@linux-foundation.org>
On 1/19/12, Andrew Morton <akpm@linux-foundation.org> wrote:
> On Wed, 18 Jan 2012 11:03:56 +0900
> Donghwa Lee <dh09.lee@samsung.com> wrote:
>
>> Samsung S5PC210 and EXYNOS SoC platform has MIPI-DSI controller and
>> MIPI-DSI
>> based LCD Panel could be used with it. This patch supports MIPI-DSI driver
>> based Samsung SoC chip.
>>
>> LCD panel driver based MIPI-DSI should be registered to MIPI-DSI driver at
>> machine code and LCD panel driver specific function registered to
>> mipi_dsim_ddi
>> structure at lcd panel init function called system init.
>> In the MIPI-DSI driver, find lcd panel driver by using registered
>> lcd panel name, and then initialize lcd panel driver.
>>
>
> The code looks nice to me. I assume that Florian will be processing
> the patch?
Hi,
As I know today is the last day for merge, So if you don't mind and
it's okay. we hope to merge it first and fix it at rc period as you
commented.
And another patch from Andrew, it's also helpful if it's merge also
Thank you,
Kyungmin Park
>
> A few minor comments:
>
>>
>> ...
>>
>> +#define master_to_driver(a) (a->dsim_lcd_drv)
>> +#define master_to_device(a) (a->dsim_lcd_dev)
>> +#define dev_to_dsim(a) platform_get_drvdata(to_platform_device(a))
>
> These aren't very type-safe: can be called on any struct whcih has a
> field called "dsim_lcd_drv". Also the "a" should be parenthesized to
> prevent obscure compile problems.
>
> Really, it's best to do away with all such problems by implementing
> these helpers in C rather than in cpp!
>
>>
>> ...
>>
>> +int s5p_mipi_dsi_register_lcd_device(struct mipi_dsim_lcd_device
>> *lcd_dev)
>> +{
>> + struct mipi_dsim_ddi *dsim_ddi;
>> +
>> + if (!lcd_dev) {
>> + pr_err("mipi_dsim_lcd_device is NULL.\n");
>> + return -EFAULT;
>> + }
>
> Can this happen? If not then BUG() is more appropriate. Or just
> remove the code altogether and let the kernel oops.
>
>
>> + if (!lcd_dev->name) {
>> + pr_err("dsim_lcd_device name is NULL.\n");
>> + return -EFAULT;
>> + }
>
> Ditto.
>
>> + dsim_ddi = kzalloc(sizeof(struct mipi_dsim_ddi), GFP_KERNEL);
>> + if (!dsim_ddi) {
>> + pr_err("failed to allocate dsim_ddi object.\n");
>> + return -EFAULT;
>
> Should be ENOMEM.
>
>> + }
>> +
>> + dsim_ddi->dsim_lcd_dev = lcd_dev;
>> +
>> + mutex_lock(&mipi_dsim_lock);
>> + list_add_tail(&dsim_ddi->list, &dsim_ddi_list);
>> + mutex_unlock(&mipi_dsim_lock);
>> +
>> + return 0;
>> +}
>> +
>> +struct mipi_dsim_ddi
>> + *s5p_mipi_dsi_find_lcd_device(struct mipi_dsim_lcd_driver *lcd_drv)
>
> Strange code layout.
>
>> +{
>> + struct mipi_dsim_ddi *dsim_ddi, *next;
>> + struct mipi_dsim_lcd_device *lcd_dev;
>> +
>> + mutex_lock(&mipi_dsim_lock);
>> +
>> + list_for_each_entry_safe(dsim_ddi, next, &dsim_ddi_list, list) {
>> + if (!dsim_ddi)
>> + goto out;
>> +
>> + lcd_dev = dsim_ddi->dsim_lcd_dev;
>> + if (!lcd_dev)
>> + continue;
>> +
>> + if ((strcmp(lcd_drv->name, lcd_dev->name)) = 0) {
>
> hm, using strcmp() to compare devices in this way looks fishy. But I
> don't know what is going on here.
>
>> + /**
>> + * bus_id would be used to identify
>> + * connected bus.
>> + */
>> + dsim_ddi->bus_id = lcd_dev->bus_id;
>> + mutex_unlock(&mipi_dsim_lock);
>> +
>> + return dsim_ddi;
>> + }
>> +
>> + list_del(&dsim_ddi->list);
>> + kfree(dsim_ddi);
>> + }
>> +
>> +out:
>> + mutex_unlock(&mipi_dsim_lock);
>> +
>> + return NULL;
>> +}
>> +
>> +int s5p_mipi_dsi_register_lcd_driver(struct mipi_dsim_lcd_driver
>> *lcd_drv)
>> +{
>> + struct mipi_dsim_ddi *dsim_ddi;
>> +
>> + if (!lcd_drv) {
>> + pr_err("mipi_dsim_lcd_driver is NULL.\n");
>> + return -EFAULT;
>> + }
>> +
>> + if (!lcd_drv->name) {
>> + pr_err("dsim_lcd_driver name is NULL.\n");
>> + return -EFAULT;
>> + }
>> +
>> + dsim_ddi = s5p_mipi_dsi_find_lcd_device(lcd_drv);
>> + if (!dsim_ddi) {
>> + pr_err("mipi_dsim_ddi object not found.\n");
>> + return -EFAULT;
>> + }
>
> Boy, someone really likes EFAULT!
>
>> + dsim_ddi->dsim_lcd_drv = lcd_drv;
>> +
>> + pr_info("registered panel driver(%s) to mipi-dsi driver.\n",
>> + lcd_drv->name);
>> +
>> + return 0;
>> +
>> +}
>> +
>> +struct mipi_dsim_ddi
>> + *s5p_mipi_dsi_bind_lcd_ddi(struct mipi_dsim_device *dsim,
>> + const char *name)
>
> More code layout oddness.
>
>> +{
>> + struct mipi_dsim_ddi *dsim_ddi, *next;
>> + struct mipi_dsim_lcd_driver *lcd_drv;
>> + struct mipi_dsim_lcd_device *lcd_dev;
>> + int ret;
>> +
>> + mutex_lock(&dsim->lock);
>> +
>> + list_for_each_entry_safe(dsim_ddi, next, &dsim_ddi_list, list) {
>> + lcd_drv = dsim_ddi->dsim_lcd_drv;
>> + lcd_dev = dsim_ddi->dsim_lcd_dev;
>> + if (!lcd_drv || !lcd_dev ||
>> + (dsim->id != dsim_ddi->bus_id))
>> + continue;
>> +
>> + dev_dbg(dsim->dev, "lcd_drv->id = %d, lcd_dev->id = %d\n",
>> + lcd_drv->id, lcd_dev->id);
>> + dev_dbg(dsim->dev, "lcd_dev->bus_id = %d, dsim->id = %d\n",
>> + lcd_dev->bus_id, dsim->id);
>> +
>> + if ((strcmp(lcd_drv->name, name) = 0)) {
>> + lcd_dev->master = dsim;
>> +
>> + lcd_dev->dev.parent = dsim->dev;
>> + dev_set_name(&lcd_dev->dev, "%s", lcd_drv->name);
>> +
>> + ret = device_register(&lcd_dev->dev);
>> + if (ret < 0) {
>> + dev_err(dsim->dev,
>> + "can't register %s, status %d\n",
>> + dev_name(&lcd_dev->dev), ret);
>> + mutex_unlock(&dsim->lock);
>> +
>> + return NULL;
>> + }
>> +
>> + dsim->dsim_lcd_dev = lcd_dev;
>> + dsim->dsim_lcd_drv = lcd_drv;
>> +
>> + mutex_unlock(&dsim->lock);
>> +
>> + return dsim_ddi;
>> + }
>> + }
>> +
>> + mutex_unlock(&dsim->lock);
>> +
>> + return NULL;
>> +}
>>
>> ...
>>
>> +static int s5p_mipi_dsi_probe(struct platform_device *pdev)
>> +{
>> + struct resource *res;
>> + struct mipi_dsim_device *dsim;
>> + struct mipi_dsim_config *dsim_config;
>> + struct mipi_dsim_platform_data *dsim_pd;
>> + struct mipi_dsim_ddi *dsim_ddi;
>> + int ret = -EINVAL;
>> +
>> + dsim = kzalloc(sizeof(struct mipi_dsim_device), GFP_KERNEL);
>> + if (!dsim) {
>> + dev_err(&pdev->dev, "failed to allocate dsim object.\n");
>> + return -EFAULT;
>
> ENOMEM!
>
>> + }
>> +
>> + dsim->pd = to_dsim_plat(pdev);
>> + dsim->dev = &pdev->dev;
>> + dsim->id = pdev->id;
>> +
>> + /* get mipi_dsim_platform_data. */
>> + dsim_pd = (struct mipi_dsim_platform_data *)dsim->pd;
>> + if (dsim_pd = NULL) {
>> + dev_err(&pdev->dev, "failed to get platform data for dsim.\n");
>> + goto err_clock_get;
>> + }
>>
>> ...
>>
>> +irqreturn_t s5p_mipi_dsi_interrupt_handler(int irq, void *dev_id)
>> +{
>> + unsigned int intsrc = 0;
>> + unsigned int intmsk = 0;
>> + struct mipi_dsim_device *dsim = NULL;
>> +
>> + dsim = (struct mipi_dsim_device *)dev_id;
>
> unneeded and undesirable cast of void*
>
>> + if (!dsim) {
>> + dev_dbg(dsim->dev, KERN_ERR "%s:error: wrong parameter\n",
>> + __func__);
>> + return IRQ_HANDLED;
>> + }
>> +
>> + intsrc = s5p_mipi_dsi_read_interrupt(dsim);
>> + intmsk = s5p_mipi_dsi_read_interrupt_mask(dsim);
>> +
>> + intmsk = ~(intmsk) & intsrc;
>> +
>> + switch (intmsk) {
>> + case INTMSK_RX_DONE:
>> + complete(&dsim_rd_comp);
>> + dev_dbg(dsim->dev, "MIPI INTMSK_RX_DONE\n");
>> + break;
>> + case INTMSK_FIFO_EMPTY:
>> + complete(&dsim_wr_comp);
>> + dev_dbg(dsim->dev, "MIPI INTMSK_FIFO_EMPTY\n");
>> + break;
>> + default:
>> + break;
>> + }
>> +
>> + s5p_mipi_dsi_clear_interrupt(dsim, intmsk);
>> +
>> + return IRQ_HANDLED;
>> +}
>>
>> ...
>>
>
> Generally: the use of the Efoo errno codes is chaotic. Please check it
> all over.
>
>
> _______________________________________________
> 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 v6 2/2] video: backlight: support s6e8ax0 panel driver based on MIPI DSI
From: Andrew Morton @ 2012-01-18 21:52 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <4F162890.2020407@samsung.com>
On Wed, 18 Jan 2012 11:04:00 +0900
Donghwa Lee <dh09.lee@samsung.com> wrote:
> This patch is amoled panel driver based MIPI DSI interface.
> S6E8AX0 means it may includes many other ldi controllers, for example,
> S6E8AA0, S6E8AB0, and so on.
>
> This patch can be modified depending on each panel properites. For example,
> second parameter of panel condition register can be changed depending on
> ldi controller or amoled type.
I have a patch for your patch!
Before:
akpm:/usr/src/25> size drivers/video/backlight/s6e8ax0.o
text data bss dec hex filename
4736 632 8 5376 1500 drivers/video/backlight/s6e8ax0.o
After:
akpm:/usr/src/25> size drivers/video/backlight/s6e8ax0.o
text data bss dec hex filename
4360 632 8 5000 1388 drivers/video/backlight/s6e8ax0.o
--- a/drivers/video/backlight/s6e8ax0.c~video-backlight-support-s6e8ax0-panel-driver-based-on-mipi-dsi-fix
+++ a/drivers/video/backlight/s6e8ax0.c
@@ -105,157 +105,157 @@ out:
mutex_unlock(&lcd->lock);
}
-const unsigned char s6e8ax0_22_gamma_30[] = {
+static const unsigned char s6e8ax0_22_gamma_30[] = {
0xfa, 0x01, 0x60, 0x10, 0x60, 0xf5, 0x00, 0xff, 0xad, 0xaf,
0xbA, 0xc3, 0xd8, 0xc5, 0x9f, 0xc6, 0x9e, 0xc1, 0xdc, 0xc0,
0x00, 0x61, 0x00, 0x5a, 0x00, 0x74,
};
-const unsigned char s6e8ax0_22_gamma_50[] = {
+static const unsigned char s6e8ax0_22_gamma_50[] = {
0xfa, 0x01, 0x60, 0x10, 0x60, 0xe8, 0x1f, 0xf7, 0xad, 0xc0,
0xb5, 0xc4, 0xdc, 0xc4, 0x9e, 0xc6, 0x9c, 0xbb, 0xd8, 0xbb,
0x00, 0x70, 0x00, 0x68, 0x00, 0x86,
};
-const unsigned char s6e8ax0_22_gamma_60[] = {
+static const unsigned char s6e8ax0_22_gamma_60[] = {
0xfa, 0x01, 0x60, 0x10, 0x60, 0xde, 0x1f, 0xef, 0xad, 0xc4,
0xb3, 0xc3, 0xdd, 0xc4, 0x9e, 0xc6, 0x9c, 0xbc, 0xd6, 0xba,
0x00, 0x75, 0x00, 0x6e, 0x00, 0x8d,
};
-const unsigned char s6e8ax0_22_gamma_70[] = {
+static const unsigned char s6e8ax0_22_gamma_70[] = {
0xfa, 0x01, 0x60, 0x10, 0x60, 0xd8, 0x1f, 0xe7, 0xaf, 0xc8,
0xb4, 0xc4, 0xdd, 0xc3, 0x9d, 0xc6, 0x9c, 0xbb, 0xd6, 0xb9,
0x00, 0x7a, 0x00, 0x72, 0x00, 0x93,
};
-const unsigned char s6e8ax0_22_gamma_80[] = {
+static const unsigned char s6e8ax0_22_gamma_80[] = {
0xfa, 0x01, 0x60, 0x10, 0x60, 0xc9, 0x1f, 0xde, 0xae, 0xc9,
0xb1, 0xc3, 0xdd, 0xc2, 0x9d, 0xc5, 0x9b, 0xbc, 0xd6, 0xbb,
0x00, 0x7f, 0x00, 0x77, 0x00, 0x99,
};
-const unsigned char s6e8ax0_22_gamma_90[] = {
+static const unsigned char s6e8ax0_22_gamma_90[] = {
0xfa, 0x01, 0x60, 0x10, 0x60, 0xc7, 0x1f, 0xd9, 0xb0, 0xcc,
0xb2, 0xc3, 0xdc, 0xc1, 0x9c, 0xc6, 0x9c, 0xbc, 0xd4, 0xb9,
0x00, 0x83, 0x00, 0x7b, 0x00, 0x9e,
};
-const unsigned char s6e8ax0_22_gamma_100[] = {
+static const unsigned char s6e8ax0_22_gamma_100[] = {
0xfa, 0x01, 0x60, 0x10, 0x60, 0xbd, 0x80, 0xcd, 0xba, 0xce,
0xb3, 0xc4, 0xde, 0xc3, 0x9c, 0xc4, 0x9, 0xb8, 0xd3, 0xb6,
0x00, 0x88, 0x00, 0x80, 0x00, 0xa5,
};
-const unsigned char s6e8ax0_22_gamma_120[] = {
+static const unsigned char s6e8ax0_22_gamma_120[] = {
0xfa, 0x01, 0x60, 0x10, 0x60, 0xb9, 0x95, 0xc8, 0xb1, 0xcf,
0xb2, 0xc6, 0xdf, 0xc5, 0x9b, 0xc3, 0x99, 0xb6, 0xd2, 0xb6,
0x00, 0x8f, 0x00, 0x86, 0x00, 0xac,
};
-const unsigned char s6e8ax0_22_gamma_130[] = {
+static const unsigned char s6e8ax0_22_gamma_130[] = {
0xfa, 0x01, 0x60, 0x10, 0x60, 0xb7, 0xa0, 0xc7, 0xb1, 0xd0,
0xb2, 0xc4, 0xdd, 0xc3, 0x9a, 0xc3, 0x98, 0xb6, 0xd0, 0xb4,
0x00, 0x92, 0x00, 0x8a, 0x00, 0xb1,
};
-const unsigned char s6e8ax0_22_gamma_140[] = {
+static const unsigned char s6e8ax0_22_gamma_140[] = {
0xfa, 0x01, 0x60, 0x10, 0x60, 0xb7, 0xa0, 0xc5, 0xb2, 0xd0,
0xb3, 0xc3, 0xde, 0xc3, 0x9b, 0xc2, 0x98, 0xb6, 0xd0, 0xb4,
0x00, 0x95, 0x00, 0x8d, 0x00, 0xb5,
};
-const unsigned char s6e8ax0_22_gamma_150[] = {
+static const unsigned char s6e8ax0_22_gamma_150[] = {
0xfa, 0x01, 0x60, 0x10, 0x60, 0xb3, 0xa0, 0xc2, 0xb2, 0xd0,
0xb2, 0xc1, 0xdd, 0xc2, 0x9b, 0xc2, 0x98, 0xb4, 0xcf, 0xb1,
0x00, 0x99, 0x00, 0x90, 0x00, 0xba,
};
-const unsigned char s6e8ax0_22_gamma_160[] = {
+static const unsigned char s6e8ax0_22_gamma_160[] = {
0xfa, 0x01, 0x60, 0x10, 0x60, 0xaf, 0xa5, 0xbf, 0xb0, 0xd0,
0xb1, 0xc3, 0xde, 0xc2, 0x99, 0xc1, 0x97, 0xb4, 0xce, 0xb1,
0x00, 0x9c, 0x00, 0x93, 0x00, 0xbe,
};
-const unsigned char s6e8ax0_22_gamma_170[] = {
+static const unsigned char s6e8ax0_22_gamma_170[] = {
0xfa, 0x01, 0x60, 0x10, 0x60, 0xaf, 0xb5, 0xbf, 0xb1, 0xd1,
0xb1, 0xc3, 0xde, 0xc3, 0x99, 0xc0, 0x96, 0xb4, 0xce, 0xb1,
0x00, 0x9f, 0x00, 0x96, 0x00, 0xc2,
};
-const unsigned char s6e8ax0_22_gamma_180[] = {
+static const unsigned char s6e8ax0_22_gamma_180[] = {
0xfa, 0x01, 0x60, 0x10, 0x60, 0xaf, 0xb7, 0xbe, 0xb3, 0xd2,
0xb3, 0xc3, 0xde, 0xc2, 0x97, 0xbf, 0x95, 0xb4, 0xcd, 0xb1,
0x00, 0xa2, 0x00, 0x99, 0x00, 0xc5,
};
-const unsigned char s6e8ax0_22_gamma_190[] = {
+static const unsigned char s6e8ax0_22_gamma_190[] = {
0xfa, 0x01, 0x60, 0x10, 0x60, 0xaf, 0xb9, 0xbe, 0xb2, 0xd2,
0xb2, 0xc3, 0xdd, 0xc3, 0x98, 0xbf, 0x95, 0xb2, 0xcc, 0xaf,
0x00, 0xa5, 0x00, 0x9c, 0x00, 0xc9,
};
-const unsigned char s6e8ax0_22_gamma_200[] = {
+static const unsigned char s6e8ax0_22_gamma_200[] = {
0xfa, 0x01, 0x60, 0x10, 0x60, 0xaf, 0xb9, 0xbc, 0xb2, 0xd2,
0xb1, 0xc4, 0xdd, 0xc3, 0x97, 0xbe, 0x95, 0xb1, 0xcb, 0xae,
0x00, 0xa8, 0x00, 0x9f, 0x00, 0xcd,
};
-const unsigned char s6e8ax0_22_gamma_210[] = {
+static const unsigned char s6e8ax0_22_gamma_210[] = {
0xfa, 0x01, 0x60, 0x10, 0x60, 0xb1, 0xc1, 0xbd, 0xb1, 0xd1,
0xb1, 0xc2, 0xde, 0xc2, 0x97, 0xbe, 0x94, 0xB0, 0xc9, 0xad,
0x00, 0xae, 0x00, 0xa4, 0x00, 0xd4,
};
-const unsigned char s6e8ax0_22_gamma_220[] = {
+static const unsigned char s6e8ax0_22_gamma_220[] = {
0xfa, 0x01, 0x60, 0x10, 0x60, 0xb1, 0xc7, 0xbd, 0xb1, 0xd1,
0xb1, 0xc2, 0xdd, 0xc2, 0x97, 0xbd, 0x94, 0xb0, 0xc9, 0xad,
0x00, 0xad, 0x00, 0xa2, 0x00, 0xd3,
};
-const unsigned char s6e8ax0_22_gamma_230[] = {
+static const unsigned char s6e8ax0_22_gamma_230[] = {
0xfa, 0x01, 0x60, 0x10, 0x60, 0xb1, 0xc3, 0xbd, 0xb2, 0xd1,
0xb1, 0xc3, 0xdd, 0xc1, 0x96, 0xbd, 0x94, 0xb0, 0xc9, 0xad,
0x00, 0xb0, 0x00, 0xa7, 0x00, 0xd7,
};
-const unsigned char s6e8ax0_22_gamma_240[] = {
+static const unsigned char s6e8ax0_22_gamma_240[] = {
0xfa, 0x01, 0x60, 0x10, 0x60, 0xb1, 0xcb, 0xbd, 0xb1, 0xd2,
0xb1, 0xc3, 0xdD, 0xc2, 0x95, 0xbd, 0x93, 0xaf, 0xc8, 0xab,
0x00, 0xb3, 0x00, 0xa9, 0x00, 0xdb,
};
-const unsigned char s6e8ax0_22_gamma_250[] = {
+static const unsigned char s6e8ax0_22_gamma_250[] = {
0xfa, 0x01, 0x60, 0x10, 0x60, 0xb3, 0xcc, 0xbe, 0xb0, 0xd2,
0xb0, 0xc3, 0xdD, 0xc2, 0x94, 0xbc, 0x92, 0xae, 0xc8, 0xab,
0x00, 0xb6, 0x00, 0xab, 0x00, 0xde,
};
-const unsigned char s6e8ax0_22_gamma_260[] = {
+static const unsigned char s6e8ax0_22_gamma_260[] = {
0xfa, 0x01, 0x60, 0x10, 0x60, 0xb3, 0xd0, 0xbe, 0xaf, 0xd1,
0xaf, 0xc2, 0xdd, 0xc1, 0x96, 0xbc, 0x93, 0xaf, 0xc8, 0xac,
0x00, 0xb7, 0x00, 0xad, 0x00, 0xe0,
};
-const unsigned char s6e8ax0_22_gamma_270[] = {
+static const unsigned char s6e8ax0_22_gamma_270[] = {
0xfa, 0x01, 0x60, 0x10, 0x60, 0xb2, 0xcF, 0xbd, 0xb0, 0xd2,
0xaf, 0xc2, 0xdc, 0xc1, 0x95, 0xbd, 0x93, 0xae, 0xc6, 0xaa,
0x00, 0xba, 0x00, 0xb0, 0x00, 0xe4,
};
-const unsigned char s6e8ax0_22_gamma_280[] = {
+static const unsigned char s6e8ax0_22_gamma_280[] = {
0xfa, 0x01, 0x60, 0x10, 0x60, 0xb2, 0xd0, 0xbd, 0xaf, 0xd0,
0xad, 0xc4, 0xdd, 0xc3, 0x95, 0xbd, 0x93, 0xac, 0xc5, 0xa9,
0x00, 0xbd, 0x00, 0xb2, 0x00, 0xe7,
};
-const unsigned char s6e8ax0_22_gamma_300[] = {
+static const unsigned char s6e8ax0_22_gamma_300[] = {
0xfa, 0x01, 0x60, 0x10, 0x60, 0xb5, 0xd3, 0xbd, 0xb1, 0xd2,
0xb0, 0xc0, 0xdc, 0xc0, 0x94, 0xba, 0x91, 0xac, 0xc5, 0xa9,
0x00, 0xc2, 0x00, 0xb7, 0x00, 0xed,
};
-const unsigned char *s6e8ax0_22_gamma_table[] = {
+static const unsigned char *s6e8ax0_22_gamma_table[] = {
s6e8ax0_22_gamma_30,
s6e8ax0_22_gamma_50,
s6e8ax0_22_gamma_60,
@@ -287,7 +287,7 @@ static void s6e8ax0_panel_cond(struct s6
{
struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
- const unsigned char data_to_send[] = {
+ static const unsigned char data_to_send[] = {
0xf8, 0x3d, 0x35, 0x00, 0x00, 0x00, 0x93, 0x00, 0x3c, 0x7d,
0x08, 0x27, 0x7d, 0x3f, 0x00, 0x00, 0x00, 0x20, 0x04, 0x08,
0x6e, 0x00, 0x00, 0x00, 0x02, 0x08, 0x08, 0x23, 0x23, 0xc0,
@@ -301,7 +301,7 @@ static void s6e8ax0_panel_cond(struct s6
static void s6e8ax0_display_cond(struct s6e8ax0 *lcd)
{
struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
- const unsigned char data_to_send[] = {
+ static const unsigned char data_to_send[] = {
0xf2, 0x80, 0x03, 0x0d
};
@@ -323,7 +323,7 @@ static void s6e8ax0_gamma_cond(struct s6
static void s6e8ax0_gamma_update(struct s6e8ax0 *lcd)
{
struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
- const unsigned char data_to_send[] = {
+ static const unsigned char data_to_send[] = {
0xf7, 0x03
};
@@ -335,7 +335,7 @@ static void s6e8ax0_gamma_update(struct
static void s6e8ax0_etc_cond1(struct s6e8ax0 *lcd)
{
struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
- const unsigned char data_to_send[] = {
+ static const unsigned char data_to_send[] = {
0xd1, 0xfe, 0x80, 0x00, 0x01, 0x0b, 0x00, 0x00, 0x40,
0x0d, 0x00, 0x00
};
@@ -347,7 +347,7 @@ static void s6e8ax0_etc_cond1(struct s6e
static void s6e8ax0_etc_cond2(struct s6e8ax0 *lcd)
{
struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
- const unsigned char data_to_send[] = {
+ static const unsigned char data_to_send[] = {
0xb6, 0x0c, 0x02, 0x03, 0x32, 0xff, 0x44, 0x44, 0xc0,
0x00
};
@@ -359,7 +359,7 @@ static void s6e8ax0_etc_cond2(struct s6e
static void s6e8ax0_etc_cond3(struct s6e8ax0 *lcd)
{
struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
- const unsigned char data_to_send[] = {
+ static const unsigned char data_to_send[] = {
0xe1, 0x10, 0x1c, 0x17, 0x08, 0x1d
};
@@ -370,7 +370,7 @@ static void s6e8ax0_etc_cond3(struct s6e
static void s6e8ax0_etc_cond4(struct s6e8ax0 *lcd)
{
struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
- const unsigned char data_to_send[] = {
+ static const unsigned char data_to_send[] = {
0xe2, 0xed, 0x07, 0xc3, 0x13, 0x0d, 0x03
};
@@ -381,7 +381,7 @@ static void s6e8ax0_etc_cond4(struct s6e
static void s6e8ax0_etc_cond5(struct s6e8ax0 *lcd)
{
struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
- const unsigned char data_to_send[] = {
+ static const unsigned char data_to_send[] = {
0xf4, 0xcf, 0x0a, 0x12, 0x10, 0x19, 0x33, 0x02
};
@@ -391,7 +391,7 @@ static void s6e8ax0_etc_cond5(struct s6e
static void s6e8ax0_etc_cond6(struct s6e8ax0 *lcd)
{
struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
- const unsigned char data_to_send[] = {
+ static const unsigned char data_to_send[] = {
0xe3, 0x40
};
@@ -403,7 +403,7 @@ static void s6e8ax0_etc_cond6(struct s6e
static void s6e8ax0_etc_cond7(struct s6e8ax0 *lcd)
{
struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
- const unsigned char data_to_send[] = {
+ static const unsigned char data_to_send[] = {
0xe4, 0x00, 0x00, 0x14, 0x80, 0x00, 0x00, 0x00
};
@@ -414,7 +414,7 @@ static void s6e8ax0_etc_cond7(struct s6e
static void s6e8ax0_elvss_set(struct s6e8ax0 *lcd)
{
struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
- const unsigned char data_to_send[] = {
+ static const unsigned char data_to_send[] = {
0xb1, 0x04, 0x00
};
@@ -425,7 +425,7 @@ static void s6e8ax0_elvss_set(struct s6e
static void s6e8ax0_elvss_nvm_set(struct s6e8ax0 *lcd)
{
struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
- const unsigned char data_to_send[] = {
+ static const unsigned char data_to_send[] = {
0xd9, 0x5c, 0x20, 0x0c, 0x0f, 0x41, 0x00, 0x10, 0x11,
0x12, 0xd1, 0x00, 0x00, 0x00, 0x00, 0x80, 0xcb, 0xed,
0x64, 0xaf
@@ -438,7 +438,7 @@ static void s6e8ax0_elvss_nvm_set(struct
static void s6e8ax0_sleep_in(struct s6e8ax0 *lcd)
{
struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
- const unsigned char data_to_send[] = {
+ static const unsigned char data_to_send[] = {
0x10, 0x00
};
@@ -450,7 +450,7 @@ static void s6e8ax0_sleep_in(struct s6e8
static void s6e8ax0_sleep_out(struct s6e8ax0 *lcd)
{
struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
- const unsigned char data_to_send[] = {
+ static const unsigned char data_to_send[] = {
0x11, 0x00
};
@@ -462,7 +462,7 @@ static void s6e8ax0_sleep_out(struct s6e
static void s6e8ax0_display_on(struct s6e8ax0 *lcd)
{
struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
- const unsigned char data_to_send[] = {
+ static const unsigned char data_to_send[] = {
0x29, 0x00
};
@@ -474,7 +474,7 @@ static void s6e8ax0_display_on(struct s6
static void s6e8ax0_display_off(struct s6e8ax0 *lcd)
{
struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
- const unsigned char data_to_send[] = {
+ static const unsigned char data_to_send[] = {
0x28, 0x00
};
@@ -486,7 +486,7 @@ static void s6e8ax0_display_off(struct s
static void s6e8ax0_apply_level2_key(struct s6e8ax0 *lcd)
{
struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
- const unsigned char data_to_send[] = {
+ static const unsigned char data_to_send[] = {
0xf0, 0x5a, 0x5a
};
@@ -497,7 +497,7 @@ static void s6e8ax0_apply_level2_key(str
static void s6e8ax0_acl_on(struct s6e8ax0 *lcd)
{
struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
- const unsigned char data_to_send[] = {
+ static const unsigned char data_to_send[] = {
0xc0, 0x01
};
@@ -509,7 +509,7 @@ static void s6e8ax0_acl_on(struct s6e8ax
static void s6e8ax0_acl_off(struct s6e8ax0 *lcd)
{
struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
- const unsigned char data_to_send[] = {
+ static const unsigned char data_to_send[] = {
0xc0, 0x00
};
@@ -523,21 +523,21 @@ static void s6e8ax0_acl_ctrl_set(struct
{
struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
/* Full white 50% reducing setting */
- const unsigned char cutoff_50[] = {
+ static const unsigned char cutoff_50[] = {
0xc1, 0x47, 0x53, 0x13, 0x53, 0x00, 0x00, 0x02, 0xcf,
0x00, 0x00, 0x04, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x08, 0x0f, 0x16, 0x1d, 0x24, 0x2a, 0x31, 0x38,
0x3f, 0x46
};
/* Full white 45% reducing setting */
- const unsigned char cutoff_45[] = {
+ static const unsigned char cutoff_45[] = {
0xc1, 0x47, 0x53, 0x13, 0x53, 0x00, 0x00, 0x02, 0xcf,
0x00, 0x00, 0x04, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x07, 0x0d, 0x13, 0x19, 0x1f, 0x25, 0x2b, 0x31,
0x37, 0x3d
};
/* Full white 40% reducing setting */
- const unsigned char cutoff_40[] = {
+ static const unsigned char cutoff_40[] = {
0xc1, 0x47, 0x53, 0x13, 0x53, 0x00, 0x00, 0x02, 0xcf,
0x00, 0x00, 0x04, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x06, 0x0c, 0x11, 0x16, 0x1c, 0x21, 0x26, 0x2b,
_
^ permalink raw reply
* Re: [PATCH v6 1/2] video: support MIPI-DSI controller driver
From: Andrew Morton @ 2012-01-18 21:05 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <4F16288C.5020406@samsung.com>
On Wed, 18 Jan 2012 11:03:56 +0900
Donghwa Lee <dh09.lee@samsung.com> wrote:
> Samsung S5PC210 and EXYNOS SoC platform has MIPI-DSI controller and MIPI-DSI
> based LCD Panel could be used with it. This patch supports MIPI-DSI driver
> based Samsung SoC chip.
>
> LCD panel driver based MIPI-DSI should be registered to MIPI-DSI driver at
> machine code and LCD panel driver specific function registered to mipi_dsim_ddi
> structure at lcd panel init function called system init.
> In the MIPI-DSI driver, find lcd panel driver by using registered
> lcd panel name, and then initialize lcd panel driver.
>
The code looks nice to me. I assume that Florian will be processing
the patch?
A few minor comments:
>
> ...
>
> +#define master_to_driver(a) (a->dsim_lcd_drv)
> +#define master_to_device(a) (a->dsim_lcd_dev)
> +#define dev_to_dsim(a) platform_get_drvdata(to_platform_device(a))
These aren't very type-safe: can be called on any struct whcih has a
field called "dsim_lcd_drv". Also the "a" should be parenthesized to
prevent obscure compile problems.
Really, it's best to do away with all such problems by implementing
these helpers in C rather than in cpp!
>
> ...
>
> +int s5p_mipi_dsi_register_lcd_device(struct mipi_dsim_lcd_device *lcd_dev)
> +{
> + struct mipi_dsim_ddi *dsim_ddi;
> +
> + if (!lcd_dev) {
> + pr_err("mipi_dsim_lcd_device is NULL.\n");
> + return -EFAULT;
> + }
Can this happen? If not then BUG() is more appropriate. Or just
remove the code altogether and let the kernel oops.
> + if (!lcd_dev->name) {
> + pr_err("dsim_lcd_device name is NULL.\n");
> + return -EFAULT;
> + }
Ditto.
> + dsim_ddi = kzalloc(sizeof(struct mipi_dsim_ddi), GFP_KERNEL);
> + if (!dsim_ddi) {
> + pr_err("failed to allocate dsim_ddi object.\n");
> + return -EFAULT;
Should be ENOMEM.
> + }
> +
> + dsim_ddi->dsim_lcd_dev = lcd_dev;
> +
> + mutex_lock(&mipi_dsim_lock);
> + list_add_tail(&dsim_ddi->list, &dsim_ddi_list);
> + mutex_unlock(&mipi_dsim_lock);
> +
> + return 0;
> +}
> +
> +struct mipi_dsim_ddi
> + *s5p_mipi_dsi_find_lcd_device(struct mipi_dsim_lcd_driver *lcd_drv)
Strange code layout.
> +{
> + struct mipi_dsim_ddi *dsim_ddi, *next;
> + struct mipi_dsim_lcd_device *lcd_dev;
> +
> + mutex_lock(&mipi_dsim_lock);
> +
> + list_for_each_entry_safe(dsim_ddi, next, &dsim_ddi_list, list) {
> + if (!dsim_ddi)
> + goto out;
> +
> + lcd_dev = dsim_ddi->dsim_lcd_dev;
> + if (!lcd_dev)
> + continue;
> +
> + if ((strcmp(lcd_drv->name, lcd_dev->name)) = 0) {
hm, using strcmp() to compare devices in this way looks fishy. But I
don't know what is going on here.
> + /**
> + * bus_id would be used to identify
> + * connected bus.
> + */
> + dsim_ddi->bus_id = lcd_dev->bus_id;
> + mutex_unlock(&mipi_dsim_lock);
> +
> + return dsim_ddi;
> + }
> +
> + list_del(&dsim_ddi->list);
> + kfree(dsim_ddi);
> + }
> +
> +out:
> + mutex_unlock(&mipi_dsim_lock);
> +
> + return NULL;
> +}
> +
> +int s5p_mipi_dsi_register_lcd_driver(struct mipi_dsim_lcd_driver *lcd_drv)
> +{
> + struct mipi_dsim_ddi *dsim_ddi;
> +
> + if (!lcd_drv) {
> + pr_err("mipi_dsim_lcd_driver is NULL.\n");
> + return -EFAULT;
> + }
> +
> + if (!lcd_drv->name) {
> + pr_err("dsim_lcd_driver name is NULL.\n");
> + return -EFAULT;
> + }
> +
> + dsim_ddi = s5p_mipi_dsi_find_lcd_device(lcd_drv);
> + if (!dsim_ddi) {
> + pr_err("mipi_dsim_ddi object not found.\n");
> + return -EFAULT;
> + }
Boy, someone really likes EFAULT!
> + dsim_ddi->dsim_lcd_drv = lcd_drv;
> +
> + pr_info("registered panel driver(%s) to mipi-dsi driver.\n",
> + lcd_drv->name);
> +
> + return 0;
> +
> +}
> +
> +struct mipi_dsim_ddi
> + *s5p_mipi_dsi_bind_lcd_ddi(struct mipi_dsim_device *dsim,
> + const char *name)
More code layout oddness.
> +{
> + struct mipi_dsim_ddi *dsim_ddi, *next;
> + struct mipi_dsim_lcd_driver *lcd_drv;
> + struct mipi_dsim_lcd_device *lcd_dev;
> + int ret;
> +
> + mutex_lock(&dsim->lock);
> +
> + list_for_each_entry_safe(dsim_ddi, next, &dsim_ddi_list, list) {
> + lcd_drv = dsim_ddi->dsim_lcd_drv;
> + lcd_dev = dsim_ddi->dsim_lcd_dev;
> + if (!lcd_drv || !lcd_dev ||
> + (dsim->id != dsim_ddi->bus_id))
> + continue;
> +
> + dev_dbg(dsim->dev, "lcd_drv->id = %d, lcd_dev->id = %d\n",
> + lcd_drv->id, lcd_dev->id);
> + dev_dbg(dsim->dev, "lcd_dev->bus_id = %d, dsim->id = %d\n",
> + lcd_dev->bus_id, dsim->id);
> +
> + if ((strcmp(lcd_drv->name, name) = 0)) {
> + lcd_dev->master = dsim;
> +
> + lcd_dev->dev.parent = dsim->dev;
> + dev_set_name(&lcd_dev->dev, "%s", lcd_drv->name);
> +
> + ret = device_register(&lcd_dev->dev);
> + if (ret < 0) {
> + dev_err(dsim->dev,
> + "can't register %s, status %d\n",
> + dev_name(&lcd_dev->dev), ret);
> + mutex_unlock(&dsim->lock);
> +
> + return NULL;
> + }
> +
> + dsim->dsim_lcd_dev = lcd_dev;
> + dsim->dsim_lcd_drv = lcd_drv;
> +
> + mutex_unlock(&dsim->lock);
> +
> + return dsim_ddi;
> + }
> + }
> +
> + mutex_unlock(&dsim->lock);
> +
> + return NULL;
> +}
>
> ...
>
> +static int s5p_mipi_dsi_probe(struct platform_device *pdev)
> +{
> + struct resource *res;
> + struct mipi_dsim_device *dsim;
> + struct mipi_dsim_config *dsim_config;
> + struct mipi_dsim_platform_data *dsim_pd;
> + struct mipi_dsim_ddi *dsim_ddi;
> + int ret = -EINVAL;
> +
> + dsim = kzalloc(sizeof(struct mipi_dsim_device), GFP_KERNEL);
> + if (!dsim) {
> + dev_err(&pdev->dev, "failed to allocate dsim object.\n");
> + return -EFAULT;
ENOMEM!
> + }
> +
> + dsim->pd = to_dsim_plat(pdev);
> + dsim->dev = &pdev->dev;
> + dsim->id = pdev->id;
> +
> + /* get mipi_dsim_platform_data. */
> + dsim_pd = (struct mipi_dsim_platform_data *)dsim->pd;
> + if (dsim_pd = NULL) {
> + dev_err(&pdev->dev, "failed to get platform data for dsim.\n");
> + goto err_clock_get;
> + }
>
> ...
>
> +irqreturn_t s5p_mipi_dsi_interrupt_handler(int irq, void *dev_id)
> +{
> + unsigned int intsrc = 0;
> + unsigned int intmsk = 0;
> + struct mipi_dsim_device *dsim = NULL;
> +
> + dsim = (struct mipi_dsim_device *)dev_id;
unneeded and undesirable cast of void*
> + if (!dsim) {
> + dev_dbg(dsim->dev, KERN_ERR "%s:error: wrong parameter\n",
> + __func__);
> + return IRQ_HANDLED;
> + }
> +
> + intsrc = s5p_mipi_dsi_read_interrupt(dsim);
> + intmsk = s5p_mipi_dsi_read_interrupt_mask(dsim);
> +
> + intmsk = ~(intmsk) & intsrc;
> +
> + switch (intmsk) {
> + case INTMSK_RX_DONE:
> + complete(&dsim_rd_comp);
> + dev_dbg(dsim->dev, "MIPI INTMSK_RX_DONE\n");
> + break;
> + case INTMSK_FIFO_EMPTY:
> + complete(&dsim_wr_comp);
> + dev_dbg(dsim->dev, "MIPI INTMSK_FIFO_EMPTY\n");
> + break;
> + default:
> + break;
> + }
> +
> + s5p_mipi_dsi_clear_interrupt(dsim, intmsk);
> +
> + return IRQ_HANDLED;
> +}
>
> ...
>
Generally: the use of the Efoo errno codes is chaotic. Please check it
all over.
^ permalink raw reply
* Re: [PATCH v6 1/2] video: support MIPI-DSI controller driver
From: Archit @ 2012-01-18 9:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <4F16288C.5020406@samsung.com>
Hi,
On Wednesday 18 January 2012 07:33 AM, Donghwa Lee wrote:
> Samsung S5PC210 and EXYNOS SoC platform has MIPI-DSI controller and MIPI-DSI
> based LCD Panel could be used with it. This patch supports MIPI-DSI driver
> based Samsung SoC chip.
>
> LCD panel driver based MIPI-DSI should be registered to MIPI-DSI driver at
> machine code and LCD panel driver specific function registered to mipi_dsim_ddi
> structure at lcd panel init function called system init.
> In the MIPI-DSI driver, find lcd panel driver by using registered
> lcd panel name, and then initialize lcd panel driver.
<snip>
The header 'mipi_dsim.h' below has a lot of generic content which could
be used by other DSI controllers too. But there are things which seem
specific to the Samsung SoC.
'mipi_dsim.h' makes it sound like a header for a generic DSI controller.
Since that's not the case, you might want to consider renaming this as
's5p_mipi_dsim.h'.
Sorry for not commenting on an earlier revision.
Regards,
Archit
> +#endif /* _REGS_DSIM_H */
> diff --git a/include/linux/mipi_dsim.h b/include/linux/mipi_dsim.h
> new file mode 100644
> index 0000000..f54da24
> --- /dev/null
> +++ b/include/linux/mipi_dsim.h
> @@ -0,0 +1,359 @@
> +/* include/linux/mipi_dsim.h
> + *
> + * Platform data header for Samsung SoC MIPI-DSIM.
> + *
> + * Copyright (c) 2011 Samsung Electronics Co., Ltd
> + *
> + * InKi Dae<inki.dae@samsung.com>
> + * Donghwa Lee<dh09.lee@samsung.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> +*/
> +
> +#ifndef _LINUX_MIPI_DSIM_H
> +#define _LINUX_MIPI_DSIM_H
> +
> +#include<linux/device.h>
> +#include<linux/fb.h>
> +
> +#define PANEL_NAME_SIZE (32)
> +
> +/*
> + * Enumerate display interface type.
> + *
> + * DSIM_COMMAND means cpu interface and rgb interface for DSIM_VIDEO.
> + *
> + * P.S. MIPI DSI Master has two display controller intefaces, RGB Interface
> + * for main display and CPU Interface(same as I80 Interface) for main
> + * and sub display.
> + */
> +enum mipi_dsim_interface_type {
> + DSIM_COMMAND,
> + DSIM_VIDEO
> +};
> +
> +enum mipi_dsim_virtual_ch_no {
> + DSIM_VIRTUAL_CH_0,
> + DSIM_VIRTUAL_CH_1,
> + DSIM_VIRTUAL_CH_2,
> + DSIM_VIRTUAL_CH_3
> +};
> +
> +enum mipi_dsim_burst_mode_type {
> + DSIM_NON_BURST_SYNC_EVENT,
> + DSIM_BURST_SYNC_EVENT,
> + DSIM_NON_BURST_SYNC_PULSE,
> + DSIM_BURST,
> + DSIM_NON_VIDEO_MODE
> +};
> +
> +enum mipi_dsim_no_of_data_lane {
> + DSIM_DATA_LANE_1,
> + DSIM_DATA_LANE_2,
> + DSIM_DATA_LANE_3,
> + DSIM_DATA_LANE_4
> +};
> +
> +enum mipi_dsim_byte_clk_src {
> + DSIM_PLL_OUT_DIV8,
> + DSIM_EXT_CLK_DIV8,
> + DSIM_EXT_CLK_BYPASS
> +};
> +
> +enum mipi_dsim_pixel_format {
> + DSIM_CMD_3BPP,
> + DSIM_CMD_8BPP,
> + DSIM_CMD_12BPP,
> + DSIM_CMD_16BPP,
> + DSIM_VID_16BPP_565,
> + DSIM_VID_18BPP_666PACKED,
> + DSIM_18BPP_666LOOSELYPACKED,
> + DSIM_24BPP_888
> +};
> +
> +/*
> + * struct mipi_dsim_config - interface for configuring mipi-dsi controller.
> + *
> + * @auto_flush: enable or disable Auto flush of MD FIFO using VSYNC pulse.
> + * @eot_disable: enable or disable EoT packet in HS mode.
> + * @auto_vertical_cnt: specifies auto vertical count mode.
> + * in Video mode, the vertical line transition uses line counter
> + * configured by VSA, VBP, and Vertical resolution.
> + * If this bit is set to '1', the line counter does not use VSA and VBP
> + * registers.(in command mode, this variable is ignored)
> + * @hse: set horizontal sync event mode.
> + * In VSYNC pulse and Vporch area, MIPI DSI master transfers only HSYNC
> + * start packet to MIPI DSI slave at MIPI DSI spec1.1r02.
> + * this bit transfers HSYNC end packet in VSYNC pulse and Vporch area
> + * (in mommand mode, this variable is ignored)
> + * @hfp: specifies HFP disable mode.
> + * if this variable is set, DSI master ignores HFP area in VIDEO mode.
> + * (in command mode, this variable is ignored)
> + * @hbp: specifies HBP disable mode.
> + * if this variable is set, DSI master ignores HBP area in VIDEO mode.
> + * (in command mode, this variable is ignored)
> + * @hsa: specifies HSA disable mode.
> + * if this variable is set, DSI master ignores HSA area in VIDEO mode.
> + * (in command mode, this variable is ignored)
> + * @cma_allow: specifies the number of horizontal lines, where command packet
> + * transmission is allowed after Stable VFP period.
> + * @e_interface: specifies interface to be used.(CPU or RGB interface)
> + * @e_virtual_ch: specifies virtual channel number that main or
> + * sub diaplsy uses.
> + * @e_pixel_format: specifies pixel stream format for main or sub display.
> + * @e_burst_mode: selects Burst mode in Video mode.
> + * in Non-burst mode, RGB data area is filled with RGB data and NULL
> + * packets, according to input bandwidth of RGB interface.
> + * In Burst mode, RGB data area is filled with RGB data only.
> + * @e_no_data_lane: specifies data lane count to be used by Master.
> + * @e_byte_clk: select byte clock source. (it must be DSIM_PLL_OUT_DIV8)
> + * DSIM_EXT_CLK_DIV8 and DSIM_EXT_CLK_BYPASSS are not supported.
> + * @pll_stable_time: specifies the PLL Timer for stability of the ganerated
> + * clock(System clock cycle base)
> + * if the timer value goes to 0x00000000, the clock stable bit of status
> + * and interrupt register is set.
> + * @esc_clk: specifies escape clock frequency for getting the escape clock
> + * prescaler value.
> + * @stop_holding_cnt: specifies the interval value between transmitting
> + * read packet(or write "set_tear_on" command) and BTA request.
> + * after transmitting read packet or write "set_tear_on" command,
> + * BTA requests to D-PHY automatically. this counter value specifies
> + * the interval between them.
> + * @bta_timeout: specifies the timer for BTA.
> + * this register specifies time out from BTA request to change
> + * the direction with respect to Tx escape clock.
> + * @rx_timeout: specifies the timer for LP Rx mode timeout.
> + * this register specifies time out on how long RxValid deasserts,
> + * after RxLpdt asserts with respect to Tx escape clock.
> + * - RxValid specifies Rx data valid indicator.
> + * - RxLpdt specifies an indicator that D-PHY is under RxLpdt mode.
> + * - RxValid and RxLpdt specifies signal from D-PHY.
> + */
> +struct mipi_dsim_config {
> + unsigned char auto_flush;
> + unsigned char eot_disable;
> +
> + unsigned char auto_vertical_cnt;
> + unsigned char hse;
> + unsigned char hfp;
> + unsigned char hbp;
> + unsigned char hsa;
> + unsigned char cmd_allow;
> +
> + enum mipi_dsim_interface_type e_interface;
> + enum mipi_dsim_virtual_ch_no e_virtual_ch;
> + enum mipi_dsim_pixel_format e_pixel_format;
> + enum mipi_dsim_burst_mode_type e_burst_mode;
> + enum mipi_dsim_no_of_data_lane e_no_data_lane;
> + enum mipi_dsim_byte_clk_src e_byte_clk;
> +
> + /*
> + * =====================> + * | P | M | S | MHz |
> + * -------------------------------------------
> + * | 3 | 100 | 3 | 100 |
> + * | 3 | 100 | 2 | 200 |
> + * | 3 | 63 | 1 | 252 |
> + * | 4 | 100 | 1 | 300 |
> + * | 4 | 110 | 1 | 330 |
> + * | 12 | 350 | 1 | 350 |
> + * | 3 | 100 | 1 | 400 |
> + * | 4 | 150 | 1 | 450 |
> + * | 6 | 118 | 1 | 472 |
> + * | 3 | 120 | 1 | 480 |
> + * | 12 | 250 | 0 | 500 |
> + * | 4 | 100 | 0 | 600 |
> + * | 3 | 81 | 0 | 648 |
> + * | 3 | 88 | 0 | 704 |
> + * | 3 | 90 | 0 | 720 |
> + * | 3 | 100 | 0 | 800 |
> + * | 12 | 425 | 0 | 850 |
> + * | 4 | 150 | 0 | 900 |
> + * | 12 | 475 | 0 | 950 |
> + * | 6 | 250 | 0 | 1000 |
> + * -------------------------------------------
> + */
> +
> + /*
> + * pms could be calculated as the following.
> + * M * 24 / P * 2 ^ S = MHz
> + */
> + unsigned char p;
> + unsigned short m;
> + unsigned char s;
> +
> + unsigned int pll_stable_time;
> + unsigned long esc_clk;
> +
> + unsigned short stop_holding_cnt;
> + unsigned char bta_timeout;
> + unsigned short rx_timeout;
> +};
> +
> +/*
> + * struct mipi_dsim_device - global interface for mipi-dsi driver.
> + *
> + * @dev: driver model representation of the device.
> + * @id: unique device id.
> + * @clock: pointer to MIPI-DSI clock of clock framework.
> + * @irq: interrupt number to MIPI-DSI controller.
> + * @reg_base: base address to memory mapped SRF of MIPI-DSI controller.
> + * (virtual address)
> + * @lock: the mutex protecting this data structure.
> + * @dsim_info: infomation for configuring mipi-dsi controller.
> + * @master_ops: callbacks to mipi-dsi operations.
> + * @dsim_lcd_dev: pointer to activated ddi device.
> + * (it would be registered by mipi-dsi driver.)
> + * @dsim_lcd_drv: pointer to activated_ddi driver.
> + * (it would be registered by mipi-dsi driver.)
> + * @lcd_info: pointer to mipi_lcd_info structure.
> + * @state: specifies status of MIPI-DSI controller.
> + * the status could be RESET, INIT, STOP, HSCLKEN and ULPS.
> + * @data_lane: specifiec enabled data lane number.
> + * this variable would be set by driver according to e_no_data_lane
> + * automatically.
> + * @e_clk_src: select byte clock source.
> + * @pd: pointer to MIPI-DSI driver platform data.
> + */
> +struct mipi_dsim_device {
> + struct device *dev;
> + int id;
> + struct resource *res;
> + struct clk *clock;
> + unsigned int irq;
> + void __iomem *reg_base;
> + struct mutex lock;
> +
> + struct mipi_dsim_config *dsim_config;
> + struct mipi_dsim_master_ops *master_ops;
> + struct mipi_dsim_lcd_device *dsim_lcd_dev;
> + struct mipi_dsim_lcd_driver *dsim_lcd_drv;
> +
> + unsigned int state;
> + unsigned int data_lane;
> + unsigned int e_clk_src;
> + bool suspended;
> +
> + struct mipi_dsim_platform_data *pd;
> +};
> +
> +/*
> + * struct mipi_dsim_platform_data - interface to platform data
> + * for mipi-dsi driver.
> + *
> + * @lcd_panel_name: specifies lcd panel name registered to mipi-dsi driver.
> + * lcd panel driver searched would be actived.
> + * @dsim_config: pointer of structure for configuring mipi-dsi controller.
> + * @enabled: indicate whether mipi controller got enabled or not.
> + * @lcd_panel_info: pointer for lcd panel specific structure.
> + * this structure specifies width, height, timing and polarity and so on.
> + * @phy_enable: pointer to a callback controlling D-PHY enable/reset
> + */
> +struct mipi_dsim_platform_data {
> + char lcd_panel_name[PANEL_NAME_SIZE];
> +
> + struct mipi_dsim_config *dsim_config;
> + unsigned int enabled;
> + void *lcd_panel_info;
> +
> + int (*phy_enable)(struct platform_device *pdev, bool on);
> +};
> +
> +/*
> + * struct mipi_dsim_master_ops - callbacks to mipi-dsi operations.
> + *
> + * @cmd_write: transfer command to lcd panel at LP mode.
> + * @cmd_read: read command from rx register.
> + * @get_dsim_frame_done: get the status that all screen data have been
> + * transferred to mipi-dsi.
> + * @clear_dsim_frame_done: clear frame done status.
> + * @get_fb_frame_done: get frame done status of display controller.
> + * @trigger: trigger display controller.
> + * - this one would be used only in case of CPU mode.
> + * @set_early_blank_mode: set framebuffer blank mode.
> + * - this callback should be called prior to fb_blank() by a client driver
> + * only if needing.
> + * @set_blank_mode: set framebuffer blank mode.
> + * - this callback should be called after fb_blank() by a client driver
> + * only if needing.
> + */
> +
> +struct mipi_dsim_master_ops {
> + int (*cmd_write)(struct mipi_dsim_device *dsim, unsigned int data_id,
> + const unsigned char *data0, unsigned int data1);
> + int (*cmd_read)(struct mipi_dsim_device *dsim, unsigned int data_id,
> + unsigned int data0, unsigned int req_size, u8 *rx_buf);
> + int (*get_dsim_frame_done)(struct mipi_dsim_device *dsim);
> + int (*clear_dsim_frame_done)(struct mipi_dsim_device *dsim);
> +
> + int (*get_fb_frame_done)(struct fb_info *info);
> + void (*trigger)(struct fb_info *info);
> + int (*set_early_blank_mode)(struct mipi_dsim_device *dsim, int power);
> + int (*set_blank_mode)(struct mipi_dsim_device *dsim, int power);
> +};
> +
> +/*
> + * device structure for mipi-dsi based lcd panel.
> + *
> + * @name: name of the device to use with this device, or an
> + * alias for that name.
> + * @dev: driver model representation of the device.
> + * @id: id of device to be registered.
> + * @bus_id: bus id for identifing connected bus
> + * and this bus id should be same as id of mipi_dsim_device.
> + * @irq: irq number for signaling when framebuffer transfer of
> + * lcd panel module is completed.
> + * this irq would be used only for MIPI-DSI based CPU mode lcd panel.
> + * @master: pointer to mipi-dsi master device object.
> + * @platform_data: lcd panel specific platform data.
> + */
> +struct mipi_dsim_lcd_device {
> + char *name;
> + struct device dev;
> + int id;
> + int bus_id;
> + int irq;
> +
> + struct mipi_dsim_device *master;
> + void *platform_data;
> +};
> +
> +/*
> + * driver structure for mipi-dsi based lcd panel.
> + *
> + * this structure should be registered by lcd panel driver.
> + * mipi-dsi driver seeks lcd panel registered through name field
> + * and calls these callback functions in appropriate time.
> + *
> + * @name: name of the driver to use with this device, or an
> + * alias for that name.
> + * @id: id of driver to be registered.
> + * this id would be used for finding device object registered.
> + */
> +struct mipi_dsim_lcd_driver {
> + char *name;
> + int id;
> +
> + void (*power_on)(struct mipi_dsim_lcd_device *dsim_dev, int enable);
> + void (*set_sequence)(struct mipi_dsim_lcd_device *dsim_dev);
> + int (*probe)(struct mipi_dsim_lcd_device *dsim_dev);
> + int (*remove)(struct mipi_dsim_lcd_device *dsim_dev);
> + void (*shutdown)(struct mipi_dsim_lcd_device *dsim_dev);
> + int (*suspend)(struct mipi_dsim_lcd_device *dsim_dev);
> + int (*resume)(struct mipi_dsim_lcd_device *dsim_dev);
> +};
> +
> +/*
> + * register mipi_dsim_lcd_device to mipi-dsi master.
> + */
> +int s5p_mipi_dsi_register_lcd_device(struct mipi_dsim_lcd_device
> + *lcd_dev);
> +/**
> + * register mipi_dsim_lcd_driver object defined by lcd panel driver
> + * to mipi-dsi driver.
> + */
> +int s5p_mipi_dsi_register_lcd_driver(struct mipi_dsim_lcd_driver
> + *lcd_drv);
> +#endif /* _LINUX_MIPI_DSIM_H */
^ permalink raw reply
* Re: [PATCH 5/6] OMAPDSS: DISPC: move fifo threhold calc to dispc.c
From: Tomi Valkeinen @ 2012-01-18 8:10 UTC (permalink / raw)
To: Archit; +Cc: linux-omap, linux-fbdev, archit, rob
In-Reply-To: <4F108D7A.4010802@ti.com>
[-- Attachment #1: Type: text/plain, Size: 2306 bytes --]
On Sat, 2012-01-14 at 01:30 +0530, Archit wrote:
> Hi,
>
> On Friday 13 January 2012 05:16 PM, Tomi Valkeinen wrote:
> > Move fifo threshold calculation into dispc.c, as the thresholds are
> > really dispc internal thing.
> >
> > Signed-off-by: Tomi Valkeinen<tomi.valkeinen@ti.com>
>
> <snip>
>
> > diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
> > index 511ae2a..1cbb7a5 100644
> > --- a/drivers/video/omap2/dss/dsi.c
> > +++ b/drivers/video/omap2/dss/dsi.c
> > @@ -4524,14 +4524,6 @@ int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable)
> > }
> > EXPORT_SYMBOL(omapdss_dsi_enable_te);
> >
> > -void dsi_get_overlay_fifo_thresholds(enum omap_plane plane,
> > - u32 fifo_size, u32 burst_size,
> > - u32 *fifo_low, u32 *fifo_high)
> > -{
> > - *fifo_high = fifo_size - burst_size;
> > - *fifo_low = fifo_size - burst_size * 2;
> > -}
>
> We are removing the special treatment for overlays connected to DSI done
> before. Won't this cause the issues you saw with DSI in OMAP3?
I added a FEAT_OMAP3_DSI_FIFO_BUG flag for OMAP3s, and changed the
dispc's fifo config function to:
void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane,
u32 *fifo_low, u32 *fifo_high, bool use_fifomerge)
{
/*
* All sizes are in bytes. Both the buffer and burst are made of
* buffer_units, and the fifo thresholds must be buffer_unit aligned.
*/
unsigned buf_unit = dss_feat_get_buffer_size_unit();
unsigned ovl_fifo_size, total_fifo_size, burst_size;
int i;
burst_size = dispc_ovl_get_burst_size(plane);
ovl_fifo_size = dispc_ovl_get_fifo_size(plane);
if (use_fifomerge) {
total_fifo_size = 0;
for (i = 0; i < omap_dss_get_num_overlays(); ++i)
total_fifo_size += dispc_ovl_get_fifo_size(i);
} else {
total_fifo_size = ovl_fifo_size;
}
/*
* We use the same low threshold for both fifomerge and non-fifomerge
* cases, but for fifomerge we calculate the high threshold using the
* combined fifo size
*/
if (dss_has_feature(FEAT_OMAP3_DSI_FIFO_BUG)) {
*fifo_low = ovl_fifo_size - burst_size * 2;
*fifo_high = total_fifo_size - burst_size;
} else {
*fifo_low = ovl_fifo_size - burst_size;
*fifo_high = total_fifo_size - buf_unit;
}
}
Tomi
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* Re: [PATCH 5/6] OMAP: 4430SDP/Panda: add HDMI HPD gpio
From: Tomi Valkeinen @ 2012-01-18 6:39 UTC (permalink / raw)
To: Archit; +Cc: linux-omap, linux-fbdev, mythripk, archit, x0132446
In-Reply-To: <4F15DAFB.40203@ti.com>
[-- Attachment #1: Type: text/plain, Size: 388 bytes --]
On Wed, 2012-01-18 at 02:02 +0530, Archit wrote:
> On Tuesday 17 January 2012 06:19 PM, Tomi Valkeinen wrote:
> > Both Panda and 4430SDP use GPIO 64 as HDMI hot-plug-detect. Configure
> > this GPIO in the board files.
>
> Minor comment: the commit message says GPIO 64, and the macros use gpio
> 63. Is this done intentionally?
Thanks, it's a typo. HPD gpio is 63.
Tomi
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* [PATCH v6 2/2] video: backlight: support s6e8ax0 panel driver based on MIPI DSI
From: Donghwa Lee @ 2012-01-18 2:04 UTC (permalink / raw)
To: linux-arm-kernel
This patch is amoled panel driver based MIPI DSI interface.
S6E8AX0 means it may includes many other ldi controllers, for example,
S6E8AA0, S6E8AB0, and so on.
This patch can be modified depending on each panel properites. For example,
second parameter of panel condition register can be changed depending on
ldi controller or amoled type.
Changes since v6:
- change data array to const type and fix cmd_write() function
parameter.
- remove unused function declaration from s6e8ax0.h
Signed-off-by: Donghwa Lee <dh09.lee@samsung.com>
Signed-off-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
drivers/video/backlight/Kconfig | 7 +
drivers/video/backlight/Makefile | 1 +
drivers/video/backlight/s6e8ax0.c | 898 +++++++++++++++++++++++++++++++++++++
drivers/video/backlight/s6e8ax0.h | 21 +
4 files changed, 927 insertions(+), 0 deletions(-)
create mode 100644 drivers/video/backlight/s6e8ax0.c
create mode 100644 drivers/video/backlight/s6e8ax0.h
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index 278aeaa..478fc4a 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -125,6 +125,13 @@ config LCD_AMS369FG06
If you have an AMS369FG06 AMOLED Panel, say Y to enable its
LCD control driver.
+config LCD_S6E8AX0
+ tristate "S6E8AX0 MIPI AMOLED LCD Driver"
+ depends on S5P_MIPI_DSI && BACKLIGHT_CLASS_DEVICE
+ default n
+ help
+ If you have an S6E8AX0 MIPI AMOLED LCD Panel, say Y to enable its
+ LCD control driver.
endif # LCD_CLASS_DEVICE
#
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index fdd1fc4..6adba58 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_LCD_TOSA) += tosa_lcd.o
obj-$(CONFIG_LCD_S6E63M0) += s6e63m0.o
obj-$(CONFIG_LCD_LD9040) += ld9040.o
obj-$(CONFIG_LCD_AMS369FG06) += ams369fg06.o
+obj-$(CONFIG_LCD_S6E8AX0) += s6e8ax0.o
obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o
obj-$(CONFIG_BACKLIGHT_ATMEL_PWM) += atmel-pwm-bl.o
diff --git a/drivers/video/backlight/s6e8ax0.c b/drivers/video/backlight/s6e8ax0.c
new file mode 100644
index 0000000..43447a0
--- /dev/null
+++ b/drivers/video/backlight/s6e8ax0.c
@@ -0,0 +1,898 @@
+/* linux/drivers/video/s6e8ax0.c
+ *
+ * MIPI-DSI based s6e8ax0 AMOLED lcd 4.65 inch panel driver.
+ *
+ * Inki Dae, <inki.dae@samsung.com>
+ * Donghwa Lee, <dh09.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#include <linux/ctype.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/lcd.h>
+#include <linux/fb.h>
+#include <linux/backlight.h>
+#include <linux/mipi_dsim.h>
+#include <linux/regulator/consumer.h>
+
+#include <video/mipi_display.h>
+
+#define LDI_MTP_LENGTH 24
+#define DSIM_PM_STABLE_TIME 10
+#define MIN_BRIGHTNESS 0
+#define MAX_BRIGHTNESS 24
+#define GAMMA_TABLE_COUNT 26
+
+#define POWER_IS_ON(pwr) ((pwr) = FB_BLANK_UNBLANK)
+#define POWER_IS_OFF(pwr) ((pwr) = FB_BLANK_POWERDOWN)
+#define POWER_IS_NRM(pwr) ((pwr) = FB_BLANK_NORMAL)
+
+#define lcd_to_master(a) (a->dsim_dev->master)
+#define lcd_to_master_ops(a) ((lcd_to_master(a))->master_ops)
+
+enum {
+ DSIM_NONE_STATE = 0,
+ DSIM_RESUME_COMPLETE = 1,
+ DSIM_FRAME_DONE = 2,
+};
+
+struct s6e8ax0 {
+ struct device *dev;
+ unsigned int power;
+ unsigned int id;
+ unsigned int gamma;
+ unsigned int acl_enable;
+ unsigned int cur_acl;
+
+ struct lcd_device *ld;
+ struct backlight_device *bd;
+
+ struct mipi_dsim_lcd_device *dsim_dev;
+ struct lcd_platform_data *ddi_pd;
+ struct mutex lock;
+ bool enabled;
+};
+
+
+static struct regulator_bulk_data supplies[] = {
+ { .supply = "vdd3", },
+ { .supply = "vci", },
+};
+
+static void s6e8ax0_regulator_enable(struct s6e8ax0 *lcd)
+{
+ int ret = 0;
+ struct lcd_platform_data *pd = NULL;
+
+ pd = lcd->ddi_pd;
+ mutex_lock(&lcd->lock);
+ if (!lcd->enabled) {
+ ret = regulator_bulk_enable(ARRAY_SIZE(supplies), supplies);
+ if (ret)
+ goto out;
+
+ lcd->enabled = true;
+ }
+ msleep(pd->power_on_delay);
+out:
+ mutex_unlock(&lcd->lock);
+}
+
+static void s6e8ax0_regulator_disable(struct s6e8ax0 *lcd)
+{
+ int ret = 0;
+
+ mutex_lock(&lcd->lock);
+ if (lcd->enabled) {
+ ret = regulator_bulk_disable(ARRAY_SIZE(supplies), supplies);
+ if (ret)
+ goto out;
+
+ lcd->enabled = false;
+ }
+out:
+ mutex_unlock(&lcd->lock);
+}
+
+const unsigned char s6e8ax0_22_gamma_30[] = {
+ 0xfa, 0x01, 0x60, 0x10, 0x60, 0xf5, 0x00, 0xff, 0xad, 0xaf,
+ 0xbA, 0xc3, 0xd8, 0xc5, 0x9f, 0xc6, 0x9e, 0xc1, 0xdc, 0xc0,
+ 0x00, 0x61, 0x00, 0x5a, 0x00, 0x74,
+};
+
+const unsigned char s6e8ax0_22_gamma_50[] = {
+ 0xfa, 0x01, 0x60, 0x10, 0x60, 0xe8, 0x1f, 0xf7, 0xad, 0xc0,
+ 0xb5, 0xc4, 0xdc, 0xc4, 0x9e, 0xc6, 0x9c, 0xbb, 0xd8, 0xbb,
+ 0x00, 0x70, 0x00, 0x68, 0x00, 0x86,
+};
+
+const unsigned char s6e8ax0_22_gamma_60[] = {
+ 0xfa, 0x01, 0x60, 0x10, 0x60, 0xde, 0x1f, 0xef, 0xad, 0xc4,
+ 0xb3, 0xc3, 0xdd, 0xc4, 0x9e, 0xc6, 0x9c, 0xbc, 0xd6, 0xba,
+ 0x00, 0x75, 0x00, 0x6e, 0x00, 0x8d,
+};
+
+const unsigned char s6e8ax0_22_gamma_70[] = {
+ 0xfa, 0x01, 0x60, 0x10, 0x60, 0xd8, 0x1f, 0xe7, 0xaf, 0xc8,
+ 0xb4, 0xc4, 0xdd, 0xc3, 0x9d, 0xc6, 0x9c, 0xbb, 0xd6, 0xb9,
+ 0x00, 0x7a, 0x00, 0x72, 0x00, 0x93,
+};
+
+const unsigned char s6e8ax0_22_gamma_80[] = {
+ 0xfa, 0x01, 0x60, 0x10, 0x60, 0xc9, 0x1f, 0xde, 0xae, 0xc9,
+ 0xb1, 0xc3, 0xdd, 0xc2, 0x9d, 0xc5, 0x9b, 0xbc, 0xd6, 0xbb,
+ 0x00, 0x7f, 0x00, 0x77, 0x00, 0x99,
+};
+
+const unsigned char s6e8ax0_22_gamma_90[] = {
+ 0xfa, 0x01, 0x60, 0x10, 0x60, 0xc7, 0x1f, 0xd9, 0xb0, 0xcc,
+ 0xb2, 0xc3, 0xdc, 0xc1, 0x9c, 0xc6, 0x9c, 0xbc, 0xd4, 0xb9,
+ 0x00, 0x83, 0x00, 0x7b, 0x00, 0x9e,
+};
+
+const unsigned char s6e8ax0_22_gamma_100[] = {
+ 0xfa, 0x01, 0x60, 0x10, 0x60, 0xbd, 0x80, 0xcd, 0xba, 0xce,
+ 0xb3, 0xc4, 0xde, 0xc3, 0x9c, 0xc4, 0x9, 0xb8, 0xd3, 0xb6,
+ 0x00, 0x88, 0x00, 0x80, 0x00, 0xa5,
+};
+
+const unsigned char s6e8ax0_22_gamma_120[] = {
+ 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb9, 0x95, 0xc8, 0xb1, 0xcf,
+ 0xb2, 0xc6, 0xdf, 0xc5, 0x9b, 0xc3, 0x99, 0xb6, 0xd2, 0xb6,
+ 0x00, 0x8f, 0x00, 0x86, 0x00, 0xac,
+};
+
+const unsigned char s6e8ax0_22_gamma_130[] = {
+ 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb7, 0xa0, 0xc7, 0xb1, 0xd0,
+ 0xb2, 0xc4, 0xdd, 0xc3, 0x9a, 0xc3, 0x98, 0xb6, 0xd0, 0xb4,
+ 0x00, 0x92, 0x00, 0x8a, 0x00, 0xb1,
+};
+
+const unsigned char s6e8ax0_22_gamma_140[] = {
+ 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb7, 0xa0, 0xc5, 0xb2, 0xd0,
+ 0xb3, 0xc3, 0xde, 0xc3, 0x9b, 0xc2, 0x98, 0xb6, 0xd0, 0xb4,
+ 0x00, 0x95, 0x00, 0x8d, 0x00, 0xb5,
+};
+
+const unsigned char s6e8ax0_22_gamma_150[] = {
+ 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb3, 0xa0, 0xc2, 0xb2, 0xd0,
+ 0xb2, 0xc1, 0xdd, 0xc2, 0x9b, 0xc2, 0x98, 0xb4, 0xcf, 0xb1,
+ 0x00, 0x99, 0x00, 0x90, 0x00, 0xba,
+};
+
+const unsigned char s6e8ax0_22_gamma_160[] = {
+ 0xfa, 0x01, 0x60, 0x10, 0x60, 0xaf, 0xa5, 0xbf, 0xb0, 0xd0,
+ 0xb1, 0xc3, 0xde, 0xc2, 0x99, 0xc1, 0x97, 0xb4, 0xce, 0xb1,
+ 0x00, 0x9c, 0x00, 0x93, 0x00, 0xbe,
+};
+
+const unsigned char s6e8ax0_22_gamma_170[] = {
+ 0xfa, 0x01, 0x60, 0x10, 0x60, 0xaf, 0xb5, 0xbf, 0xb1, 0xd1,
+ 0xb1, 0xc3, 0xde, 0xc3, 0x99, 0xc0, 0x96, 0xb4, 0xce, 0xb1,
+ 0x00, 0x9f, 0x00, 0x96, 0x00, 0xc2,
+};
+
+const unsigned char s6e8ax0_22_gamma_180[] = {
+ 0xfa, 0x01, 0x60, 0x10, 0x60, 0xaf, 0xb7, 0xbe, 0xb3, 0xd2,
+ 0xb3, 0xc3, 0xde, 0xc2, 0x97, 0xbf, 0x95, 0xb4, 0xcd, 0xb1,
+ 0x00, 0xa2, 0x00, 0x99, 0x00, 0xc5,
+};
+
+const unsigned char s6e8ax0_22_gamma_190[] = {
+ 0xfa, 0x01, 0x60, 0x10, 0x60, 0xaf, 0xb9, 0xbe, 0xb2, 0xd2,
+ 0xb2, 0xc3, 0xdd, 0xc3, 0x98, 0xbf, 0x95, 0xb2, 0xcc, 0xaf,
+ 0x00, 0xa5, 0x00, 0x9c, 0x00, 0xc9,
+};
+
+const unsigned char s6e8ax0_22_gamma_200[] = {
+ 0xfa, 0x01, 0x60, 0x10, 0x60, 0xaf, 0xb9, 0xbc, 0xb2, 0xd2,
+ 0xb1, 0xc4, 0xdd, 0xc3, 0x97, 0xbe, 0x95, 0xb1, 0xcb, 0xae,
+ 0x00, 0xa8, 0x00, 0x9f, 0x00, 0xcd,
+};
+
+const unsigned char s6e8ax0_22_gamma_210[] = {
+ 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb1, 0xc1, 0xbd, 0xb1, 0xd1,
+ 0xb1, 0xc2, 0xde, 0xc2, 0x97, 0xbe, 0x94, 0xB0, 0xc9, 0xad,
+ 0x00, 0xae, 0x00, 0xa4, 0x00, 0xd4,
+};
+
+const unsigned char s6e8ax0_22_gamma_220[] = {
+ 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb1, 0xc7, 0xbd, 0xb1, 0xd1,
+ 0xb1, 0xc2, 0xdd, 0xc2, 0x97, 0xbd, 0x94, 0xb0, 0xc9, 0xad,
+ 0x00, 0xad, 0x00, 0xa2, 0x00, 0xd3,
+};
+
+const unsigned char s6e8ax0_22_gamma_230[] = {
+ 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb1, 0xc3, 0xbd, 0xb2, 0xd1,
+ 0xb1, 0xc3, 0xdd, 0xc1, 0x96, 0xbd, 0x94, 0xb0, 0xc9, 0xad,
+ 0x00, 0xb0, 0x00, 0xa7, 0x00, 0xd7,
+};
+
+const unsigned char s6e8ax0_22_gamma_240[] = {
+ 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb1, 0xcb, 0xbd, 0xb1, 0xd2,
+ 0xb1, 0xc3, 0xdD, 0xc2, 0x95, 0xbd, 0x93, 0xaf, 0xc8, 0xab,
+ 0x00, 0xb3, 0x00, 0xa9, 0x00, 0xdb,
+};
+
+const unsigned char s6e8ax0_22_gamma_250[] = {
+ 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb3, 0xcc, 0xbe, 0xb0, 0xd2,
+ 0xb0, 0xc3, 0xdD, 0xc2, 0x94, 0xbc, 0x92, 0xae, 0xc8, 0xab,
+ 0x00, 0xb6, 0x00, 0xab, 0x00, 0xde,
+};
+
+const unsigned char s6e8ax0_22_gamma_260[] = {
+ 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb3, 0xd0, 0xbe, 0xaf, 0xd1,
+ 0xaf, 0xc2, 0xdd, 0xc1, 0x96, 0xbc, 0x93, 0xaf, 0xc8, 0xac,
+ 0x00, 0xb7, 0x00, 0xad, 0x00, 0xe0,
+};
+
+const unsigned char s6e8ax0_22_gamma_270[] = {
+ 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb2, 0xcF, 0xbd, 0xb0, 0xd2,
+ 0xaf, 0xc2, 0xdc, 0xc1, 0x95, 0xbd, 0x93, 0xae, 0xc6, 0xaa,
+ 0x00, 0xba, 0x00, 0xb0, 0x00, 0xe4,
+};
+
+const unsigned char s6e8ax0_22_gamma_280[] = {
+ 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb2, 0xd0, 0xbd, 0xaf, 0xd0,
+ 0xad, 0xc4, 0xdd, 0xc3, 0x95, 0xbd, 0x93, 0xac, 0xc5, 0xa9,
+ 0x00, 0xbd, 0x00, 0xb2, 0x00, 0xe7,
+};
+
+const unsigned char s6e8ax0_22_gamma_300[] = {
+ 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb5, 0xd3, 0xbd, 0xb1, 0xd2,
+ 0xb0, 0xc0, 0xdc, 0xc0, 0x94, 0xba, 0x91, 0xac, 0xc5, 0xa9,
+ 0x00, 0xc2, 0x00, 0xb7, 0x00, 0xed,
+};
+
+const unsigned char *s6e8ax0_22_gamma_table[] = {
+ s6e8ax0_22_gamma_30,
+ s6e8ax0_22_gamma_50,
+ s6e8ax0_22_gamma_60,
+ s6e8ax0_22_gamma_70,
+ s6e8ax0_22_gamma_80,
+ s6e8ax0_22_gamma_90,
+ s6e8ax0_22_gamma_100,
+ s6e8ax0_22_gamma_120,
+ s6e8ax0_22_gamma_130,
+ s6e8ax0_22_gamma_140,
+ s6e8ax0_22_gamma_150,
+ s6e8ax0_22_gamma_160,
+ s6e8ax0_22_gamma_170,
+ s6e8ax0_22_gamma_180,
+ s6e8ax0_22_gamma_190,
+ s6e8ax0_22_gamma_200,
+ s6e8ax0_22_gamma_210,
+ s6e8ax0_22_gamma_220,
+ s6e8ax0_22_gamma_230,
+ s6e8ax0_22_gamma_240,
+ s6e8ax0_22_gamma_250,
+ s6e8ax0_22_gamma_260,
+ s6e8ax0_22_gamma_270,
+ s6e8ax0_22_gamma_280,
+ s6e8ax0_22_gamma_300,
+};
+
+static void s6e8ax0_panel_cond(struct s6e8ax0 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+
+ const unsigned char data_to_send[] = {
+ 0xf8, 0x3d, 0x35, 0x00, 0x00, 0x00, 0x93, 0x00, 0x3c, 0x7d,
+ 0x08, 0x27, 0x7d, 0x3f, 0x00, 0x00, 0x00, 0x20, 0x04, 0x08,
+ 0x6e, 0x00, 0x00, 0x00, 0x02, 0x08, 0x08, 0x23, 0x23, 0xc0,
+ 0xc8, 0x08, 0x48, 0xc1, 0x00, 0xc1, 0xff, 0xff, 0xc8
+ };
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void s6e8ax0_display_cond(struct s6e8ax0 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ const unsigned char data_to_send[] = {
+ 0xf2, 0x80, 0x03, 0x0d
+ };
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+/* Gamma 2.2 Setting (200cd, 7500K, 10MPCD) */
+static void s6e8ax0_gamma_cond(struct s6e8ax0 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ unsigned int gamma = lcd->bd->props.brightness;
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ s6e8ax0_22_gamma_table[gamma],
+ GAMMA_TABLE_COUNT);
+}
+
+static void s6e8ax0_gamma_update(struct s6e8ax0 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ const unsigned char data_to_send[] = {
+ 0xf7, 0x03
+ };
+
+ ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_SHORT_WRITE_PARAM, data_to_send,
+ ARRAY_SIZE(data_to_send));
+}
+
+static void s6e8ax0_etc_cond1(struct s6e8ax0 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ const unsigned char data_to_send[] = {
+ 0xd1, 0xfe, 0x80, 0x00, 0x01, 0x0b, 0x00, 0x00, 0x40,
+ 0x0d, 0x00, 0x00
+ };
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void s6e8ax0_etc_cond2(struct s6e8ax0 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ const unsigned char data_to_send[] = {
+ 0xb6, 0x0c, 0x02, 0x03, 0x32, 0xff, 0x44, 0x44, 0xc0,
+ 0x00
+ };
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void s6e8ax0_etc_cond3(struct s6e8ax0 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ const unsigned char data_to_send[] = {
+ 0xe1, 0x10, 0x1c, 0x17, 0x08, 0x1d
+ };
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void s6e8ax0_etc_cond4(struct s6e8ax0 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ const unsigned char data_to_send[] = {
+ 0xe2, 0xed, 0x07, 0xc3, 0x13, 0x0d, 0x03
+ };
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void s6e8ax0_etc_cond5(struct s6e8ax0 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ const unsigned char data_to_send[] = {
+ 0xf4, 0xcf, 0x0a, 0x12, 0x10, 0x19, 0x33, 0x02
+ };
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ data_to_send, ARRAY_SIZE(data_to_send));
+}
+static void s6e8ax0_etc_cond6(struct s6e8ax0 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ const unsigned char data_to_send[] = {
+ 0xe3, 0x40
+ };
+
+ ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_SHORT_WRITE_PARAM,
+ data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void s6e8ax0_etc_cond7(struct s6e8ax0 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ const unsigned char data_to_send[] = {
+ 0xe4, 0x00, 0x00, 0x14, 0x80, 0x00, 0x00, 0x00
+ };
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void s6e8ax0_elvss_set(struct s6e8ax0 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ const unsigned char data_to_send[] = {
+ 0xb1, 0x04, 0x00
+ };
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void s6e8ax0_elvss_nvm_set(struct s6e8ax0 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ const unsigned char data_to_send[] = {
+ 0xd9, 0x5c, 0x20, 0x0c, 0x0f, 0x41, 0x00, 0x10, 0x11,
+ 0x12, 0xd1, 0x00, 0x00, 0x00, 0x00, 0x80, 0xcb, 0xed,
+ 0x64, 0xaf
+ };
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void s6e8ax0_sleep_in(struct s6e8ax0 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ const unsigned char data_to_send[] = {
+ 0x10, 0x00
+ };
+
+ ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_SHORT_WRITE,
+ data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void s6e8ax0_sleep_out(struct s6e8ax0 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ const unsigned char data_to_send[] = {
+ 0x11, 0x00
+ };
+
+ ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_SHORT_WRITE,
+ data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void s6e8ax0_display_on(struct s6e8ax0 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ const unsigned char data_to_send[] = {
+ 0x29, 0x00
+ };
+
+ ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_SHORT_WRITE,
+ data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void s6e8ax0_display_off(struct s6e8ax0 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ const unsigned char data_to_send[] = {
+ 0x28, 0x00
+ };
+
+ ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_SHORT_WRITE,
+ data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void s6e8ax0_apply_level2_key(struct s6e8ax0 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ const unsigned char data_to_send[] = {
+ 0xf0, 0x5a, 0x5a
+ };
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void s6e8ax0_acl_on(struct s6e8ax0 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ const unsigned char data_to_send[] = {
+ 0xc0, 0x01
+ };
+
+ ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_SHORT_WRITE,
+ data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+static void s6e8ax0_acl_off(struct s6e8ax0 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ const unsigned char data_to_send[] = {
+ 0xc0, 0x00
+ };
+
+ ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_SHORT_WRITE,
+ data_to_send, ARRAY_SIZE(data_to_send));
+}
+
+/* Full white 50% reducing setting */
+static void s6e8ax0_acl_ctrl_set(struct s6e8ax0 *lcd)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ /* Full white 50% reducing setting */
+ const unsigned char cutoff_50[] = {
+ 0xc1, 0x47, 0x53, 0x13, 0x53, 0x00, 0x00, 0x02, 0xcf,
+ 0x00, 0x00, 0x04, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x08, 0x0f, 0x16, 0x1d, 0x24, 0x2a, 0x31, 0x38,
+ 0x3f, 0x46
+ };
+ /* Full white 45% reducing setting */
+ const unsigned char cutoff_45[] = {
+ 0xc1, 0x47, 0x53, 0x13, 0x53, 0x00, 0x00, 0x02, 0xcf,
+ 0x00, 0x00, 0x04, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x07, 0x0d, 0x13, 0x19, 0x1f, 0x25, 0x2b, 0x31,
+ 0x37, 0x3d
+ };
+ /* Full white 40% reducing setting */
+ const unsigned char cutoff_40[] = {
+ 0xc1, 0x47, 0x53, 0x13, 0x53, 0x00, 0x00, 0x02, 0xcf,
+ 0x00, 0x00, 0x04, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x06, 0x0c, 0x11, 0x16, 0x1c, 0x21, 0x26, 0x2b,
+ 0x31, 0x36
+ };
+
+ if (lcd->acl_enable) {
+ if (lcd->cur_acl = 0) {
+ if (lcd->gamma = 0 || lcd->gamma = 1) {
+ s6e8ax0_acl_off(lcd);
+ dev_dbg(&lcd->ld->dev,
+ "cur_acl=%d\n", lcd->cur_acl);
+ } else
+ s6e8ax0_acl_on(lcd);
+ }
+ switch (lcd->gamma) {
+ case 0: /* 30cd */
+ s6e8ax0_acl_off(lcd);
+ lcd->cur_acl = 0;
+ break;
+ case 1 ... 3: /* 50cd ~ 90cd */
+ ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_LONG_WRITE,
+ cutoff_40,
+ ARRAY_SIZE(cutoff_40));
+ lcd->cur_acl = 40;
+ break;
+ case 4 ... 7: /* 120cd ~ 210cd */
+ ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_LONG_WRITE,
+ cutoff_45,
+ ARRAY_SIZE(cutoff_45));
+ lcd->cur_acl = 45;
+ break;
+ case 8 ... 10: /* 220cd ~ 300cd */
+ ops->cmd_write(lcd_to_master(lcd),
+ MIPI_DSI_DCS_LONG_WRITE,
+ cutoff_50,
+ ARRAY_SIZE(cutoff_50));
+ lcd->cur_acl = 50;
+ break;
+ default:
+ break;
+ }
+ } else {
+ s6e8ax0_acl_off(lcd);
+ lcd->cur_acl = 0;
+ dev_dbg(&lcd->ld->dev, "cur_acl = %d\n", lcd->cur_acl);
+ }
+}
+
+static void s6e8ax0_read_id(struct s6e8ax0 *lcd, u8 *mtp_id)
+{
+ unsigned int ret;
+ unsigned int addr = 0xd1; /* MTP ID */
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+
+ ret = ops->cmd_read(lcd_to_master(lcd),
+ MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM,
+ addr, 3, mtp_id);
+}
+
+static int s6e8ax0_panel_init(struct s6e8ax0 *lcd)
+{
+ s6e8ax0_apply_level2_key(lcd);
+ s6e8ax0_sleep_out(lcd);
+ msleep(1);
+ s6e8ax0_panel_cond(lcd);
+ s6e8ax0_display_cond(lcd);
+ s6e8ax0_gamma_cond(lcd);
+ s6e8ax0_gamma_update(lcd);
+
+ s6e8ax0_etc_cond1(lcd);
+ s6e8ax0_etc_cond2(lcd);
+ s6e8ax0_etc_cond3(lcd);
+ s6e8ax0_etc_cond4(lcd);
+ s6e8ax0_etc_cond5(lcd);
+ s6e8ax0_etc_cond6(lcd);
+ s6e8ax0_etc_cond7(lcd);
+
+ s6e8ax0_elvss_nvm_set(lcd);
+ s6e8ax0_elvss_set(lcd);
+
+ s6e8ax0_acl_ctrl_set(lcd);
+ s6e8ax0_acl_on(lcd);
+
+ /* if ID3 value is not 33h, branch private elvss mode */
+ msleep(lcd->ddi_pd->power_on_delay);
+
+ return 0;
+}
+
+static int s6e8ax0_update_gamma_ctrl(struct s6e8ax0 *lcd, int brightness)
+{
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+
+ ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
+ s6e8ax0_22_gamma_table[brightness],
+ ARRAY_SIZE(s6e8ax0_22_gamma_table));
+
+ /* update gamma table. */
+ s6e8ax0_gamma_update(lcd);
+ lcd->gamma = brightness;
+
+ return 0;
+}
+
+static int s6e8ax0_gamma_ctrl(struct s6e8ax0 *lcd, int gamma)
+{
+ s6e8ax0_update_gamma_ctrl(lcd, gamma);
+
+ return 0;
+}
+
+static int s6e8ax0_set_power(struct lcd_device *ld, int power)
+{
+ struct s6e8ax0 *lcd = lcd_get_data(ld);
+ struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
+ int ret = 0;
+
+ if (power != FB_BLANK_UNBLANK && power != FB_BLANK_POWERDOWN &&
+ power != FB_BLANK_NORMAL) {
+ dev_err(lcd->dev, "power value should be 0, 1 or 4.\n");
+ return -EINVAL;
+ }
+
+ if ((power = FB_BLANK_UNBLANK) && ops->set_blank_mode) {
+ /* LCD power on */
+ if ((POWER_IS_ON(power) && POWER_IS_OFF(lcd->power))
+ || (POWER_IS_ON(power) && POWER_IS_NRM(lcd->power))) {
+ ret = ops->set_blank_mode(lcd_to_master(lcd), power);
+ if (!ret && lcd->power != power)
+ lcd->power = power;
+ }
+ } else if ((power = FB_BLANK_POWERDOWN) && ops->set_early_blank_mode) {
+ /* LCD power off */
+ if ((POWER_IS_OFF(power) && POWER_IS_ON(lcd->power)) ||
+ (POWER_IS_ON(lcd->power) && POWER_IS_NRM(power))) {
+ ret = ops->set_early_blank_mode(lcd_to_master(lcd),
+ power);
+ if (!ret && lcd->power != power)
+ lcd->power = power;
+ }
+ }
+
+ return ret;
+}
+
+static int s6e8ax0_get_power(struct lcd_device *ld)
+{
+ struct s6e8ax0 *lcd = lcd_get_data(ld);
+
+ return lcd->power;
+}
+
+static int s6e8ax0_get_brightness(struct backlight_device *bd)
+{
+ return bd->props.brightness;
+}
+
+static int s6e8ax0_set_brightness(struct backlight_device *bd)
+{
+ int ret = 0, brightness = bd->props.brightness;
+ struct s6e8ax0 *lcd = bl_get_data(bd);
+
+ if (brightness < MIN_BRIGHTNESS ||
+ brightness > bd->props.max_brightness) {
+ dev_err(lcd->dev, "lcd brightness should be %d to %d.\n",
+ MIN_BRIGHTNESS, MAX_BRIGHTNESS);
+ return -EINVAL;
+ }
+
+ ret = s6e8ax0_gamma_ctrl(lcd, brightness);
+ if (ret) {
+ dev_err(&bd->dev, "lcd brightness setting failed.\n");
+ return -EIO;
+ }
+
+ return ret;
+}
+
+static struct lcd_ops s6e8ax0_lcd_ops = {
+ .set_power = s6e8ax0_set_power,
+ .get_power = s6e8ax0_get_power,
+};
+
+static struct backlight_ops s6e8ax0_backlight_ops = {
+ .get_brightness = s6e8ax0_get_brightness,
+ .update_status = s6e8ax0_set_brightness,
+};
+
+static void s6e8ax0_power_on(struct mipi_dsim_lcd_device *dsim_dev, int power)
+{
+ struct s6e8ax0 *lcd = dev_get_drvdata(&dsim_dev->dev);
+
+ msleep(lcd->ddi_pd->power_on_delay);
+
+ /* lcd power on */
+ if (power)
+ s6e8ax0_regulator_enable(lcd);
+ else
+ s6e8ax0_regulator_disable(lcd);
+
+ msleep(lcd->ddi_pd->reset_delay);
+
+ /* lcd reset */
+ if (lcd->ddi_pd->reset)
+ lcd->ddi_pd->reset(lcd->ld);
+ msleep(5);
+}
+
+static void s6e8ax0_set_sequence(struct mipi_dsim_lcd_device *dsim_dev)
+{
+ struct s6e8ax0 *lcd = dev_get_drvdata(&dsim_dev->dev);
+
+ s6e8ax0_panel_init(lcd);
+ s6e8ax0_display_on(lcd);
+
+ lcd->power = FB_BLANK_UNBLANK;
+}
+
+static int s6e8ax0_probe(struct mipi_dsim_lcd_device *dsim_dev)
+{
+ struct s6e8ax0 *lcd;
+ int ret;
+ u8 mtp_id[3] = {0, };
+
+ lcd = kzalloc(sizeof(struct s6e8ax0), GFP_KERNEL);
+ if (!lcd) {
+ dev_err(&dsim_dev->dev, "failed to allocate s6e8ax0 structure.\n");
+ return -ENOMEM;
+ }
+
+ lcd->dsim_dev = dsim_dev;
+ lcd->ddi_pd = (struct lcd_platform_data *)dsim_dev->platform_data;
+ lcd->dev = &dsim_dev->dev;
+
+ mutex_init(&lcd->lock);
+
+ ret = regulator_bulk_get(lcd->dev, ARRAY_SIZE(supplies), supplies);
+ if (ret) {
+ dev_err(lcd->dev, "Failed to get regulators: %d\n", ret);
+ goto err_lcd_register;
+ }
+
+ lcd->ld = lcd_device_register("s6e8ax0", lcd->dev, lcd,
+ &s6e8ax0_lcd_ops);
+ if (IS_ERR(lcd->ld)) {
+ dev_err(lcd->dev, "failed to register lcd ops.\n");
+ ret = PTR_ERR(lcd->ld);
+ goto err_lcd_register;
+ }
+
+ lcd->bd = backlight_device_register("s6e8ax0-bl", lcd->dev, lcd,
+ &s6e8ax0_backlight_ops, NULL);
+ if (IS_ERR(lcd->bd)) {
+ dev_err(lcd->dev, "failed to register backlight ops.\n");
+ ret = PTR_ERR(lcd->bd);
+ goto err_backlight_register;
+ }
+
+ lcd->bd->props.max_brightness = MAX_BRIGHTNESS;
+ lcd->bd->props.brightness = MAX_BRIGHTNESS;
+
+ s6e8ax0_read_id(lcd, mtp_id);
+ if (mtp_id[0] = 0x00)
+ dev_err(lcd->dev, "read id failed\n");
+
+ dev_info(lcd->dev, "Read ID : %x, %x, %x\n",
+ mtp_id[0], mtp_id[1], mtp_id[2]);
+
+ if (mtp_id[2] = 0x33)
+ dev_info(lcd->dev,
+ "ID-3 is 0xff does not support dynamic elvss\n");
+ else
+ dev_info(lcd->dev,
+ "ID-3 is 0x%x support dynamic elvss\n", mtp_id[2]);
+
+ lcd->acl_enable = 1;
+ lcd->cur_acl = 0;
+
+ dev_set_drvdata(&dsim_dev->dev, lcd);
+
+ dev_dbg(lcd->dev, "probed s6e8ax0 panel driver.\n");
+
+ return 0;
+
+err_backlight_register:
+ lcd_device_unregister(lcd->ld);
+
+err_lcd_register:
+ regulator_bulk_free(ARRAY_SIZE(supplies), supplies);
+ kfree(lcd);
+
+ return ret;
+}
+
+#ifdef CONFIG_PM
+static int s6e8ax0_suspend(struct mipi_dsim_lcd_device *dsim_dev)
+{
+ struct s6e8ax0 *lcd = dev_get_drvdata(&dsim_dev->dev);
+
+ s6e8ax0_sleep_in(lcd);
+ msleep(lcd->ddi_pd->power_off_delay);
+ s6e8ax0_display_off(lcd);
+
+ s6e8ax0_regulator_disable(lcd);
+
+ return 0;
+}
+
+static int s6e8ax0_resume(struct mipi_dsim_lcd_device *dsim_dev)
+{
+ struct s6e8ax0 *lcd = dev_get_drvdata(&dsim_dev->dev);
+
+ s6e8ax0_sleep_out(lcd);
+ msleep(lcd->ddi_pd->power_on_delay);
+
+ s6e8ax0_regulator_enable(lcd);
+ s6e8ax0_set_sequence(dsim_dev);
+
+ return 0;
+}
+#else
+#define s6e8ax0_suspend NULL
+#define s6e8ax0_resume NULL
+#endif
+
+static struct mipi_dsim_lcd_driver s6e8ax0_dsim_ddi_driver = {
+ .name = "s6e8ax0",
+ .id = -1,
+
+ .power_on = s6e8ax0_power_on,
+ .set_sequence = s6e8ax0_set_sequence,
+ .probe = s6e8ax0_probe,
+ .suspend = s6e8ax0_suspend,
+ .resume = s6e8ax0_resume,
+};
+
+static int s6e8ax0_init(void)
+{
+ s5p_mipi_dsi_register_lcd_driver(&s6e8ax0_dsim_ddi_driver);
+
+ return 0;
+}
+
+static void s6e8ax0_exit(void)
+{
+ return;
+}
+
+module_init(s6e8ax0_init);
+module_exit(s6e8ax0_exit);
+
+MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>");
+MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
+MODULE_DESCRIPTION("MIPI-DSI based s6e8ax0 AMOLED LCD Panel Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/backlight/s6e8ax0.h b/drivers/video/backlight/s6e8ax0.h
new file mode 100644
index 0000000..1f1b270
--- /dev/null
+++ b/drivers/video/backlight/s6e8ax0.h
@@ -0,0 +1,21 @@
+/* linux/drivers/video/backlight/s6e8ax0.h
+ *
+ * MIPI-DSI based s6e8ax0 AMOLED LCD Panel definitions.
+ *
+ * Copyright (c) 2011 Samsung Electronics
+ *
+ * Inki Dae, <inki.dae@samsung.com>
+ * Donghwa Lee <dh09.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef _S6E8AX0_H
+#define _S6E8AX0_H
+
+extern void s6e8ax0_init(void);
+
+#endif
+
--
1.7.4.1
^ permalink raw reply related
* [PATCH v6 1/2] video: support MIPI-DSI controller driver
From: Donghwa Lee @ 2012-01-18 2:03 UTC (permalink / raw)
To: linux-arm-kernel
Samsung S5PC210 and EXYNOS SoC platform has MIPI-DSI controller and MIPI-DSI
based LCD Panel could be used with it. This patch supports MIPI-DSI driver
based Samsung SoC chip.
LCD panel driver based MIPI-DSI should be registered to MIPI-DSI driver at
machine code and LCD panel driver specific function registered to mipi_dsim_ddi
structure at lcd panel init function called system init.
In the MIPI-DSI driver, find lcd panel driver by using registered
lcd panel name, and then initialize lcd panel driver.
Changes since v5:
- change s5p_mipi_dsi_wr_data() function 3rd parameter to arrays const
Signed-off-by: Donghwa Lee <dh09.lee@samsung.com>
Signed-off-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
drivers/video/Kconfig | 6 +
drivers/video/Makefile | 2 +
drivers/video/s5p_mipi_dsi.c | 613 ++++++++++++++++++++++
drivers/video/s5p_mipi_dsi_common.c | 896 +++++++++++++++++++++++++++++++++
drivers/video/s5p_mipi_dsi_common.h | 46 ++
drivers/video/s5p_mipi_dsi_lowlevel.c | 617 +++++++++++++++++++++++
drivers/video/s5p_mipi_dsi_lowlevel.h | 112 ++++
drivers/video/s5p_mipi_dsi_regs.h | 149 ++++++
include/linux/mipi_dsim.h | 359 +++++++++++++
9 files changed, 2800 insertions(+), 0 deletions(-)
create mode 100644 drivers/video/s5p_mipi_dsi.c
create mode 100644 drivers/video/s5p_mipi_dsi_common.c
create mode 100644 drivers/video/s5p_mipi_dsi_common.h
create mode 100644 drivers/video/s5p_mipi_dsi_lowlevel.c
create mode 100644 drivers/video/s5p_mipi_dsi_lowlevel.h
create mode 100644 drivers/video/s5p_mipi_dsi_regs.h
create mode 100644 include/linux/mipi_dsim.h
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index d83e967..bdc382e 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -2082,6 +2082,12 @@ config FB_S3C2410_DEBUG
Turn on debugging messages. Note that you can set/unset at run time
through sysfs
+config S5P_MIPI_DSI
+ tristate "Samsung SoC MIPI-DSI support."
+ depends on FB_S3C && (ARCH_S5PV210 || ARCH_EXYNOS)
+ help
+ This enables support for MIPI-DSI device.
+
config FB_NUC900
bool "NUC900 LCD framebuffer support"
depends on FB && ARCH_W90X900
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 9b9d8ff..29eb7c9 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -120,6 +120,8 @@ obj-$(CONFIG_FB_SH7760) += sh7760fb.o
obj-$(CONFIG_FB_IMX) += imxfb.o
obj-$(CONFIG_FB_S3C) += s3c-fb.o
obj-$(CONFIG_FB_S3C2410) += s3c2410fb.o
+obj-$(CONFIG_S5P_MIPI_DSI) += s5p_mipi_dsi.o s5p_mipi_dsi_common.o \
+ s5p_mipi_dsi_lowlevel.o
obj-$(CONFIG_FB_FSL_DIU) += fsl-diu-fb.o
obj-$(CONFIG_FB_COBALT) += cobalt_lcdfb.o
obj-$(CONFIG_FB_PNX4008_DUM) += pnx4008/
diff --git a/drivers/video/s5p_mipi_dsi.c b/drivers/video/s5p_mipi_dsi.c
new file mode 100644
index 0000000..f9053f8
--- /dev/null
+++ b/drivers/video/s5p_mipi_dsi.c
@@ -0,0 +1,613 @@
+/* linux/drivers/video/s5p_mipi_dsi.c
+ *
+ * Samsung SoC MIPI-DSIM driver.
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * InKi Dae, <inki.dae@samsung.com>
+ * Donghwa Lee, <dh09.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/clk.h>
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/fb.h>
+#include <linux/ctype.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/memory.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/kthread.h>
+#include <linux/notifier.h>
+#include <linux/mipi_dsim.h>
+#include <linux/regulator/consumer.h>
+#include <linux/pm_runtime.h>
+
+#include <plat/fb.h>
+
+#include "s5p_mipi_dsi_common.h"
+#include "s5p_mipi_dsi_lowlevel.h"
+
+#define master_to_driver(a) (a->dsim_lcd_drv)
+#define master_to_device(a) (a->dsim_lcd_dev)
+#define dev_to_dsim(a) platform_get_drvdata(to_platform_device(a))
+
+struct mipi_dsim_ddi {
+ int bus_id;
+ struct list_head list;
+ struct mipi_dsim_lcd_device *dsim_lcd_dev;
+ struct mipi_dsim_lcd_driver *dsim_lcd_drv;
+};
+
+static LIST_HEAD(dsim_ddi_list);
+
+static DEFINE_MUTEX(mipi_dsim_lock);
+
+static struct mipi_dsim_platform_data *to_dsim_plat(struct platform_device
+ *pdev)
+{
+ return pdev->dev.platform_data;
+}
+
+static struct regulator_bulk_data supplies[] = {
+ { .supply = "vdd10", },
+ { .supply = "vdd18", },
+};
+
+static int s5p_mipi_regulator_enable(struct mipi_dsim_device *dsim)
+{
+ int ret;
+
+ mutex_lock(&dsim->lock);
+ ret = regulator_bulk_enable(ARRAY_SIZE(supplies), supplies);
+ mutex_unlock(&dsim->lock);
+
+ return ret;
+}
+
+static int s5p_mipi_regulator_disable(struct mipi_dsim_device *dsim)
+{
+ int ret;
+
+ mutex_lock(&dsim->lock);
+ ret = regulator_bulk_disable(ARRAY_SIZE(supplies), supplies);
+ mutex_unlock(&dsim->lock);
+
+ return ret;
+}
+
+/* update all register settings to MIPI DSI controller. */
+static void s5p_mipi_update_cfg(struct mipi_dsim_device *dsim)
+{
+ /*
+ * data from Display controller(FIMD) is not transferred in video mode
+ * but in case of command mode, all settings is not updated to
+ * registers.
+ */
+ s5p_mipi_dsi_stand_by(dsim, 0);
+
+ s5p_mipi_dsi_init_dsim(dsim);
+ s5p_mipi_dsi_init_link(dsim);
+
+ s5p_mipi_dsi_set_hs_enable(dsim);
+
+ /* set display timing. */
+ s5p_mipi_dsi_set_display_mode(dsim, dsim->dsim_config);
+
+ /*
+ * data from Display controller(FIMD) is transferred in video mode
+ * but in case of command mode, all settigs is updated to registers.
+ */
+ s5p_mipi_dsi_stand_by(dsim, 1);
+}
+
+static int s5p_mipi_dsi_early_blank_mode(struct mipi_dsim_device *dsim,
+ int power)
+{
+ struct mipi_dsim_lcd_driver *client_drv = master_to_driver(dsim);
+ struct mipi_dsim_lcd_device *client_dev = master_to_device(dsim);
+
+ switch (power) {
+ case FB_BLANK_POWERDOWN:
+ if (dsim->suspended)
+ return 0;
+
+ if (client_drv && client_drv->suspend)
+ client_drv->suspend(client_dev);
+
+ clk_disable(dsim->clock);
+
+ s5p_mipi_regulator_disable(dsim);
+
+ dsim->suspended = true;
+
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int s5p_mipi_dsi_blank_mode(struct mipi_dsim_device *dsim, int power)
+{
+ struct platform_device *pdev = to_platform_device(dsim->dev);
+ struct mipi_dsim_lcd_driver *client_drv = master_to_driver(dsim);
+ struct mipi_dsim_lcd_device *client_dev = master_to_device(dsim);
+
+ switch (power) {
+ case FB_BLANK_UNBLANK:
+ if (!dsim->suspended)
+ return 0;
+
+ /* lcd panel power on. */
+ if (client_drv && client_drv->power_on)
+ client_drv->power_on(client_dev, 1);
+
+ s5p_mipi_regulator_disable(dsim);
+
+ /* enable MIPI-DSI PHY. */
+ if (dsim->pd->phy_enable)
+ dsim->pd->phy_enable(pdev, true);
+
+ clk_enable(dsim->clock);
+
+ s5p_mipi_update_cfg(dsim);
+
+ /* set lcd panel sequence commands. */
+ if (client_drv && client_drv->set_sequence)
+ client_drv->set_sequence(client_dev);
+
+ dsim->suspended = false;
+
+ break;
+ case FB_BLANK_NORMAL:
+ /* TODO. */
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+int s5p_mipi_dsi_register_lcd_device(struct mipi_dsim_lcd_device *lcd_dev)
+{
+ struct mipi_dsim_ddi *dsim_ddi;
+
+ if (!lcd_dev) {
+ pr_err("mipi_dsim_lcd_device is NULL.\n");
+ return -EFAULT;
+ }
+
+ if (!lcd_dev->name) {
+ pr_err("dsim_lcd_device name is NULL.\n");
+ return -EFAULT;
+ }
+
+ dsim_ddi = kzalloc(sizeof(struct mipi_dsim_ddi), GFP_KERNEL);
+ if (!dsim_ddi) {
+ pr_err("failed to allocate dsim_ddi object.\n");
+ return -EFAULT;
+ }
+
+ dsim_ddi->dsim_lcd_dev = lcd_dev;
+
+ mutex_lock(&mipi_dsim_lock);
+ list_add_tail(&dsim_ddi->list, &dsim_ddi_list);
+ mutex_unlock(&mipi_dsim_lock);
+
+ return 0;
+}
+
+struct mipi_dsim_ddi
+ *s5p_mipi_dsi_find_lcd_device(struct mipi_dsim_lcd_driver *lcd_drv)
+{
+ struct mipi_dsim_ddi *dsim_ddi, *next;
+ struct mipi_dsim_lcd_device *lcd_dev;
+
+ mutex_lock(&mipi_dsim_lock);
+
+ list_for_each_entry_safe(dsim_ddi, next, &dsim_ddi_list, list) {
+ if (!dsim_ddi)
+ goto out;
+
+ lcd_dev = dsim_ddi->dsim_lcd_dev;
+ if (!lcd_dev)
+ continue;
+
+ if ((strcmp(lcd_drv->name, lcd_dev->name)) = 0) {
+ /**
+ * bus_id would be used to identify
+ * connected bus.
+ */
+ dsim_ddi->bus_id = lcd_dev->bus_id;
+ mutex_unlock(&mipi_dsim_lock);
+
+ return dsim_ddi;
+ }
+
+ list_del(&dsim_ddi->list);
+ kfree(dsim_ddi);
+ }
+
+out:
+ mutex_unlock(&mipi_dsim_lock);
+
+ return NULL;
+}
+
+int s5p_mipi_dsi_register_lcd_driver(struct mipi_dsim_lcd_driver *lcd_drv)
+{
+ struct mipi_dsim_ddi *dsim_ddi;
+
+ if (!lcd_drv) {
+ pr_err("mipi_dsim_lcd_driver is NULL.\n");
+ return -EFAULT;
+ }
+
+ if (!lcd_drv->name) {
+ pr_err("dsim_lcd_driver name is NULL.\n");
+ return -EFAULT;
+ }
+
+ dsim_ddi = s5p_mipi_dsi_find_lcd_device(lcd_drv);
+ if (!dsim_ddi) {
+ pr_err("mipi_dsim_ddi object not found.\n");
+ return -EFAULT;
+ }
+
+ dsim_ddi->dsim_lcd_drv = lcd_drv;
+
+ pr_info("registered panel driver(%s) to mipi-dsi driver.\n",
+ lcd_drv->name);
+
+ return 0;
+
+}
+
+struct mipi_dsim_ddi
+ *s5p_mipi_dsi_bind_lcd_ddi(struct mipi_dsim_device *dsim,
+ const char *name)
+{
+ struct mipi_dsim_ddi *dsim_ddi, *next;
+ struct mipi_dsim_lcd_driver *lcd_drv;
+ struct mipi_dsim_lcd_device *lcd_dev;
+ int ret;
+
+ mutex_lock(&dsim->lock);
+
+ list_for_each_entry_safe(dsim_ddi, next, &dsim_ddi_list, list) {
+ lcd_drv = dsim_ddi->dsim_lcd_drv;
+ lcd_dev = dsim_ddi->dsim_lcd_dev;
+ if (!lcd_drv || !lcd_dev ||
+ (dsim->id != dsim_ddi->bus_id))
+ continue;
+
+ dev_dbg(dsim->dev, "lcd_drv->id = %d, lcd_dev->id = %d\n",
+ lcd_drv->id, lcd_dev->id);
+ dev_dbg(dsim->dev, "lcd_dev->bus_id = %d, dsim->id = %d\n",
+ lcd_dev->bus_id, dsim->id);
+
+ if ((strcmp(lcd_drv->name, name) = 0)) {
+ lcd_dev->master = dsim;
+
+ lcd_dev->dev.parent = dsim->dev;
+ dev_set_name(&lcd_dev->dev, "%s", lcd_drv->name);
+
+ ret = device_register(&lcd_dev->dev);
+ if (ret < 0) {
+ dev_err(dsim->dev,
+ "can't register %s, status %d\n",
+ dev_name(&lcd_dev->dev), ret);
+ mutex_unlock(&dsim->lock);
+
+ return NULL;
+ }
+
+ dsim->dsim_lcd_dev = lcd_dev;
+ dsim->dsim_lcd_drv = lcd_drv;
+
+ mutex_unlock(&dsim->lock);
+
+ return dsim_ddi;
+ }
+ }
+
+ mutex_unlock(&dsim->lock);
+
+ return NULL;
+}
+
+/* define MIPI-DSI Master operations. */
+static struct mipi_dsim_master_ops master_ops = {
+ .cmd_read = s5p_mipi_dsi_rd_data,
+ .cmd_write = s5p_mipi_dsi_wr_data,
+ .get_dsim_frame_done = s5p_mipi_dsi_get_frame_done_status,
+ .clear_dsim_frame_done = s5p_mipi_dsi_clear_frame_done,
+ .set_early_blank_mode = s5p_mipi_dsi_early_blank_mode,
+ .set_blank_mode = s5p_mipi_dsi_blank_mode,
+};
+
+static int s5p_mipi_dsi_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct mipi_dsim_device *dsim;
+ struct mipi_dsim_config *dsim_config;
+ struct mipi_dsim_platform_data *dsim_pd;
+ struct mipi_dsim_ddi *dsim_ddi;
+ int ret = -EINVAL;
+
+ dsim = kzalloc(sizeof(struct mipi_dsim_device), GFP_KERNEL);
+ if (!dsim) {
+ dev_err(&pdev->dev, "failed to allocate dsim object.\n");
+ return -EFAULT;
+ }
+
+ dsim->pd = to_dsim_plat(pdev);
+ dsim->dev = &pdev->dev;
+ dsim->id = pdev->id;
+
+ /* get mipi_dsim_platform_data. */
+ dsim_pd = (struct mipi_dsim_platform_data *)dsim->pd;
+ if (dsim_pd = NULL) {
+ dev_err(&pdev->dev, "failed to get platform data for dsim.\n");
+ goto err_clock_get;
+ }
+ /* get mipi_dsim_config. */
+ dsim_config = dsim_pd->dsim_config;
+ if (dsim_config = NULL) {
+ dev_err(&pdev->dev, "failed to get dsim config data.\n");
+ goto err_clock_get;
+ }
+
+ dsim->dsim_config = dsim_config;
+ dsim->master_ops = &master_ops;
+
+ mutex_init(&dsim->lock);
+
+ ret = regulator_bulk_get(&pdev->dev, ARRAY_SIZE(supplies), supplies);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to get regulators: %d\n", ret);
+ goto err_clock_get;
+ }
+
+ dsim->clock = clk_get(&pdev->dev, "dsim0");
+ if (IS_ERR(dsim->clock)) {
+ dev_err(&pdev->dev, "failed to get dsim clock source\n");
+ goto err_clock_get;
+ }
+
+ clk_enable(dsim->clock);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "failed to get io memory region\n");
+ goto err_platform_get;
+ }
+
+ dsim->res = request_mem_region(res->start, resource_size(res),
+ dev_name(&pdev->dev));
+ if (!dsim->res) {
+ dev_err(&pdev->dev, "failed to request io memory region\n");
+ ret = -ENOMEM;
+ goto err_mem_region;
+ }
+
+ dsim->reg_base = ioremap(res->start, resource_size(res));
+ if (!dsim->reg_base) {
+ dev_err(&pdev->dev, "failed to remap io region\n");
+ ret = -EFAULT;
+ goto err_ioremap;
+ }
+
+ mutex_init(&dsim->lock);
+
+ /* bind lcd ddi matched with panel name. */
+ dsim_ddi = s5p_mipi_dsi_bind_lcd_ddi(dsim, dsim_pd->lcd_panel_name);
+ if (!dsim_ddi) {
+ dev_err(&pdev->dev, "mipi_dsim_ddi object not found.\n");
+ goto err_bind;
+ }
+
+ dsim->irq = platform_get_irq(pdev, 0);
+ if (dsim->irq < 0) {
+ dev_err(&pdev->dev, "failed to request dsim irq resource\n");
+ ret = -EINVAL;
+ goto err_platform_get_irq;
+ }
+
+ ret = request_irq(dsim->irq, s5p_mipi_dsi_interrupt_handler,
+ IRQF_SHARED, pdev->name, dsim);
+ if (ret != 0) {
+ dev_err(&pdev->dev, "failed to request dsim irq\n");
+ ret = -EINVAL;
+ goto err_bind;
+ }
+
+ init_completion(&dsim_wr_comp);
+ init_completion(&dsim_rd_comp);
+
+ /* enable interrupt */
+ s5p_mipi_dsi_init_interrupt(dsim);
+
+ /* initialize mipi-dsi client(lcd panel). */
+ if (dsim_ddi->dsim_lcd_drv && dsim_ddi->dsim_lcd_drv->probe)
+ dsim_ddi->dsim_lcd_drv->probe(dsim_ddi->dsim_lcd_dev);
+
+ /* in case that mipi got enabled at bootloader. */
+ if (dsim_pd->enabled)
+ goto out;
+
+ /* lcd panel power on. */
+ if (dsim_ddi->dsim_lcd_drv && dsim_ddi->dsim_lcd_drv->power_on)
+ dsim_ddi->dsim_lcd_drv->power_on(dsim_ddi->dsim_lcd_dev, 1);
+
+ s5p_mipi_regulator_enable(dsim);
+
+ /* enable MIPI-DSI PHY. */
+ if (dsim->pd->phy_enable)
+ dsim->pd->phy_enable(pdev, true);
+
+ s5p_mipi_update_cfg(dsim);
+
+ /* set lcd panel sequence commands. */
+ if (dsim_ddi->dsim_lcd_drv && dsim_ddi->dsim_lcd_drv->set_sequence)
+ dsim_ddi->dsim_lcd_drv->set_sequence(dsim_ddi->dsim_lcd_dev);
+
+ dsim->suspended = false;
+
+out:
+ platform_set_drvdata(pdev, dsim);
+
+ dev_dbg(&pdev->dev, "mipi-dsi driver(%s mode) has been probed.\n",
+ (dsim_config->e_interface = DSIM_COMMAND) ?
+ "CPU" : "RGB");
+
+ return 0;
+
+err_bind:
+ iounmap(dsim->reg_base);
+
+err_ioremap:
+ release_mem_region(dsim->res->start, resource_size(dsim->res));
+
+err_mem_region:
+ release_resource(dsim->res);
+
+err_platform_get:
+ clk_disable(dsim->clock);
+ clk_put(dsim->clock);
+err_clock_get:
+ kfree(dsim);
+
+err_platform_get_irq:
+ return ret;
+}
+
+static int __devexit s5p_mipi_dsi_remove(struct platform_device *pdev)
+{
+ struct mipi_dsim_device *dsim = platform_get_drvdata(pdev);
+ struct mipi_dsim_ddi *dsim_ddi, *next;
+ struct mipi_dsim_lcd_driver *dsim_lcd_drv;
+
+ iounmap(dsim->reg_base);
+
+ clk_disable(dsim->clock);
+ clk_put(dsim->clock);
+
+ release_resource(dsim->res);
+ release_mem_region(dsim->res->start, resource_size(dsim->res));
+
+ list_for_each_entry_safe(dsim_ddi, next, &dsim_ddi_list, list) {
+ if (dsim_ddi) {
+ if (dsim->id != dsim_ddi->bus_id)
+ continue;
+
+ dsim_lcd_drv = dsim_ddi->dsim_lcd_drv;
+
+ if (dsim_lcd_drv->remove)
+ dsim_lcd_drv->remove(dsim_ddi->dsim_lcd_dev);
+
+ kfree(dsim_ddi);
+ }
+ }
+
+ regulator_bulk_free(ARRAY_SIZE(supplies), supplies);
+ kfree(dsim);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int s5p_mipi_dsi_suspend(struct platform_device *pdev,
+ pm_message_t state)
+{
+ struct mipi_dsim_device *dsim = platform_get_drvdata(pdev);
+
+ disable_irq(dsim->irq);
+
+ if (dsim->suspended)
+ return 0;
+
+ if (master_to_driver(dsim) && (master_to_driver(dsim))->suspend)
+ (master_to_driver(dsim))->suspend(master_to_device(dsim));
+
+ /* enable MIPI-DSI PHY. */
+ if (dsim->pd->phy_enable)
+ dsim->pd->phy_enable(pdev, false);
+
+ clk_disable(dsim->clock);
+
+ s5p_mipi_regulator_disable(dsim);
+
+ dsim->suspended = true;
+
+ return 0;
+}
+
+static int s5p_mipi_dsi_resume(struct platform_device *pdev)
+{
+ struct mipi_dsim_device *dsim = platform_get_drvdata(pdev);
+ struct mipi_dsim_lcd_driver *client_drv = master_to_driver(dsim);
+ struct mipi_dsim_lcd_device *client_dev = master_to_device(dsim);
+
+ enable_irq(dsim->irq);
+
+ if (!dsim->suspended)
+ return 0;
+
+ /* lcd panel power on. */
+ if (client_drv && client_drv->power_on)
+ client_drv->power_on(client_dev, 1);
+
+ s5p_mipi_regulator_enable(dsim);
+
+ /* enable MIPI-DSI PHY. */
+ if (dsim->pd->phy_enable)
+ dsim->pd->phy_enable(pdev, true);
+
+ clk_enable(dsim->clock);
+
+ s5p_mipi_update_cfg(dsim);
+
+ /* set lcd panel sequence commands. */
+ if (client_drv && client_drv->set_sequence)
+ client_drv->set_sequence(client_dev);
+
+ dsim->suspended = false;
+
+ return 0;
+}
+#else
+#define s5p_mipi_dsi_suspend NULL
+#define s5p_mipi_dsi_resume NULL
+#endif
+
+static struct platform_driver s5p_mipi_dsi_driver = {
+ .probe = s5p_mipi_dsi_probe,
+ .remove = __devexit_p(s5p_mipi_dsi_remove),
+ .suspend = s5p_mipi_dsi_suspend,
+ .resume = s5p_mipi_dsi_resume,
+ .driver = {
+ .name = "s5p-mipi-dsim",
+ .owner = THIS_MODULE,
+ },
+};
+
+module_platform_driver(s5p_mipi_dsi_driver);
+
+MODULE_AUTHOR("InKi Dae <inki.dae@samsung.com>");
+MODULE_DESCRIPTION("Samusung SoC MIPI-DSI driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/s5p_mipi_dsi_common.c b/drivers/video/s5p_mipi_dsi_common.c
new file mode 100644
index 0000000..7d14d7e
--- /dev/null
+++ b/drivers/video/s5p_mipi_dsi_common.c
@@ -0,0 +1,896 @@
+/* linux/drivers/video/s5p_mipi_dsi_common.c
+ *
+ * Samsung SoC MIPI-DSI common driver.
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * InKi Dae, <inki.dae@samsung.com>
+ * Donghwa Lee, <dh09.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/fb.h>
+#include <linux/ctype.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/memory.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <linux/mipi_dsim.h>
+
+#include <video/mipi_display.h>
+
+#include <mach/map.h>
+
+#include "s5p_mipi_dsi_regs.h"
+#include "s5p_mipi_dsi_lowlevel.h"
+#include "s5p_mipi_dsi_common.h"
+
+#define MIPI_FIFO_TIMEOUT msecs_to_jiffies(250)
+#define MIPI_RX_FIFO_READ_DONE 0x30800002
+#define MIPI_MAX_RX_FIFO 20
+#define MHZ (1000 * 1000)
+#define FIN_HZ (24 * MHZ)
+
+#define DFIN_PLL_MIN_HZ (6 * MHZ)
+#define DFIN_PLL_MAX_HZ (12 * MHZ)
+
+#define DFVCO_MIN_HZ (500 * MHZ)
+#define DFVCO_MAX_HZ (1000 * MHZ)
+
+#define TRY_GET_FIFO_TIMEOUT (5000 * 2)
+#define TRY_FIFO_CLEAR (10)
+
+/* MIPI-DSIM status types. */
+enum {
+ DSIM_STATE_INIT, /* should be initialized. */
+ DSIM_STATE_STOP, /* CPU and LCDC are LP mode. */
+ DSIM_STATE_HSCLKEN, /* HS clock was enabled. */
+ DSIM_STATE_ULPS
+};
+
+/* define DSI lane types. */
+enum {
+ DSIM_LANE_CLOCK = (1 << 0),
+ DSIM_LANE_DATA0 = (1 << 1),
+ DSIM_LANE_DATA1 = (1 << 2),
+ DSIM_LANE_DATA2 = (1 << 3),
+ DSIM_LANE_DATA3 = (1 << 4)
+};
+
+static unsigned int dpll_table[15] = {
+ 100, 120, 170, 220, 270,
+ 320, 390, 450, 510, 560,
+ 640, 690, 770, 870, 950
+};
+
+irqreturn_t s5p_mipi_dsi_interrupt_handler(int irq, void *dev_id)
+{
+ unsigned int intsrc = 0;
+ unsigned int intmsk = 0;
+ struct mipi_dsim_device *dsim = NULL;
+
+ dsim = (struct mipi_dsim_device *)dev_id;
+ if (!dsim) {
+ dev_dbg(dsim->dev, KERN_ERR "%s:error: wrong parameter\n",
+ __func__);
+ return IRQ_HANDLED;
+ }
+
+ intsrc = s5p_mipi_dsi_read_interrupt(dsim);
+ intmsk = s5p_mipi_dsi_read_interrupt_mask(dsim);
+
+ intmsk = ~(intmsk) & intsrc;
+
+ switch (intmsk) {
+ case INTMSK_RX_DONE:
+ complete(&dsim_rd_comp);
+ dev_dbg(dsim->dev, "MIPI INTMSK_RX_DONE\n");
+ break;
+ case INTMSK_FIFO_EMPTY:
+ complete(&dsim_wr_comp);
+ dev_dbg(dsim->dev, "MIPI INTMSK_FIFO_EMPTY\n");
+ break;
+ default:
+ break;
+ }
+
+ s5p_mipi_dsi_clear_interrupt(dsim, intmsk);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * write long packet to mipi dsi slave
+ * @dsim: mipi dsim device structure.
+ * @data0: packet data to send.
+ * @data1: size of packet data
+ */
+static void s5p_mipi_dsi_long_data_wr(struct mipi_dsim_device *dsim,
+ const unsigned char *data0, unsigned int data_size)
+{
+ unsigned int data_cnt = 0, payload = 0;
+
+ /* in case that data count is more then 4 */
+ for (data_cnt = 0; data_cnt < data_size; data_cnt += 4) {
+ /*
+ * after sending 4bytes per one time,
+ * send remainder data less then 4.
+ */
+ if ((data_size - data_cnt) < 4) {
+ if ((data_size - data_cnt) = 3) {
+ payload = data0[data_cnt] |
+ data0[data_cnt + 1] << 8 |
+ data0[data_cnt + 2] << 16;
+ dev_dbg(dsim->dev, "count = 3 payload = %x, %x %x %x\n",
+ payload, data0[data_cnt],
+ data0[data_cnt + 1],
+ data0[data_cnt + 2]);
+ } else if ((data_size - data_cnt) = 2) {
+ payload = data0[data_cnt] |
+ data0[data_cnt + 1] << 8;
+ dev_dbg(dsim->dev,
+ "count = 2 payload = %x, %x %x\n", payload,
+ data0[data_cnt],
+ data0[data_cnt + 1]);
+ } else if ((data_size - data_cnt) = 1) {
+ payload = data0[data_cnt];
+ }
+
+ s5p_mipi_dsi_wr_tx_data(dsim, payload);
+ /* send 4bytes per one time. */
+ } else {
+ payload = data0[data_cnt] |
+ data0[data_cnt + 1] << 8 |
+ data0[data_cnt + 2] << 16 |
+ data0[data_cnt + 3] << 24;
+
+ dev_dbg(dsim->dev,
+ "count = 4 payload = %x, %x %x %x %x\n",
+ payload, *(u8 *)(data0 + data_cnt),
+ data0[data_cnt + 1],
+ data0[data_cnt + 2],
+ data0[data_cnt + 3]);
+
+ s5p_mipi_dsi_wr_tx_data(dsim, payload);
+ }
+ }
+}
+
+int s5p_mipi_dsi_wr_data(struct mipi_dsim_device *dsim, unsigned int data_id,
+ const unsigned char *data0, unsigned int data_size)
+{
+ unsigned int check_rx_ack = 0;
+
+ if (dsim->state = DSIM_STATE_ULPS) {
+ dev_err(dsim->dev, "state is ULPS.\n");
+
+ return -EINVAL;
+ }
+
+ /* FIXME!!! why does it need this delay? */
+ msleep(20);
+
+ mutex_lock(&dsim->lock);
+
+ switch (data_id) {
+ /* short packet types of packet types for command. */
+ case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM:
+ case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM:
+ case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM:
+ case MIPI_DSI_DCS_SHORT_WRITE:
+ case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
+ case MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE:
+ s5p_mipi_dsi_wr_tx_header(dsim, data_id, data0[0], data0[1]);
+ if (check_rx_ack) {
+ /* process response func should be implemented */
+ mutex_unlock(&dsim->lock);
+ return 0;
+ } else {
+ mutex_unlock(&dsim->lock);
+ return -EINVAL;
+ }
+
+ /* general command */
+ case MIPI_DSI_COLOR_MODE_OFF:
+ case MIPI_DSI_COLOR_MODE_ON:
+ case MIPI_DSI_SHUTDOWN_PERIPHERAL:
+ case MIPI_DSI_TURN_ON_PERIPHERAL:
+ s5p_mipi_dsi_wr_tx_header(dsim, data_id, data0[0], data0[1]);
+ if (check_rx_ack) {
+ /* process response func should be implemented. */
+ mutex_unlock(&dsim->lock);
+ return 0;
+ } else {
+ mutex_unlock(&dsim->lock);
+ return -EINVAL;
+ }
+
+ /* packet types for video data */
+ case MIPI_DSI_V_SYNC_START:
+ case MIPI_DSI_V_SYNC_END:
+ case MIPI_DSI_H_SYNC_START:
+ case MIPI_DSI_H_SYNC_END:
+ case MIPI_DSI_END_OF_TRANSMISSION:
+ mutex_unlock(&dsim->lock);
+ return 0;
+
+ /* long packet type and null packet */
+ case MIPI_DSI_NULL_PACKET:
+ case MIPI_DSI_BLANKING_PACKET:
+ mutex_unlock(&dsim->lock);
+ return 0;
+ case MIPI_DSI_GENERIC_LONG_WRITE:
+ case MIPI_DSI_DCS_LONG_WRITE:
+ {
+ unsigned int size, payload = 0;
+ INIT_COMPLETION(dsim_wr_comp);
+
+ size = data_size * 4;
+
+ /* if data count is less then 4, then send 3bytes data. */
+ if (data_size < 4) {
+ payload = data0[0] |
+ data0[1] << 8 |
+ data0[2] << 16;
+
+ s5p_mipi_dsi_wr_tx_data(dsim, payload);
+
+ dev_dbg(dsim->dev, "count = %d payload = %x,%x %x %x\n",
+ data_size, payload, data0[0],
+ data0[1], data0[2]);
+
+ /* in case that data count is more then 4 */
+ } else
+ s5p_mipi_dsi_long_data_wr(dsim, data0, data_size);
+
+ /* put data into header fifo */
+ s5p_mipi_dsi_wr_tx_header(dsim, data_id, data_size & 0xff,
+ (data_size & 0xff00) >> 8);
+
+ if (!wait_for_completion_interruptible_timeout(&dsim_wr_comp,
+ MIPI_FIFO_TIMEOUT)) {
+ dev_warn(dsim->dev, "command write timeout.\n");
+ mutex_unlock(&dsim->lock);
+ return -EAGAIN;
+ }
+
+ if (check_rx_ack) {
+ /* process response func should be implemented. */
+ mutex_unlock(&dsim->lock);
+ return 0;
+ } else {
+ mutex_unlock(&dsim->lock);
+ return -EINVAL;
+ }
+ }
+
+ /* packet typo for video data */
+ case MIPI_DSI_PACKED_PIXEL_STREAM_16:
+ case MIPI_DSI_PACKED_PIXEL_STREAM_18:
+ case MIPI_DSI_PIXEL_STREAM_3BYTE_18:
+ case MIPI_DSI_PACKED_PIXEL_STREAM_24:
+ if (check_rx_ack) {
+ /* process response func should be implemented. */
+ mutex_unlock(&dsim->lock);
+ return 0;
+ } else {
+ mutex_unlock(&dsim->lock);
+ return -EINVAL;
+ }
+ default:
+ dev_warn(dsim->dev,
+ "data id %x is not supported current DSI spec.\n",
+ data_id);
+
+ mutex_unlock(&dsim->lock);
+ return -EINVAL;
+ }
+
+ mutex_unlock(&dsim->lock);
+ return 0;
+}
+
+static unsigned int s5p_mipi_dsi_long_data_rd(struct mipi_dsim_device *dsim,
+ unsigned int req_size, unsigned int rx_data, u8 *rx_buf)
+{
+ unsigned int rcv_pkt, i, j;
+ u16 rxsize;
+
+ /* for long packet */
+ rxsize = (u16)((rx_data & 0x00ffff00) >> 8);
+ dev_dbg(dsim->dev, "mipi dsi rx size : %d\n", rxsize);
+ if (rxsize != req_size) {
+ dev_dbg(dsim->dev,
+ "received size mismatch received: %d, requested: %d\n",
+ rxsize, req_size);
+ goto err;
+ }
+
+ for (i = 0; i < (rxsize >> 2); i++) {
+ rcv_pkt = s5p_mipi_dsi_rd_rx_fifo(dsim);
+ dev_dbg(dsim->dev, "received pkt : %08x\n", rcv_pkt);
+ for (j = 0; j < 4; j++) {
+ rx_buf[(i * 4) + j] + (u8)(rcv_pkt >> (j * 8)) & 0xff;
+ dev_dbg(dsim->dev, "received value : %02x\n",
+ (rcv_pkt >> (j * 8)) & 0xff);
+ }
+ }
+ if (rxsize % 4) {
+ rcv_pkt = s5p_mipi_dsi_rd_rx_fifo(dsim);
+ dev_dbg(dsim->dev, "received pkt : %08x\n", rcv_pkt);
+ for (j = 0; j < (rxsize % 4); j++) {
+ rx_buf[(i * 4) + j] + (u8)(rcv_pkt >> (j * 8)) & 0xff;
+ dev_dbg(dsim->dev, "received value : %02x\n",
+ (rcv_pkt >> (j * 8)) & 0xff);
+ }
+ }
+
+ return rxsize;
+
+err:
+ return -EINVAL;
+}
+
+static unsigned int s5p_mipi_dsi_response_size(unsigned int req_size)
+{
+ switch (req_size) {
+ case 1:
+ return MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE;
+ case 2:
+ return MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE;
+ default:
+ return MIPI_DSI_RX_GENERIC_LONG_READ_RESPONSE;
+ }
+}
+
+int s5p_mipi_dsi_rd_data(struct mipi_dsim_device *dsim, unsigned int data_id,
+ unsigned int data0, unsigned int req_size, u8 *rx_buf)
+{
+ unsigned int rx_data, rcv_pkt, i;
+ u8 response = 0;
+ u16 rxsize;
+
+ if (dsim->state = DSIM_STATE_ULPS) {
+ dev_err(dsim->dev, "state is ULPS.\n");
+
+ return -EINVAL;
+ }
+
+ /* FIXME!!! */
+ msleep(20);
+
+ mutex_lock(&dsim->lock);
+ INIT_COMPLETION(dsim_rd_comp);
+ s5p_mipi_dsi_rd_tx_header(dsim,
+ MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE, req_size);
+
+ response = s5p_mipi_dsi_response_size(req_size);
+
+ switch (data_id) {
+ case MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM:
+ case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM:
+ case MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM:
+ case MIPI_DSI_DCS_READ:
+ s5p_mipi_dsi_rd_tx_header(dsim,
+ data_id, data0);
+ /* process response func should be implemented. */
+ break;
+ default:
+ dev_warn(dsim->dev,
+ "data id %x is not supported current DSI spec.\n",
+ data_id);
+
+ return -EINVAL;
+ }
+
+ if (!wait_for_completion_interruptible_timeout(&dsim_rd_comp,
+ MIPI_FIFO_TIMEOUT)) {
+ pr_err("RX done interrupt timeout\n");
+ mutex_unlock(&dsim->lock);
+ return 0;
+ }
+
+ msleep(20);
+
+ rx_data = s5p_mipi_dsi_rd_rx_fifo(dsim);
+
+ if ((u8)(rx_data & 0xff) != response) {
+ printk(KERN_ERR
+ "mipi dsi wrong response rx_data : %x, response:%x\n",
+ rx_data, response);
+ goto clear_rx_fifo;
+ }
+
+ if (req_size <= 2) {
+ /* for short packet */
+ for (i = 0; i < req_size; i++)
+ rx_buf[i] = (rx_data >> (8 + (i * 8))) & 0xff;
+ rxsize = req_size;
+ } else {
+ /* for long packet */
+ rxsize = s5p_mipi_dsi_long_data_rd(dsim, req_size, rx_data,
+ rx_buf);
+ if (rxsize != req_size)
+ goto clear_rx_fifo;
+ }
+
+ rcv_pkt = s5p_mipi_dsi_rd_rx_fifo(dsim);
+
+ msleep(20);
+
+ if (rcv_pkt != MIPI_RX_FIFO_READ_DONE) {
+ dev_info(dsim->dev,
+ "Can't found RX FIFO READ DONE FLAG : %x\n", rcv_pkt);
+ goto clear_rx_fifo;
+ }
+
+ mutex_unlock(&dsim->lock);
+
+ return rxsize;
+
+clear_rx_fifo:
+ i = 0;
+ while (1) {
+ rcv_pkt = s5p_mipi_dsi_rd_rx_fifo(dsim);
+ if ((rcv_pkt = MIPI_RX_FIFO_READ_DONE)
+ || (i > MIPI_MAX_RX_FIFO))
+ break;
+ dev_dbg(dsim->dev,
+ "mipi dsi clear rx fifo : %08x\n", rcv_pkt);
+ i++;
+ }
+ dev_info(dsim->dev,
+ "mipi dsi rx done count : %d, rcv_pkt : %08x\n", i, rcv_pkt);
+
+ mutex_unlock(&dsim->lock);
+
+ return 0;
+}
+
+static int s5p_mipi_dsi_pll_on(struct mipi_dsim_device *dsim,
+ unsigned int enable)
+{
+ int sw_timeout;
+
+ if (enable) {
+ sw_timeout = 1000;
+
+ s5p_mipi_dsi_enable_pll(dsim, 1);
+ while (1) {
+ sw_timeout--;
+ if (s5p_mipi_dsi_is_pll_stable(dsim))
+ return 0;
+ if (sw_timeout = 0)
+ return -EINVAL;
+ }
+ } else
+ s5p_mipi_dsi_enable_pll(dsim, 0);
+
+ return 0;
+}
+
+static unsigned long s5p_mipi_dsi_change_pll(struct mipi_dsim_device *dsim,
+ unsigned int pre_divider, unsigned int main_divider,
+ unsigned int scaler)
+{
+ unsigned long dfin_pll, dfvco, dpll_out;
+ unsigned int i, freq_band = 0xf;
+
+ dfin_pll = (FIN_HZ / pre_divider);
+
+ /******************************************************
+ * Serial Clock(=ByteClk X 8) FreqBand[3:0] *
+ ******************************************************
+ * ~ 99.99 MHz 0000
+ * 100 ~ 119.99 MHz 0001
+ * 120 ~ 159.99 MHz 0010
+ * 160 ~ 199.99 MHz 0011
+ * 200 ~ 239.99 MHz 0100
+ * 140 ~ 319.99 MHz 0101
+ * 320 ~ 389.99 MHz 0110
+ * 390 ~ 449.99 MHz 0111
+ * 450 ~ 509.99 MHz 1000
+ * 510 ~ 559.99 MHz 1001
+ * 560 ~ 639.99 MHz 1010
+ * 640 ~ 689.99 MHz 1011
+ * 690 ~ 769.99 MHz 1100
+ * 770 ~ 869.99 MHz 1101
+ * 870 ~ 949.99 MHz 1110
+ * 950 ~ 1000 MHz 1111
+ ******************************************************/
+ if (dfin_pll < DFIN_PLL_MIN_HZ || dfin_pll > DFIN_PLL_MAX_HZ) {
+ dev_warn(dsim->dev, "fin_pll range should be 6MHz ~ 12MHz\n");
+ s5p_mipi_dsi_enable_afc(dsim, 0, 0);
+ } else {
+ if (dfin_pll < 7 * MHZ)
+ s5p_mipi_dsi_enable_afc(dsim, 1, 0x1);
+ else if (dfin_pll < 8 * MHZ)
+ s5p_mipi_dsi_enable_afc(dsim, 1, 0x0);
+ else if (dfin_pll < 9 * MHZ)
+ s5p_mipi_dsi_enable_afc(dsim, 1, 0x3);
+ else if (dfin_pll < 10 * MHZ)
+ s5p_mipi_dsi_enable_afc(dsim, 1, 0x2);
+ else if (dfin_pll < 11 * MHZ)
+ s5p_mipi_dsi_enable_afc(dsim, 1, 0x5);
+ else
+ s5p_mipi_dsi_enable_afc(dsim, 1, 0x4);
+ }
+
+ dfvco = dfin_pll * main_divider;
+ dev_dbg(dsim->dev, "dfvco = %lu, dfin_pll = %lu, main_divider = %d\n",
+ dfvco, dfin_pll, main_divider);
+ if (dfvco < DFVCO_MIN_HZ || dfvco > DFVCO_MAX_HZ)
+ dev_warn(dsim->dev, "fvco range should be 500MHz ~ 1000MHz\n");
+
+ dpll_out = dfvco / (1 << scaler);
+ dev_dbg(dsim->dev, "dpll_out = %lu, dfvco = %lu, scaler = %d\n",
+ dpll_out, dfvco, scaler);
+
+ for (i = 0; i < ARRAY_SIZE(dpll_table); i++) {
+ if (dpll_out < dpll_table[i] * MHZ) {
+ freq_band = i;
+ break;
+ }
+ }
+
+ dev_dbg(dsim->dev, "freq_band = %d\n", freq_band);
+
+ s5p_mipi_dsi_pll_freq(dsim, pre_divider, main_divider, scaler);
+
+ s5p_mipi_dsi_hs_zero_ctrl(dsim, 0);
+ s5p_mipi_dsi_prep_ctrl(dsim, 0);
+
+ /* Freq Band */
+ s5p_mipi_dsi_pll_freq_band(dsim, freq_band);
+
+ /* Stable time */
+ s5p_mipi_dsi_pll_stable_time(dsim, dsim->dsim_config->pll_stable_time);
+
+ /* Enable PLL */
+ dev_dbg(dsim->dev, "FOUT of mipi dphy pll is %luMHz\n",
+ (dpll_out / MHZ));
+
+ return dpll_out;
+}
+
+static int s5p_mipi_dsi_set_clock(struct mipi_dsim_device *dsim,
+ unsigned int byte_clk_sel, unsigned int enable)
+{
+ unsigned int esc_div;
+ unsigned long esc_clk_error_rate;
+ unsigned long hs_clk = 0, byte_clk = 0, escape_clk = 0;
+
+ if (enable) {
+ dsim->e_clk_src = byte_clk_sel;
+
+ /* Escape mode clock and byte clock source */
+ s5p_mipi_dsi_set_byte_clock_src(dsim, byte_clk_sel);
+
+ /* DPHY, DSIM Link : D-PHY clock out */
+ if (byte_clk_sel = DSIM_PLL_OUT_DIV8) {
+ hs_clk = s5p_mipi_dsi_change_pll(dsim,
+ dsim->dsim_config->p, dsim->dsim_config->m,
+ dsim->dsim_config->s);
+ if (hs_clk = 0) {
+ dev_err(dsim->dev,
+ "failed to get hs clock.\n");
+ return -EINVAL;
+ }
+
+ byte_clk = hs_clk / 8;
+ s5p_mipi_dsi_enable_pll_bypass(dsim, 0);
+ s5p_mipi_dsi_pll_on(dsim, 1);
+ /* DPHY : D-PHY clock out, DSIM link : external clock out */
+ } else if (byte_clk_sel = DSIM_EXT_CLK_DIV8) {
+ dev_warn(dsim->dev, "this project is not support\n");
+ dev_warn(dsim->dev,
+ "external clock source for MIPI DSIM.\n");
+ } else if (byte_clk_sel = DSIM_EXT_CLK_BYPASS) {
+ dev_warn(dsim->dev, "this project is not support\n");
+ dev_warn(dsim->dev,
+ "external clock source for MIPI DSIM\n");
+ }
+
+ /* escape clock divider */
+ esc_div = byte_clk / (dsim->dsim_config->esc_clk);
+ dev_dbg(dsim->dev,
+ "esc_div = %d, byte_clk = %lu, esc_clk = %lu\n",
+ esc_div, byte_clk, dsim->dsim_config->esc_clk);
+ if ((byte_clk / esc_div) >= (20 * MHZ) ||
+ (byte_clk / esc_div) >
+ dsim->dsim_config->esc_clk)
+ esc_div += 1;
+
+ escape_clk = byte_clk / esc_div;
+ dev_dbg(dsim->dev,
+ "escape_clk = %lu, byte_clk = %lu, esc_div = %d\n",
+ escape_clk, byte_clk, esc_div);
+
+ /* enable escape clock. */
+ s5p_mipi_dsi_enable_byte_clock(dsim, 1);
+
+ /* enable byte clk and escape clock */
+ s5p_mipi_dsi_set_esc_clk_prs(dsim, 1, esc_div);
+ /* escape clock on lane */
+ s5p_mipi_dsi_enable_esc_clk_on_lane(dsim,
+ (DSIM_LANE_CLOCK | dsim->data_lane), 1);
+
+ dev_dbg(dsim->dev, "byte clock is %luMHz\n",
+ (byte_clk / MHZ));
+ dev_dbg(dsim->dev, "escape clock that user's need is %lu\n",
+ (dsim->dsim_config->esc_clk / MHZ));
+ dev_dbg(dsim->dev, "escape clock divider is %x\n", esc_div);
+ dev_dbg(dsim->dev, "escape clock is %luMHz\n",
+ ((byte_clk / esc_div) / MHZ));
+
+ if ((byte_clk / esc_div) > escape_clk) {
+ esc_clk_error_rate = escape_clk /
+ (byte_clk / esc_div);
+ dev_warn(dsim->dev, "error rate is %lu over.\n",
+ (esc_clk_error_rate / 100));
+ } else if ((byte_clk / esc_div) < (escape_clk)) {
+ esc_clk_error_rate = (byte_clk / esc_div) /
+ escape_clk;
+ dev_warn(dsim->dev, "error rate is %lu under.\n",
+ (esc_clk_error_rate / 100));
+ }
+ } else {
+ s5p_mipi_dsi_enable_esc_clk_on_lane(dsim,
+ (DSIM_LANE_CLOCK | dsim->data_lane), 0);
+ s5p_mipi_dsi_set_esc_clk_prs(dsim, 0, 0);
+
+ /* disable escape clock. */
+ s5p_mipi_dsi_enable_byte_clock(dsim, 0);
+
+ if (byte_clk_sel = DSIM_PLL_OUT_DIV8)
+ s5p_mipi_dsi_pll_on(dsim, 0);
+ }
+
+ return 0;
+}
+
+int s5p_mipi_dsi_init_dsim(struct mipi_dsim_device *dsim)
+{
+ dsim->state = DSIM_STATE_INIT;
+
+ switch (dsim->dsim_config->e_no_data_lane) {
+ case DSIM_DATA_LANE_1:
+ dsim->data_lane = DSIM_LANE_DATA0;
+ break;
+ case DSIM_DATA_LANE_2:
+ dsim->data_lane = DSIM_LANE_DATA0 | DSIM_LANE_DATA1;
+ break;
+ case DSIM_DATA_LANE_3:
+ dsim->data_lane = DSIM_LANE_DATA0 | DSIM_LANE_DATA1 |
+ DSIM_LANE_DATA2;
+ break;
+ case DSIM_DATA_LANE_4:
+ dsim->data_lane = DSIM_LANE_DATA0 | DSIM_LANE_DATA1 |
+ DSIM_LANE_DATA2 | DSIM_LANE_DATA3;
+ break;
+ default:
+ dev_info(dsim->dev, "data lane is invalid.\n");
+ return -EINVAL;
+ };
+
+ s5p_mipi_dsi_sw_reset(dsim);
+ s5p_mipi_dsi_func_reset(dsim);
+
+ s5p_mipi_dsi_dp_dn_swap(dsim, 0);
+
+ return 0;
+}
+
+void s5p_mipi_dsi_init_interrupt(struct mipi_dsim_device *dsim)
+{
+ unsigned int src = 0;
+
+ src = (INTSRC_SFR_FIFO_EMPTY | INTSRC_RX_DATA_DONE);
+ s5p_mipi_dsi_set_interrupt(dsim, src, 1);
+
+ src = 0;
+ src = ~(INTMSK_RX_DONE | INTMSK_FIFO_EMPTY);
+ s5p_mipi_dsi_set_interrupt_mask(dsim, src, 1);
+}
+
+int s5p_mipi_dsi_enable_frame_done_int(struct mipi_dsim_device *dsim,
+ unsigned int enable)
+{
+ /* enable only frame done interrupt */
+ s5p_mipi_dsi_set_interrupt_mask(dsim, INTMSK_FRAME_DONE, enable);
+
+ return 0;
+}
+
+void s5p_mipi_dsi_stand_by(struct mipi_dsim_device *dsim,
+ unsigned int enable)
+{
+
+ /* consider Main display and Sub display. */
+
+ s5p_mipi_dsi_set_main_stand_by(dsim, enable);
+}
+
+int s5p_mipi_dsi_set_display_mode(struct mipi_dsim_device *dsim,
+ struct mipi_dsim_config *dsim_config)
+{
+ struct mipi_dsim_platform_data *dsim_pd;
+ struct fb_videomode *timing;
+
+ dsim_pd = (struct mipi_dsim_platform_data *)dsim->pd;
+ timing = (struct fb_videomode *)dsim_pd->lcd_panel_info;
+
+ /* in case of VIDEO MODE (RGB INTERFACE), it sets polarities. */
+ if (dsim_config->e_interface = (u32) DSIM_VIDEO) {
+ if (dsim_config->auto_vertical_cnt = 0) {
+ s5p_mipi_dsi_set_main_disp_vporch(dsim,
+ dsim_config->cmd_allow,
+ timing->upper_margin,
+ timing->lower_margin);
+ s5p_mipi_dsi_set_main_disp_hporch(dsim,
+ timing->left_margin,
+ timing->right_margin);
+ s5p_mipi_dsi_set_main_disp_sync_area(dsim,
+ timing->vsync_len,
+ timing->hsync_len);
+ }
+ }
+
+ s5p_mipi_dsi_set_main_disp_resol(dsim, timing->xres,
+ timing->yres);
+
+ s5p_mipi_dsi_display_config(dsim, dsim_config);
+
+ dev_info(dsim->dev, "lcd panel => width = %d, height = %d\n",
+ timing->xres, timing->yres);
+
+ return 0;
+}
+
+int s5p_mipi_dsi_init_link(struct mipi_dsim_device *dsim)
+{
+ unsigned int time_out = 100;
+
+ switch (dsim->state) {
+ case DSIM_STATE_INIT:
+ s5p_mipi_dsi_init_fifo_pointer(dsim, 0x1f);
+
+ /* dsi configuration */
+ s5p_mipi_dsi_init_config(dsim);
+ s5p_mipi_dsi_enable_lane(dsim, DSIM_LANE_CLOCK, 1);
+ s5p_mipi_dsi_enable_lane(dsim, dsim->data_lane, 1);
+
+ /* set clock configuration */
+ s5p_mipi_dsi_set_clock(dsim, dsim->dsim_config->e_byte_clk, 1);
+
+ /* check clock and data lane state are stop state */
+ while (!(s5p_mipi_dsi_is_lane_state(dsim))) {
+ time_out--;
+ if (time_out = 0) {
+ dev_err(dsim->dev,
+ "DSI Master is not stop state.\n");
+ dev_err(dsim->dev,
+ "Check initialization process\n");
+
+ return -EINVAL;
+ }
+ }
+ if (time_out != 0) {
+ dev_info(dsim->dev,
+ "DSI Master driver has been completed.\n");
+ dev_info(dsim->dev, "DSI Master state is stop state\n");
+ }
+
+ dsim->state = DSIM_STATE_STOP;
+
+ /* BTA sequence counters */
+ s5p_mipi_dsi_set_stop_state_counter(dsim,
+ dsim->dsim_config->stop_holding_cnt);
+ s5p_mipi_dsi_set_bta_timeout(dsim,
+ dsim->dsim_config->bta_timeout);
+ s5p_mipi_dsi_set_lpdr_timeout(dsim,
+ dsim->dsim_config->rx_timeout);
+
+ return 0;
+ default:
+ dev_info(dsim->dev, "DSI Master is already init.\n");
+ return 0;
+ }
+
+ return 0;
+}
+
+int s5p_mipi_dsi_set_hs_enable(struct mipi_dsim_device *dsim)
+{
+ if (dsim->state != DSIM_STATE_STOP) {
+ dev_warn(dsim->dev, "DSIM is not in stop state.\n");
+ return 0;
+ }
+
+ if (dsim->e_clk_src = DSIM_EXT_CLK_BYPASS) {
+ dev_warn(dsim->dev, "clock source is external bypass.\n");
+ return 0;
+ }
+
+ 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;
+}
+
+int s5p_mipi_dsi_set_data_transfer_mode(struct mipi_dsim_device *dsim,
+ unsigned int mode)
+{
+ if (mode) {
+ if (dsim->state != DSIM_STATE_HSCLKEN) {
+ dev_err(dsim->dev, "HS Clock lane is not enabled.\n");
+ return -EINVAL;
+ }
+
+ s5p_mipi_dsi_set_lcdc_transfer_mode(dsim, 0);
+ } else {
+ if (dsim->state = DSIM_STATE_INIT || dsim->state =
+ DSIM_STATE_ULPS) {
+ dev_err(dsim->dev,
+ "DSI Master is not STOP or HSDT state.\n");
+ return -EINVAL;
+ }
+
+ s5p_mipi_dsi_set_cpu_transfer_mode(dsim, 0);
+ }
+
+ return 0;
+}
+
+int s5p_mipi_dsi_get_frame_done_status(struct mipi_dsim_device *dsim)
+{
+ return _s5p_mipi_dsi_get_frame_done_status(dsim);
+}
+
+int s5p_mipi_dsi_clear_frame_done(struct mipi_dsim_device *dsim)
+{
+ _s5p_mipi_dsi_clear_frame_done(dsim);
+
+ return 0;
+}
+
+int s5p_mipi_dsi_fifo_clear(struct mipi_dsim_device *dsim,
+ unsigned int val)
+{
+ int try = TRY_FIFO_CLEAR;
+
+ s5p_mipi_dsi_sw_reset_release(dsim);
+ s5p_mipi_dsi_func_reset(dsim);
+
+ do {
+ if (s5p_mipi_dsi_get_sw_reset_release(dsim)) {
+ s5p_mipi_dsi_init_interrupt(dsim);
+ dev_dbg(dsim->dev, "reset release done.\n");
+ return 0;
+ }
+ } while (--try);
+
+ dev_err(dsim->dev, "failed to clear dsim fifo.\n");
+ return -EAGAIN;
+}
+
+MODULE_AUTHOR("InKi Dae <inki.dae@samsung.com>");
+MODULE_DESCRIPTION("Samusung SoC MIPI-DSI common driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/s5p_mipi_dsi_common.h b/drivers/video/s5p_mipi_dsi_common.h
new file mode 100644
index 0000000..475a399
--- /dev/null
+++ b/drivers/video/s5p_mipi_dsi_common.h
@@ -0,0 +1,46 @@
+/* linux/drivers/video/s5p_mipi_dsi_common.h
+ *
+ * Header file for Samsung SoC MIPI-DSI common driver.
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * InKi Dae <inki.dae@samsung.com>
+ * Donghwa Lee <dh09.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef _S5P_MIPI_DSI_COMMON_H
+#define _S5P_MIPI_DSI_COMMON_H
+
+static DECLARE_COMPLETION(dsim_rd_comp);
+static DECLARE_COMPLETION(dsim_wr_comp);
+
+int s5p_mipi_dsi_wr_data(struct mipi_dsim_device *dsim, unsigned int data_id,
+ const unsigned char *data0, unsigned int data_size);
+int s5p_mipi_dsi_rd_data(struct mipi_dsim_device *dsim, unsigned int data_id,
+ unsigned int data0, unsigned int req_size, u8 *rx_buf);
+irqreturn_t s5p_mipi_dsi_interrupt_handler(int irq, void *dev_id);
+void s5p_mipi_dsi_init_interrupt(struct mipi_dsim_device *dsim);
+int s5p_mipi_dsi_init_dsim(struct mipi_dsim_device *dsim);
+void s5p_mipi_dsi_stand_by(struct mipi_dsim_device *dsim,
+ unsigned int enable);
+int s5p_mipi_dsi_set_display_mode(struct mipi_dsim_device *dsim,
+ struct mipi_dsim_config *dsim_info);
+int s5p_mipi_dsi_init_link(struct mipi_dsim_device *dsim);
+int s5p_mipi_dsi_set_hs_enable(struct mipi_dsim_device *dsim);
+int s5p_mipi_dsi_set_data_transfer_mode(struct mipi_dsim_device *dsim,
+ unsigned int mode);
+int s5p_mipi_dsi_enable_frame_done_int(struct mipi_dsim_device *dsim,
+ unsigned int enable);
+int s5p_mipi_dsi_get_frame_done_status(struct mipi_dsim_device *dsim);
+int s5p_mipi_dsi_clear_frame_done(struct mipi_dsim_device *dsim);
+
+extern struct fb_info *registered_fb[FB_MAX] __read_mostly;
+
+int s5p_mipi_dsi_fifo_clear(struct mipi_dsim_device *dsim,
+ unsigned int val);
+
+#endif /* _S5P_MIPI_DSI_COMMON_H */
diff --git a/drivers/video/s5p_mipi_dsi_lowlevel.c b/drivers/video/s5p_mipi_dsi_lowlevel.c
new file mode 100644
index 0000000..a4a21d0
--- /dev/null
+++ b/drivers/video/s5p_mipi_dsi_lowlevel.c
@@ -0,0 +1,617 @@
+/* linux/drivers/video/s5p_mipi_dsi_lowlevel.c
+ *
+ * Samsung SoC MIPI-DSI lowlevel driver.
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * InKi Dae, <inki.dae@samsung.com>
+ * Donghwa Lee, <dh09.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/ctype.h>
+#include <linux/io.h>
+#include <linux/mipi_dsim.h>
+
+#include <mach/map.h>
+
+#include "s5p_mipi_dsi_regs.h"
+
+void s5p_mipi_dsi_func_reset(struct mipi_dsim_device *dsim)
+{
+ unsigned int reg;
+
+ reg = readl(dsim->reg_base + S5P_DSIM_SWRST);
+
+ reg |= DSIM_FUNCRST;
+
+ writel(reg, dsim->reg_base + S5P_DSIM_SWRST);
+}
+
+void s5p_mipi_dsi_sw_reset(struct mipi_dsim_device *dsim)
+{
+ unsigned int reg;
+
+ reg = readl(dsim->reg_base + S5P_DSIM_SWRST);
+
+ reg |= DSIM_SWRST;
+
+ writel(reg, dsim->reg_base + S5P_DSIM_SWRST);
+}
+
+void s5p_mipi_dsi_sw_reset_release(struct mipi_dsim_device *dsim)
+{
+ unsigned int reg;
+
+ reg = readl(dsim->reg_base + S5P_DSIM_INTSRC);
+
+ reg |= INTSRC_SW_RST_RELEASE;
+
+ writel(reg, dsim->reg_base + S5P_DSIM_INTSRC);
+}
+
+int s5p_mipi_dsi_get_sw_reset_release(struct mipi_dsim_device *dsim)
+{
+ return (readl(dsim->reg_base + S5P_DSIM_INTSRC)) &
+ INTSRC_SW_RST_RELEASE;
+}
+
+unsigned int s5p_mipi_dsi_read_interrupt_mask(struct mipi_dsim_device *dsim)
+{
+ unsigned int reg;
+
+ reg = readl(dsim->reg_base + S5P_DSIM_INTMSK);
+
+ return reg;
+}
+
+void s5p_mipi_dsi_set_interrupt_mask(struct mipi_dsim_device *dsim,
+ unsigned int mode, unsigned int mask)
+{
+ unsigned int reg = 0;
+
+ if (mask)
+ reg |= mode;
+ else
+ reg &= ~mode;
+
+ writel(reg, dsim->reg_base + S5P_DSIM_INTMSK);
+}
+
+void s5p_mipi_dsi_init_fifo_pointer(struct mipi_dsim_device *dsim,
+ unsigned int cfg)
+{
+ unsigned int reg;
+
+ reg = readl(dsim->reg_base + S5P_DSIM_FIFOCTRL);
+
+ writel(reg & ~(cfg), dsim->reg_base + S5P_DSIM_FIFOCTRL);
+ mdelay(10);
+ reg |= cfg;
+
+ writel(reg, dsim->reg_base + S5P_DSIM_FIFOCTRL);
+}
+
+/*
+ * this function set PLL P, M and S value in D-PHY
+ */
+void s5p_mipi_dsi_set_phy_tunning(struct mipi_dsim_device *dsim,
+ unsigned int value)
+{
+ writel(DSIM_AFC_CTL(value), dsim->reg_base + S5P_DSIM_PHYACCHR);
+}
+
+void s5p_mipi_dsi_set_main_stand_by(struct mipi_dsim_device *dsim,
+ unsigned int enable)
+{
+ unsigned int reg;
+
+ reg = readl(dsim->reg_base + S5P_DSIM_MDRESOL);
+
+ reg &= ~DSIM_MAIN_STAND_BY;
+
+ if (enable)
+ reg |= DSIM_MAIN_STAND_BY;
+
+ writel(reg, dsim->reg_base + S5P_DSIM_MDRESOL);
+}
+
+void s5p_mipi_dsi_set_main_disp_resol(struct mipi_dsim_device *dsim,
+ unsigned int width_resol, unsigned int height_resol)
+{
+ unsigned int reg;
+
+ /* standby should be set after configuration so set to not ready*/
+ reg = (readl(dsim->reg_base + S5P_DSIM_MDRESOL)) &
+ ~(DSIM_MAIN_STAND_BY);
+ writel(reg, dsim->reg_base + S5P_DSIM_MDRESOL);
+
+ reg &= ~((0x7ff << 16) | (0x7ff << 0));
+ reg |= DSIM_MAIN_VRESOL(height_resol) | DSIM_MAIN_HRESOL(width_resol);
+
+ reg |= DSIM_MAIN_STAND_BY;
+ writel(reg, dsim->reg_base + S5P_DSIM_MDRESOL);
+}
+
+void s5p_mipi_dsi_set_main_disp_vporch(struct mipi_dsim_device *dsim,
+ unsigned int cmd_allow, unsigned int vfront, unsigned int vback)
+{
+ unsigned int reg;
+
+ reg = (readl(dsim->reg_base + S5P_DSIM_MVPORCH)) &
+ ~((DSIM_CMD_ALLOW_MASK) | (DSIM_STABLE_VFP_MASK) |
+ (DSIM_MAIN_VBP_MASK));
+
+ reg |= (DSIM_CMD_ALLOW_SHIFT(cmd_allow & 0xf) |
+ DSIM_STABLE_VFP_SHIFT(vfront & 0x7ff) |
+ DSIM_MAIN_VBP_SHIFT(vback & 0x7ff));
+
+ 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 |= DSIM_MAIN_HFP_SHIFT(front) | DSIM_MAIN_HBP_SHIFT(back);
+
+ 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 |= (DSIM_MAIN_VSA_SHIFT(vert & 0x3ff) |
+ DSIM_MAIN_HSA_SHIFT(hori));
+
+ 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 |= (DSIM_SUB_VRESOL_SHIFT(vert & 0x7ff) |
+ DSIM_SUB_HRESOL_SHIFT(hori & 0x7ff));
+ writel(reg, dsim->reg_base + S5P_DSIM_SDRESOL);
+
+ reg |= DSIM_SUB_STANDY_SHIFT(1);
+ 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_AUTO_FLUSH(dsim_config->auto_flush)) |
+ (DSIM_EOT_DISABLE(dsim_config->eot_disable)) |
+ (DSIM_AUTO_MODE_SHIFT(dsim_config->auto_vertical_cnt)) |
+ (DSIM_HSE_MODE_SHIFT(dsim_config->hse)) |
+ (DSIM_HFP_MODE_SHIFT(dsim_config->hfp)) |
+ (DSIM_HBP_MODE_SHIFT(dsim_config->hbp)) |
+ (DSIM_HSA_MODE_SHIFT(dsim_config->hsa)) |
+ (DSIM_NUM_OF_DATALANE_SHIFT(dsim_config->e_no_data_lane)));
+
+ writel(cfg, dsim->reg_base + S5P_DSIM_CONFIG);
+}
+
+void s5p_mipi_dsi_display_config(struct mipi_dsim_device *dsim,
+ struct mipi_dsim_config *dsim_config)
+{
+ u32 reg = (readl(dsim->reg_base + S5P_DSIM_CONFIG)) &
+ ~((0x3 << 26) | (1 << 25) | (0x3 << 18) | (0x7 << 12) |
+ (0x3 << 16) | (0x7 << 8));
+
+ if (dsim_config->e_interface = DSIM_VIDEO)
+ reg |= (1 << 25);
+ else if (dsim_config->e_interface = DSIM_COMMAND)
+ reg &= ~(1 << 25);
+ else {
+ dev_err(dsim->dev, "unknown lcd type.\n");
+ return;
+ }
+
+ /* main lcd */
+ reg |= ((u8) (dsim_config->e_burst_mode) & 0x3) << 26 |
+ ((u8) (dsim_config->e_virtual_ch) & 0x3) << 18 |
+ ((u8) (dsim_config->e_pixel_format) & 0x7) << 12;
+
+ writel(reg, dsim->reg_base + S5P_DSIM_CONFIG);
+}
+
+void s5p_mipi_dsi_enable_lane(struct mipi_dsim_device *dsim, unsigned int lane,
+ unsigned int enable)
+{
+ unsigned int reg;
+
+ reg = readl(dsim->reg_base + S5P_DSIM_CONFIG);
+
+ if (enable)
+ reg |= DSIM_LANE_ENx(lane);
+ else
+ reg &= ~DSIM_LANE_ENx(lane);
+
+ writel(reg, dsim->reg_base + S5P_DSIM_CONFIG);
+}
+
+
+void s5p_mipi_dsi_set_data_lane_number(struct mipi_dsim_device *dsim,
+ unsigned int count)
+{
+ unsigned int cfg;
+
+ /* get the data lane number. */
+ cfg = DSIM_NUM_OF_DATALANE_SHIFT(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_SHIFT(0x1));
+
+ reg |= DSIM_PLL_BYPASS_SHIFT(enable);
+
+ 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)) &
+ ~(DSIM_FREQ_BAND_SHIFT(0x1f));
+
+ reg |= DSIM_FREQ_BAND_SHIFT(freq_band & 0x1f);
+
+ 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)) &
+ ~(DSIM_PLL_EN_SHIFT(0x1));
+
+ reg |= DSIM_PLL_EN_SHIFT(enable & 0x1);
+
+ 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)) &
+ ~(DSIM_BYTE_CLK_SRC_SHIFT(0x3));
+
+ reg |= (DSIM_BYTE_CLK_SRC_SHIFT(src));
+
+ 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)) &
+ ~(DSIM_BYTE_CLKEN_SHIFT(0x1));
+
+ reg |= DSIM_BYTE_CLKEN_SHIFT(enable);
+
+ 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)) &
+ ~(DSIM_ESC_CLKEN_SHIFT(0x1) | 0xffff);
+
+ reg |= DSIM_ESC_CLKEN_SHIFT(enable);
+ 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)) &
+ ~(DSIM_FORCE_STOP_STATE_SHIFT(0x1));
+
+ reg |= (DSIM_FORCE_STOP_STATE_SHIFT(enable & 0x1));
+
+ 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;
+
+ 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)) &
+ ~(DSIM_STOP_STATE_CNT_SHIFT(0x7ff));
+
+ reg |= (DSIM_STOP_STATE_CNT_SHIFT(cnt_val & 0x7ff));
+
+ 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)) &
+ ~(DSIM_BTA_TOUT_SHIFT(0xff));
+
+ reg |= (DSIM_BTA_TOUT_SHIFT(timeout));
+
+ 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)) &
+ ~(DSIM_LPDR_TOUT_SHIFT(0xffff));
+
+ reg |= (DSIM_LPDR_TOUT_SHIFT(timeout));
+
+ writel(reg, dsim->reg_base + S5P_DSIM_TIMEOUT);
+}
+
+void s5p_mipi_dsi_set_cpu_transfer_mode(struct mipi_dsim_device *dsim,
+ unsigned int lp)
+{
+ unsigned int reg = readl(dsim->reg_base + S5P_DSIM_ESCMODE);
+
+ reg &= ~DSIM_CMD_LPDT_LP;
+
+ if (lp)
+ reg |= DSIM_CMD_LPDT_LP;
+
+ writel(reg, dsim->reg_base + S5P_DSIM_ESCMODE);
+}
+
+void s5p_mipi_dsi_set_lcdc_transfer_mode(struct mipi_dsim_device *dsim,
+ unsigned int lp)
+{
+ unsigned int reg = readl(dsim->reg_base + S5P_DSIM_ESCMODE);
+
+ reg &= ~DSIM_TX_LPDT_LP;
+
+ if (lp)
+ reg |= DSIM_TX_LPDT_LP;
+
+ writel(reg, dsim->reg_base + S5P_DSIM_ESCMODE);
+}
+
+void s5p_mipi_dsi_enable_hs_clock(struct mipi_dsim_device *dsim,
+ unsigned int enable)
+{
+ unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_CLKCTRL)) &
+ ~(DSIM_TX_REQUEST_HSCLK_SHIFT(0x1));
+
+ reg |= DSIM_TX_REQUEST_HSCLK_SHIFT(enable);
+
+ writel(reg, dsim->reg_base + S5P_DSIM_CLKCTRL);
+}
+
+void s5p_mipi_dsi_dp_dn_swap(struct mipi_dsim_device *dsim,
+ unsigned int swap_en)
+{
+ unsigned int reg = readl(dsim->reg_base + S5P_DSIM_PHYACCHR1);
+
+ reg &= ~(0x3 << 0);
+ reg |= (swap_en & 0x3) << 0;
+
+ writel(reg, dsim->reg_base + S5P_DSIM_PHYACCHR1);
+}
+
+void s5p_mipi_dsi_hs_zero_ctrl(struct mipi_dsim_device *dsim,
+ unsigned int hs_zero)
+{
+ unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_PLLCTRL)) &
+ ~(0xf << 28);
+
+ reg |= ((hs_zero & 0xf) << 28);
+
+ writel(reg, dsim->reg_base + S5P_DSIM_PLLCTRL);
+}
+
+void s5p_mipi_dsi_prep_ctrl(struct mipi_dsim_device *dsim, unsigned int prep)
+{
+ unsigned int reg = (readl(dsim->reg_base + S5P_DSIM_PLLCTRL)) &
+ ~(0x7 << 20);
+
+ reg |= ((prep & 0x7) << 20);
+
+ writel(reg, dsim->reg_base + S5P_DSIM_PLLCTRL);
+}
+
+unsigned int s5p_mipi_dsi_read_interrupt(struct mipi_dsim_device *dsim)
+{
+ return readl(dsim->reg_base + S5P_DSIM_INTSRC);
+}
+
+void s5p_mipi_dsi_clear_interrupt(struct mipi_dsim_device *dsim,
+ unsigned int src)
+{
+ unsigned int reg = readl(dsim->reg_base + S5P_DSIM_INTSRC);
+
+ reg |= src;
+
+ writel(reg, dsim->reg_base + S5P_DSIM_INTSRC);
+}
+
+void s5p_mipi_dsi_set_interrupt(struct mipi_dsim_device *dsim,
+ unsigned int src, unsigned int enable)
+{
+ unsigned int reg = 0;
+
+ if (enable)
+ reg |= src;
+ else
+ reg &= ~src;
+
+ writel(reg, dsim->reg_base + S5P_DSIM_INTSRC);
+}
+
+unsigned int s5p_mipi_dsi_is_pll_stable(struct mipi_dsim_device *dsim)
+{
+ unsigned int reg;
+
+ reg = readl(dsim->reg_base + S5P_DSIM_STATUS);
+
+ return reg & (1 << 31) ? 1 : 0;
+}
+
+unsigned int s5p_mipi_dsi_get_fifo_state(struct mipi_dsim_device *dsim)
+{
+ return readl(dsim->reg_base + S5P_DSIM_FIFOCTRL) & ~(0x1f);
+}
+
+void s5p_mipi_dsi_wr_tx_header(struct mipi_dsim_device *dsim,
+ unsigned int di, unsigned int data0, unsigned int data1)
+{
+ unsigned int reg = (data1 << 16) | (data0 << 8) | ((di & 0x3f) << 0);
+
+ writel(reg, dsim->reg_base + S5P_DSIM_PKTHDR);
+}
+
+void s5p_mipi_dsi_rd_tx_header(struct mipi_dsim_device *dsim,
+ unsigned int di, unsigned int data0)
+{
+ unsigned int reg = (data0 << 8) | (di << 0);
+
+ writel(reg, dsim->reg_base + S5P_DSIM_PKTHDR);
+}
+
+unsigned int s5p_mipi_dsi_rd_rx_fifo(struct mipi_dsim_device *dsim)
+{
+ return readl(dsim->reg_base + S5P_DSIM_RXFIFO);
+}
+
+unsigned int _s5p_mipi_dsi_get_frame_done_status(struct mipi_dsim_device *dsim)
+{
+ unsigned int reg = readl(dsim->reg_base + S5P_DSIM_INTSRC);
+
+ return (reg & INTSRC_FRAME_DONE) ? 1 : 0;
+}
+
+void _s5p_mipi_dsi_clear_frame_done(struct mipi_dsim_device *dsim)
+{
+ unsigned int reg = readl(dsim->reg_base + S5P_DSIM_INTSRC);
+
+ writel(reg | INTSRC_FRAME_DONE, dsim->reg_base +
+ S5P_DSIM_INTSRC);
+}
+
+void s5p_mipi_dsi_wr_tx_data(struct mipi_dsim_device *dsim,
+ unsigned int tx_data)
+{
+ writel(tx_data, dsim->reg_base + S5P_DSIM_PAYLOAD);
+}
diff --git a/drivers/video/s5p_mipi_dsi_lowlevel.h b/drivers/video/s5p_mipi_dsi_lowlevel.h
new file mode 100644
index 0000000..da3a63e
--- /dev/null
+++ b/drivers/video/s5p_mipi_dsi_lowlevel.h
@@ -0,0 +1,112 @@
+/* linux/drivers/video/s5p_mipi_dsi_lowlevel.h
+ *
+ * Header file for Samsung SoC MIPI-DSI lowlevel driver.
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * InKi Dae <inki.dae@samsung.com>
+ * Donghwa Lee <dh09.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef _S5P_MIPI_DSI_LOWLEVEL_H
+#define _S5P_MIPI_DSI_LOWLEVEL_H
+
+void s5p_mipi_dsi_func_reset(struct mipi_dsim_device *dsim);
+void s5p_mipi_dsi_sw_reset(struct mipi_dsim_device *dsim);
+void s5p_mipi_dsi_sw_reset_release(struct mipi_dsim_device *dsim);
+int s5p_mipi_dsi_get_sw_reset_release(struct mipi_dsim_device *dsim);
+void s5p_mipi_dsi_set_interrupt_mask(struct mipi_dsim_device *dsim,
+ unsigned int mode, unsigned int mask);
+void s5p_mipi_dsi_set_data_lane_number(struct mipi_dsim_device *dsim,
+ unsigned int count);
+void s5p_mipi_dsi_init_fifo_pointer(struct mipi_dsim_device *dsim,
+ unsigned int cfg);
+void s5p_mipi_dsi_set_phy_tunning(struct mipi_dsim_device *dsim,
+ unsigned int value);
+void s5p_mipi_dsi_set_phy_tunning(struct mipi_dsim_device *dsim,
+ unsigned int value);
+void s5p_mipi_dsi_set_main_stand_by(struct mipi_dsim_device *dsim,
+ unsigned int enable);
+void s5p_mipi_dsi_set_main_disp_resol(struct mipi_dsim_device *dsim,
+ unsigned int width_resol, unsigned int height_resol);
+void s5p_mipi_dsi_set_main_disp_vporch(struct mipi_dsim_device *dsim,
+ unsigned int cmd_allow, unsigned int vfront, unsigned int vback);
+void s5p_mipi_dsi_set_main_disp_hporch(struct mipi_dsim_device *dsim,
+ unsigned int front, unsigned int back);
+void s5p_mipi_dsi_set_main_disp_sync_area(struct mipi_dsim_device *dsim,
+ unsigned int vert, unsigned int hori);
+void s5p_mipi_dsi_set_sub_disp_resol(struct mipi_dsim_device *dsim,
+ unsigned int vert, unsigned int hori);
+void s5p_mipi_dsi_init_config(struct mipi_dsim_device *dsim);
+void s5p_mipi_dsi_display_config(struct mipi_dsim_device *dsim,
+ struct mipi_dsim_config *dsim_config);
+void s5p_mipi_dsi_set_data_lane_number(struct mipi_dsim_device *dsim,
+ unsigned int count);
+void s5p_mipi_dsi_enable_lane(struct mipi_dsim_device *dsim, unsigned int lane,
+ unsigned int enable);
+void s5p_mipi_dsi_enable_afc(struct mipi_dsim_device *dsim, unsigned int enable,
+ unsigned int afc_code);
+void s5p_mipi_dsi_enable_pll_bypass(struct mipi_dsim_device *dsim,
+ unsigned int enable);
+void s5p_mipi_dsi_set_pll_pms(struct mipi_dsim_device *dsim, unsigned int p,
+ unsigned int m, unsigned int s);
+void s5p_mipi_dsi_pll_freq_band(struct mipi_dsim_device *dsim,
+ unsigned int freq_band);
+void s5p_mipi_dsi_pll_freq(struct mipi_dsim_device *dsim,
+ unsigned int pre_divider, unsigned int main_divider,
+ unsigned int scaler);
+void s5p_mipi_dsi_pll_stable_time(struct mipi_dsim_device *dsim,
+ unsigned int lock_time);
+void s5p_mipi_dsi_enable_pll(struct mipi_dsim_device *dsim,
+ unsigned int enable);
+void s5p_mipi_dsi_set_byte_clock_src(struct mipi_dsim_device *dsim,
+ unsigned int src);
+void s5p_mipi_dsi_enable_byte_clock(struct mipi_dsim_device *dsim,
+ unsigned int enable);
+void s5p_mipi_dsi_set_esc_clk_prs(struct mipi_dsim_device *dsim,
+ unsigned int enable, unsigned int prs_val);
+void s5p_mipi_dsi_enable_esc_clk_on_lane(struct mipi_dsim_device *dsim,
+ unsigned int lane_sel, unsigned int enable);
+void s5p_mipi_dsi_force_dphy_stop_state(struct mipi_dsim_device *dsim,
+ unsigned int enable);
+unsigned int s5p_mipi_dsi_is_lane_state(struct mipi_dsim_device *dsim);
+void s5p_mipi_dsi_set_stop_state_counter(struct mipi_dsim_device *dsim,
+ unsigned int cnt_val);
+void s5p_mipi_dsi_set_bta_timeout(struct mipi_dsim_device *dsim,
+ unsigned int timeout);
+void s5p_mipi_dsi_set_lpdr_timeout(struct mipi_dsim_device *dsim,
+ unsigned int timeout);
+void s5p_mipi_dsi_set_lcdc_transfer_mode(struct mipi_dsim_device *dsim,
+ unsigned int lp);
+void s5p_mipi_dsi_set_cpu_transfer_mode(struct mipi_dsim_device *dsim,
+ unsigned int lp);
+void s5p_mipi_dsi_enable_hs_clock(struct mipi_dsim_device *dsim,
+ unsigned int enable);
+void s5p_mipi_dsi_dp_dn_swap(struct mipi_dsim_device *dsim,
+ unsigned int swap_en);
+void s5p_mipi_dsi_hs_zero_ctrl(struct mipi_dsim_device *dsim,
+ unsigned int hs_zero);
+void s5p_mipi_dsi_prep_ctrl(struct mipi_dsim_device *dsim, unsigned int prep);
+unsigned int s5p_mipi_dsi_read_interrupt(struct mipi_dsim_device *dsim);
+unsigned int s5p_mipi_dsi_read_interrupt_mask(struct mipi_dsim_device *dsim);
+void s5p_mipi_dsi_clear_interrupt(struct mipi_dsim_device *dsim,
+ unsigned int src);
+void s5p_mipi_dsi_set_interrupt(struct mipi_dsim_device *dsim,
+ unsigned int src, unsigned int enable);
+unsigned int s5p_mipi_dsi_is_pll_stable(struct mipi_dsim_device *dsim);
+unsigned int s5p_mipi_dsi_get_fifo_state(struct mipi_dsim_device *dsim);
+unsigned int _s5p_mipi_dsi_get_frame_done_status(struct mipi_dsim_device *dsim);
+void _s5p_mipi_dsi_clear_frame_done(struct mipi_dsim_device *dsim);
+void s5p_mipi_dsi_wr_tx_header(struct mipi_dsim_device *dsim, unsigned int di,
+ unsigned int data0, unsigned int data1);
+void s5p_mipi_dsi_wr_tx_data(struct mipi_dsim_device *dsim,
+ unsigned int tx_data);
+void s5p_mipi_dsi_rd_tx_header(struct mipi_dsim_device *dsim,
+ unsigned int data0, unsigned int data1);
+unsigned int s5p_mipi_dsi_rd_rx_fifo(struct mipi_dsim_device *dsim);
+
+#endif /* _S5P_MIPI_DSI_LOWLEVEL_H */
diff --git a/drivers/video/s5p_mipi_dsi_regs.h b/drivers/video/s5p_mipi_dsi_regs.h
new file mode 100644
index 0000000..2ad482f
--- /dev/null
+++ b/drivers/video/s5p_mipi_dsi_regs.h
@@ -0,0 +1,149 @@
+/* linux/driver/video/s5p_mipi_dsi_regs.h
+ *
+ * Register definition file for Samsung MIPI-DSIM driver
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * InKi Dae <inki.dae@samsung.com>
+ * Donghwa Lee <dh09.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef _REGS_DSIM_H
+#define _REGS_DSIM_H
+
+#define S5P_DSIM_STATUS 0x0 /* Status register */
+#define S5P_DSIM_SWRST 0x4 /* Software reset register */
+#define S5P_DSIM_CLKCTRL 0x8 /* Clock control register */
+#define S5P_DSIM_TIMEOUT 0xc /* Time out register */
+#define S5P_DSIM_CONFIG 0x10 /* Configuration register */
+#define S5P_DSIM_ESCMODE 0x14 /* Escape mode register */
+
+/* Main display image resolution register */
+#define S5P_DSIM_MDRESOL 0x18
+#define S5P_DSIM_MVPORCH 0x1c /* Main display Vporch register */
+#define S5P_DSIM_MHPORCH 0x20 /* Main display Hporch register */
+#define S5P_DSIM_MSYNC 0x24 /* Main display sync area register */
+
+/* Sub display image resolution register */
+#define S5P_DSIM_SDRESOL 0x28
+#define S5P_DSIM_INTSRC 0x2c /* Interrupt source register */
+#define S5P_DSIM_INTMSK 0x30 /* Interrupt mask register */
+#define S5P_DSIM_PKTHDR 0x34 /* Packet Header FIFO register */
+#define S5P_DSIM_PAYLOAD 0x38 /* Payload FIFO register */
+#define S5P_DSIM_RXFIFO 0x3c /* Read FIFO register */
+#define S5P_DSIM_FIFOTHLD 0x40 /* FIFO threshold level register */
+#define S5P_DSIM_FIFOCTRL 0x44 /* FIFO status and control register */
+
+/* FIFO memory AC characteristic register */
+#define S5P_DSIM_PLLCTRL 0x4c /* PLL control register */
+#define S5P_DSIM_PLLTMR 0x50 /* PLL timer register */
+#define S5P_DSIM_PHYACCHR 0x54 /* D-PHY AC characteristic register */
+#define S5P_DSIM_PHYACCHR1 0x58 /* D-PHY AC characteristic register1 */
+
+/* DSIM_STATUS */
+#define DSIM_STOP_STATE_DAT(x) (((x) & 0xf) << 0)
+#define DSIM_STOP_STATE_CLK (1 << 8)
+#define DSIM_TX_READY_HS_CLK (1 << 10)
+
+/* DSIM_SWRST */
+#define DSIM_FUNCRST (1 << 16)
+#define DSIM_SWRST (1 << 0)
+
+/* S5P_DSIM_TIMEOUT */
+#define DSIM_LPDR_TOUT_SHIFT(x) ((x) << 0)
+#define DSIM_BTA_TOUT_SHIFT(x) ((x) << 16)
+
+/* S5P_DSIM_CLKCTRL */
+#define DSIM_LANE_ESC_CLKEN(x) (((x) & 0x1f) << 19)
+#define DSIM_BYTE_CLKEN_SHIFT(x) ((x) << 24)
+#define DSIM_BYTE_CLK_SRC_SHIFT(x) ((x) << 25)
+#define DSIM_PLL_BYPASS_SHIFT(x) ((x) << 27)
+#define DSIM_ESC_CLKEN_SHIFT(x) ((x) << 28)
+#define DSIM_TX_REQUEST_HSCLK_SHIFT(x) ((x) << 31)
+
+/* S5P_DSIM_CONFIG */
+#define DSIM_LANE_ENx(x) (((x) & 0x1f) << 0)
+#define DSIM_NUM_OF_DATALANE_SHIFT(x) ((x) << 5)
+#define DSIM_HSA_MODE_SHIFT(x) ((x) << 20)
+#define DSIM_HBP_MODE_SHIFT(x) ((x) << 21)
+#define DSIM_HFP_MODE_SHIFT(x) ((x) << 22)
+#define DSIM_HSE_MODE_SHIFT(x) ((x) << 23)
+#define DSIM_AUTO_MODE_SHIFT(x) ((x) << 24)
+#define DSIM_EOT_DISABLE(x) ((x) << 28)
+#define DSIM_AUTO_FLUSH(x) ((x) << 29)
+
+#define DSIM_NUM_OF_DATA_LANE(x) ((x) << DSIM_NUM_OF_DATALANE_SHIFT)
+
+/* S5P_DSIM_ESCMODE */
+#define DSIM_TX_LPDT_LP (1 << 6)
+#define DSIM_CMD_LPDT_LP (1 << 7)
+#define DSIM_FORCE_STOP_STATE_SHIFT(x) ((x) << 20)
+#define DSIM_STOP_STATE_CNT_SHIFT(x) ((x) << 21)
+
+/* 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(x) ((x) << 28)
+#define DSIM_STABLE_VFP_SHIFT(x) ((x) << 16)
+#define DSIM_MAIN_VBP_SHIFT(x) ((x) << 0)
+#define DSIM_CMD_ALLOW_MASK (0xf << 28)
+#define DSIM_STABLE_VFP_MASK (0x7ff << 16)
+#define DSIM_MAIN_VBP_MASK (0x7ff << 0)
+
+/* S5P_DSIM_MHPORCH */
+#define DSIM_MAIN_HFP_SHIFT(x) ((x) << 16)
+#define DSIM_MAIN_HBP_SHIFT(x) ((x) << 0)
+#define DSIM_MAIN_HFP_MASK ((0xffff) << 16)
+#define DSIM_MAIN_HBP_MASK ((0xffff) << 0)
+
+/* S5P_DSIM_MSYNC */
+#define DSIM_MAIN_VSA_SHIFT(x) ((x) << 22)
+#define DSIM_MAIN_HSA_SHIFT(x) ((x) << 0)
+#define DSIM_MAIN_VSA_MASK ((0x3ff) << 22)
+#define DSIM_MAIN_HSA_MASK ((0xffff) << 0)
+
+/* S5P_DSIM_SDRESOL */
+#define DSIM_SUB_STANDY_SHIFT(x) ((x) << 31)
+#define DSIM_SUB_VRESOL_SHIFT(x) ((x) << 16)
+#define DSIM_SUB_HRESOL_SHIFT(x) ((x) << 0)
+#define DSIM_SUB_STANDY_MASK ((0x1) << 31)
+#define DSIM_SUB_VRESOL_MASK ((0x7ff) << 16)
+#define DSIM_SUB_HRESOL_MASK ((0x7ff) << 0)
+
+/* S5P_DSIM_INTSRC */
+#define INTSRC_PLL_STABLE (1 << 31)
+#define INTSRC_SW_RST_RELEASE (1 << 30)
+#define INTSRC_SFR_FIFO_EMPTY (1 << 29)
+#define INTSRC_FRAME_DONE (1 << 24)
+#define INTSRC_RX_DATA_DONE (1 << 18)
+
+/* S5P_DSIM_INTMSK */
+#define INTMSK_FIFO_EMPTY (1 << 29)
+#define INTMSK_BTA (1 << 25)
+#define INTMSK_FRAME_DONE (1 << 24)
+#define INTMSK_RX_TIMEOUT (1 << 21)
+#define INTMSK_BTA_TIMEOUT (1 << 20)
+#define INTMSK_RX_DONE (1 << 18)
+#define INTMSK_RX_TE (1 << 17)
+#define INTMSK_RX_ACK (1 << 16)
+#define INTMSK_RX_ECC_ERR (1 << 15)
+#define INTMSK_RX_CRC_ERR (1 << 14)
+
+/* S5P_DSIM_FIFOCTRL */
+#define SFR_HEADER_EMPTY (1 << 22)
+
+/* S5P_DSIM_PHYACCHR */
+#define DSIM_AFC_CTL(x) (((x) & 0x7) << 5)
+
+/* S5P_DSIM_PLLCTRL */
+#define DSIM_PLL_EN_SHIFT(x) ((x) << 23)
+#define DSIM_FREQ_BAND_SHIFT(x) ((x) << 24)
+
+#endif /* _REGS_DSIM_H */
diff --git a/include/linux/mipi_dsim.h b/include/linux/mipi_dsim.h
new file mode 100644
index 0000000..f54da24
--- /dev/null
+++ b/include/linux/mipi_dsim.h
@@ -0,0 +1,359 @@
+/* include/linux/mipi_dsim.h
+ *
+ * Platform data header for Samsung SoC MIPI-DSIM.
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ *
+ * InKi Dae <inki.dae@samsung.com>
+ * Donghwa Lee <dh09.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef _LINUX_MIPI_DSIM_H
+#define _LINUX_MIPI_DSIM_H
+
+#include <linux/device.h>
+#include <linux/fb.h>
+
+#define PANEL_NAME_SIZE (32)
+
+/*
+ * Enumerate display interface type.
+ *
+ * DSIM_COMMAND means cpu interface and rgb interface for DSIM_VIDEO.
+ *
+ * P.S. MIPI DSI Master has two display controller intefaces, RGB Interface
+ * for main display and CPU Interface(same as I80 Interface) for main
+ * and sub display.
+ */
+enum mipi_dsim_interface_type {
+ DSIM_COMMAND,
+ DSIM_VIDEO
+};
+
+enum mipi_dsim_virtual_ch_no {
+ DSIM_VIRTUAL_CH_0,
+ DSIM_VIRTUAL_CH_1,
+ DSIM_VIRTUAL_CH_2,
+ DSIM_VIRTUAL_CH_3
+};
+
+enum mipi_dsim_burst_mode_type {
+ DSIM_NON_BURST_SYNC_EVENT,
+ DSIM_BURST_SYNC_EVENT,
+ DSIM_NON_BURST_SYNC_PULSE,
+ DSIM_BURST,
+ DSIM_NON_VIDEO_MODE
+};
+
+enum mipi_dsim_no_of_data_lane {
+ DSIM_DATA_LANE_1,
+ DSIM_DATA_LANE_2,
+ DSIM_DATA_LANE_3,
+ DSIM_DATA_LANE_4
+};
+
+enum mipi_dsim_byte_clk_src {
+ DSIM_PLL_OUT_DIV8,
+ DSIM_EXT_CLK_DIV8,
+ DSIM_EXT_CLK_BYPASS
+};
+
+enum mipi_dsim_pixel_format {
+ DSIM_CMD_3BPP,
+ DSIM_CMD_8BPP,
+ DSIM_CMD_12BPP,
+ DSIM_CMD_16BPP,
+ DSIM_VID_16BPP_565,
+ DSIM_VID_18BPP_666PACKED,
+ DSIM_18BPP_666LOOSELYPACKED,
+ DSIM_24BPP_888
+};
+
+/*
+ * struct mipi_dsim_config - interface for configuring mipi-dsi controller.
+ *
+ * @auto_flush: enable or disable Auto flush of MD FIFO using VSYNC pulse.
+ * @eot_disable: enable or disable EoT packet in HS mode.
+ * @auto_vertical_cnt: specifies auto vertical count mode.
+ * in Video mode, the vertical line transition uses line counter
+ * configured by VSA, VBP, and Vertical resolution.
+ * If this bit is set to '1', the line counter does not use VSA and VBP
+ * registers.(in command mode, this variable is ignored)
+ * @hse: set horizontal sync event mode.
+ * In VSYNC pulse and Vporch area, MIPI DSI master transfers only HSYNC
+ * start packet to MIPI DSI slave at MIPI DSI spec1.1r02.
+ * this bit transfers HSYNC end packet in VSYNC pulse and Vporch area
+ * (in mommand mode, this variable is ignored)
+ * @hfp: specifies HFP disable mode.
+ * if this variable is set, DSI master ignores HFP area in VIDEO mode.
+ * (in command mode, this variable is ignored)
+ * @hbp: specifies HBP disable mode.
+ * if this variable is set, DSI master ignores HBP area in VIDEO mode.
+ * (in command mode, this variable is ignored)
+ * @hsa: specifies HSA disable mode.
+ * if this variable is set, DSI master ignores HSA area in VIDEO mode.
+ * (in command mode, this variable is ignored)
+ * @cma_allow: specifies the number of horizontal lines, where command packet
+ * transmission is allowed after Stable VFP period.
+ * @e_interface: specifies interface to be used.(CPU or RGB interface)
+ * @e_virtual_ch: specifies virtual channel number that main or
+ * sub diaplsy uses.
+ * @e_pixel_format: specifies pixel stream format for main or sub display.
+ * @e_burst_mode: selects Burst mode in Video mode.
+ * in Non-burst mode, RGB data area is filled with RGB data and NULL
+ * packets, according to input bandwidth of RGB interface.
+ * In Burst mode, RGB data area is filled with RGB data only.
+ * @e_no_data_lane: specifies data lane count to be used by Master.
+ * @e_byte_clk: select byte clock source. (it must be DSIM_PLL_OUT_DIV8)
+ * DSIM_EXT_CLK_DIV8 and DSIM_EXT_CLK_BYPASSS are not supported.
+ * @pll_stable_time: specifies the PLL Timer for stability of the ganerated
+ * clock(System clock cycle base)
+ * if the timer value goes to 0x00000000, the clock stable bit of status
+ * and interrupt register is set.
+ * @esc_clk: specifies escape clock frequency for getting the escape clock
+ * prescaler value.
+ * @stop_holding_cnt: specifies the interval value between transmitting
+ * read packet(or write "set_tear_on" command) and BTA request.
+ * after transmitting read packet or write "set_tear_on" command,
+ * BTA requests to D-PHY automatically. this counter value specifies
+ * the interval between them.
+ * @bta_timeout: specifies the timer for BTA.
+ * this register specifies time out from BTA request to change
+ * the direction with respect to Tx escape clock.
+ * @rx_timeout: specifies the timer for LP Rx mode timeout.
+ * this register specifies time out on how long RxValid deasserts,
+ * after RxLpdt asserts with respect to Tx escape clock.
+ * - RxValid specifies Rx data valid indicator.
+ * - RxLpdt specifies an indicator that D-PHY is under RxLpdt mode.
+ * - RxValid and RxLpdt specifies signal from D-PHY.
+ */
+struct mipi_dsim_config {
+ unsigned char auto_flush;
+ unsigned char eot_disable;
+
+ unsigned char auto_vertical_cnt;
+ unsigned char hse;
+ unsigned char hfp;
+ unsigned char hbp;
+ unsigned char hsa;
+ unsigned char cmd_allow;
+
+ enum mipi_dsim_interface_type e_interface;
+ enum mipi_dsim_virtual_ch_no e_virtual_ch;
+ enum mipi_dsim_pixel_format e_pixel_format;
+ enum mipi_dsim_burst_mode_type e_burst_mode;
+ enum mipi_dsim_no_of_data_lane e_no_data_lane;
+ enum mipi_dsim_byte_clk_src e_byte_clk;
+
+ /*
+ * =====================+ * | P | M | S | MHz |
+ * -------------------------------------------
+ * | 3 | 100 | 3 | 100 |
+ * | 3 | 100 | 2 | 200 |
+ * | 3 | 63 | 1 | 252 |
+ * | 4 | 100 | 1 | 300 |
+ * | 4 | 110 | 1 | 330 |
+ * | 12 | 350 | 1 | 350 |
+ * | 3 | 100 | 1 | 400 |
+ * | 4 | 150 | 1 | 450 |
+ * | 6 | 118 | 1 | 472 |
+ * | 3 | 120 | 1 | 480 |
+ * | 12 | 250 | 0 | 500 |
+ * | 4 | 100 | 0 | 600 |
+ * | 3 | 81 | 0 | 648 |
+ * | 3 | 88 | 0 | 704 |
+ * | 3 | 90 | 0 | 720 |
+ * | 3 | 100 | 0 | 800 |
+ * | 12 | 425 | 0 | 850 |
+ * | 4 | 150 | 0 | 900 |
+ * | 12 | 475 | 0 | 950 |
+ * | 6 | 250 | 0 | 1000 |
+ * -------------------------------------------
+ */
+
+ /*
+ * pms could be calculated as the following.
+ * M * 24 / P * 2 ^ S = MHz
+ */
+ unsigned char p;
+ unsigned short m;
+ unsigned char s;
+
+ unsigned int pll_stable_time;
+ unsigned long esc_clk;
+
+ unsigned short stop_holding_cnt;
+ unsigned char bta_timeout;
+ unsigned short rx_timeout;
+};
+
+/*
+ * struct mipi_dsim_device - global interface for mipi-dsi driver.
+ *
+ * @dev: driver model representation of the device.
+ * @id: unique device id.
+ * @clock: pointer to MIPI-DSI clock of clock framework.
+ * @irq: interrupt number to MIPI-DSI controller.
+ * @reg_base: base address to memory mapped SRF of MIPI-DSI controller.
+ * (virtual address)
+ * @lock: the mutex protecting this data structure.
+ * @dsim_info: infomation for configuring mipi-dsi controller.
+ * @master_ops: callbacks to mipi-dsi operations.
+ * @dsim_lcd_dev: pointer to activated ddi device.
+ * (it would be registered by mipi-dsi driver.)
+ * @dsim_lcd_drv: pointer to activated_ddi driver.
+ * (it would be registered by mipi-dsi driver.)
+ * @lcd_info: pointer to mipi_lcd_info structure.
+ * @state: specifies status of MIPI-DSI controller.
+ * the status could be RESET, INIT, STOP, HSCLKEN and ULPS.
+ * @data_lane: specifiec enabled data lane number.
+ * this variable would be set by driver according to e_no_data_lane
+ * automatically.
+ * @e_clk_src: select byte clock source.
+ * @pd: pointer to MIPI-DSI driver platform data.
+ */
+struct mipi_dsim_device {
+ struct device *dev;
+ int id;
+ struct resource *res;
+ struct clk *clock;
+ unsigned int irq;
+ void __iomem *reg_base;
+ struct mutex lock;
+
+ struct mipi_dsim_config *dsim_config;
+ struct mipi_dsim_master_ops *master_ops;
+ struct mipi_dsim_lcd_device *dsim_lcd_dev;
+ struct mipi_dsim_lcd_driver *dsim_lcd_drv;
+
+ unsigned int state;
+ unsigned int data_lane;
+ unsigned int e_clk_src;
+ bool suspended;
+
+ struct mipi_dsim_platform_data *pd;
+};
+
+/*
+ * struct mipi_dsim_platform_data - interface to platform data
+ * for mipi-dsi driver.
+ *
+ * @lcd_panel_name: specifies lcd panel name registered to mipi-dsi driver.
+ * lcd panel driver searched would be actived.
+ * @dsim_config: pointer of structure for configuring mipi-dsi controller.
+ * @enabled: indicate whether mipi controller got enabled or not.
+ * @lcd_panel_info: pointer for lcd panel specific structure.
+ * this structure specifies width, height, timing and polarity and so on.
+ * @phy_enable: pointer to a callback controlling D-PHY enable/reset
+ */
+struct mipi_dsim_platform_data {
+ char lcd_panel_name[PANEL_NAME_SIZE];
+
+ struct mipi_dsim_config *dsim_config;
+ unsigned int enabled;
+ void *lcd_panel_info;
+
+ int (*phy_enable)(struct platform_device *pdev, bool on);
+};
+
+/*
+ * struct mipi_dsim_master_ops - callbacks to mipi-dsi operations.
+ *
+ * @cmd_write: transfer command to lcd panel at LP mode.
+ * @cmd_read: read command from rx register.
+ * @get_dsim_frame_done: get the status that all screen data have been
+ * transferred to mipi-dsi.
+ * @clear_dsim_frame_done: clear frame done status.
+ * @get_fb_frame_done: get frame done status of display controller.
+ * @trigger: trigger display controller.
+ * - this one would be used only in case of CPU mode.
+ * @set_early_blank_mode: set framebuffer blank mode.
+ * - this callback should be called prior to fb_blank() by a client driver
+ * only if needing.
+ * @set_blank_mode: set framebuffer blank mode.
+ * - this callback should be called after fb_blank() by a client driver
+ * only if needing.
+ */
+
+struct mipi_dsim_master_ops {
+ int (*cmd_write)(struct mipi_dsim_device *dsim, unsigned int data_id,
+ const unsigned char *data0, unsigned int data1);
+ int (*cmd_read)(struct mipi_dsim_device *dsim, unsigned int data_id,
+ unsigned int data0, unsigned int req_size, u8 *rx_buf);
+ int (*get_dsim_frame_done)(struct mipi_dsim_device *dsim);
+ int (*clear_dsim_frame_done)(struct mipi_dsim_device *dsim);
+
+ int (*get_fb_frame_done)(struct fb_info *info);
+ void (*trigger)(struct fb_info *info);
+ int (*set_early_blank_mode)(struct mipi_dsim_device *dsim, int power);
+ int (*set_blank_mode)(struct mipi_dsim_device *dsim, int power);
+};
+
+/*
+ * device structure for mipi-dsi based lcd panel.
+ *
+ * @name: name of the device to use with this device, or an
+ * alias for that name.
+ * @dev: driver model representation of the device.
+ * @id: id of device to be registered.
+ * @bus_id: bus id for identifing connected bus
+ * and this bus id should be same as id of mipi_dsim_device.
+ * @irq: irq number for signaling when framebuffer transfer of
+ * lcd panel module is completed.
+ * this irq would be used only for MIPI-DSI based CPU mode lcd panel.
+ * @master: pointer to mipi-dsi master device object.
+ * @platform_data: lcd panel specific platform data.
+ */
+struct mipi_dsim_lcd_device {
+ char *name;
+ struct device dev;
+ int id;
+ int bus_id;
+ int irq;
+
+ struct mipi_dsim_device *master;
+ void *platform_data;
+};
+
+/*
+ * driver structure for mipi-dsi based lcd panel.
+ *
+ * this structure should be registered by lcd panel driver.
+ * mipi-dsi driver seeks lcd panel registered through name field
+ * and calls these callback functions in appropriate time.
+ *
+ * @name: name of the driver to use with this device, or an
+ * alias for that name.
+ * @id: id of driver to be registered.
+ * this id would be used for finding device object registered.
+ */
+struct mipi_dsim_lcd_driver {
+ char *name;
+ int id;
+
+ void (*power_on)(struct mipi_dsim_lcd_device *dsim_dev, int enable);
+ void (*set_sequence)(struct mipi_dsim_lcd_device *dsim_dev);
+ int (*probe)(struct mipi_dsim_lcd_device *dsim_dev);
+ int (*remove)(struct mipi_dsim_lcd_device *dsim_dev);
+ void (*shutdown)(struct mipi_dsim_lcd_device *dsim_dev);
+ int (*suspend)(struct mipi_dsim_lcd_device *dsim_dev);
+ int (*resume)(struct mipi_dsim_lcd_device *dsim_dev);
+};
+
+/*
+ * register mipi_dsim_lcd_device to mipi-dsi master.
+ */
+int s5p_mipi_dsi_register_lcd_device(struct mipi_dsim_lcd_device
+ *lcd_dev);
+/**
+ * register mipi_dsim_lcd_driver object defined by lcd panel driver
+ * to mipi-dsi driver.
+ */
+int s5p_mipi_dsi_register_lcd_driver(struct mipi_dsim_lcd_driver
+ *lcd_drv);
+#endif /* _LINUX_MIPI_DSIM_H */
--
1.7.4.1
^ permalink raw reply related
* Re: [PATCH v5 2/2] video: backlight: support s6e8ax0 panel driver based on MIPI DSI
From: Donghwa Lee @ 2012-01-18 0:52 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20120104170103.bae938a9.akpm@linux-foundation.org>
On Thu, 5, Jan 2012 10:01, Andrew Morton wrote:
> On Wed, 21 Dec 2011 13:25:00 +0900
> Donghwa Lee <dh09.lee@samsung.com> wrote:
>
>>
>> This patch is amoled panel driver based MIPI DSI interface.
>> S6E8AX0 means it may includes many other ldi controllers, for example,
>> S6E8AA0, S6E8AB0, and so on.
>>
>> This patch can be modified depending on each panel properites. For example,
>> second parameter of panel condition register can be changed depending on
>> ldi controller or amoled type.
>>
>>
>> ...
>>
>> +static unsigned char s6e8ax0_22_gamma_30[] = {
>> + 0xFA, 0x01, 0x60, 0x10, 0x60, 0xF5, 0x00, 0xFF, 0xAD, 0xAF,
>> + 0xBA, 0xC3, 0xD8, 0xC5, 0x9F, 0xC6, 0x9E, 0xC1, 0xDC, 0xC0,
>> + 0x00, 0x61, 0x00, 0x5A, 0x00, 0x74,
>> +};
>> +
>>
>> ...
>>
>> +static unsigned char s6e8ax0_22_gamma_300[] = {
>> + 0xFA, 0x01, 0x60, 0x10, 0x60, 0xB5, 0xD3, 0xBD, 0xB1, 0xD2,
>> + 0xB0, 0xC0, 0xDC, 0xC0, 0x94, 0xBA, 0x91, 0xAC, 0xC5, 0xA9,
>> + 0x00, 0xC2, 0x00, 0xB7, 0x00, 0xED,
>> +};
>> +
>> +static unsigned char *s6e8ax0_22_gamma_table[] = {
>> + s6e8ax0_22_gamma_30,
>> + s6e8ax0_22_gamma_50,
>> + s6e8ax0_22_gamma_60,
>> + s6e8ax0_22_gamma_70,
>> + s6e8ax0_22_gamma_80,
>> + s6e8ax0_22_gamma_90,
>> + s6e8ax0_22_gamma_100,
>> + s6e8ax0_22_gamma_120,
>> + s6e8ax0_22_gamma_130,
>> + s6e8ax0_22_gamma_140,
>> + s6e8ax0_22_gamma_150,
>> + s6e8ax0_22_gamma_160,
>> + s6e8ax0_22_gamma_170,
>> + s6e8ax0_22_gamma_180,
>> + s6e8ax0_22_gamma_190,
>> + s6e8ax0_22_gamma_200,
>> + s6e8ax0_22_gamma_210,
>> + s6e8ax0_22_gamma_220,
>> + s6e8ax0_22_gamma_230,
>> + s6e8ax0_22_gamma_240,
>> + s6e8ax0_22_gamma_250,
>> + s6e8ax0_22_gamma_260,
>> + s6e8ax0_22_gamma_270,
>> + s6e8ax0_22_gamma_280,
>> + s6e8ax0_22_gamma_300,
>> +};
>
> I suggest making all the above arrays const. Otherwise the compiler
> might end up deciding to needlessly allocate space in writeable storage
> for them.
>
> If that means that ops->cmd_write() needs constification as well then
> let's just do that, for it is the right thing to do.
>
Ok, I will change it to const arrays with ops->cmd_write() function parameter.
>> +static void s6e8ax0_panel_cond(struct s6e8ax0 *lcd)
>> +{
>> + struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
>> +
>> + unsigned char data_to_send[] = {
>> + 0xf8, 0x3d, 0x35, 0x00, 0x00, 0x00, 0x93, 0x00, 0x3c,
>> + 0x7d, 0x08, 0x27, 0x7d, 0x3f, 0x00, 0x00, 0x00, 0x20,
>> + 0x04, 0x08, 0x6e, 0x00, 0x00, 0x00, 0x02, 0x08, 0x08,
>> + 0x23, 0x23, 0xc0, 0xc8, 0x08, 0x48, 0xc1, 0x00, 0xc1,
>> + 0xff, 0xff, 0xc8
>> + };
>
> Arrays like this certainly should be const. As it stands, the compiler
> needs to generate room on the stack and generate a local copy of the
> array each time this function is called!
>
>> + ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
>> + data_to_send, ARRAY_SIZE(data_to_send));
>> +}
>> +
>> +static void s6e8ax0_display_cond(struct s6e8ax0 *lcd)
>> +{
>> + struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
>> + unsigned char data_to_send[] = {
>> + 0xf2, 0x80, 0x03, 0x0d
>> + };
>> +
>> + ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
>> + data_to_send, ARRAY_SIZE(data_to_send));
>> +}
>> +
>> +/* Gamma 2.2 Setting (200cd, 7500K, 10MPCD) */
>> +static void s6e8ax0_gamma_cond(struct s6e8ax0 *lcd)
>> +{
>> + struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
>> + unsigned int gamma = lcd->bd->props.brightness;
>> +
>> + ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
>> + s6e8ax0_22_gamma_table[gamma],
>> + ARRAY_SIZE(s6e8ax0_22_gamma_table));
>
> This seems wrong. ARRAY_SIZE(s6e8ax0_22_gamma_table) does not
> represent the size of s6e8ax0_22_gamma_table[gamma]!
>
>> +}
>> +
>>
>> ...
>>
>> +static int s6e8ax0_update_gamma_ctrl(struct s6e8ax0 *lcd, int brightness)
>> +{
>> + struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
>> +
>> + ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
>> + s6e8ax0_22_gamma_table[brightness],
>> + ARRAY_SIZE(s6e8ax0_22_gamma_table));
>
> Ditto.
>
>> + /* update gamma table. */
>> + s6e8ax0_gamma_update(lcd);
>> + lcd->gamma = brightness;
>> +
>> + return 0;
>> +}
>> +
>>
>> ...
>>
>> +static void s6e8ax0_power_on(struct mipi_dsim_lcd_device *dsim_dev, int power)
>> +{
>> + struct s6e8ax0 *lcd = dev_get_drvdata(&dsim_dev->dev);
>> +
>> + msleep(lcd->ddi_pd->power_on_delay);
>> +
>> + /* lcd power on */
>> + if (power)
>> + s6e8ax0_regulator_enable(lcd);
>> + else
>> + s6e8ax0_regulator_disable(lcd);
>> +
>> + msleep(lcd->ddi_pd->reset_delay);
>> +
>> + /* lcd reset */
>> + if (lcd->ddi_pd->reset)
>> + lcd->ddi_pd->reset(lcd->ld);
>> + msleep(5);
>> +}
>
> Maybe we should hold lcd->lock across this function to prevent other
> code paths from getting in and fiddling with the hardware while it is
> powering on?
>
In s6e8ax0_regulator_enable()/disable() functions, lcd->lock was used to hold.
>>
>> ...
>>
>
> --
> 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
* Re: [PATCH 5/6] OMAP: 4430SDP/Panda: add HDMI HPD gpio
From: Archit @ 2012-01-17 20:44 UTC (permalink / raw)
To: Tomi Valkeinen; +Cc: linux-omap, linux-fbdev, mythripk, archit, x0132446
In-Reply-To: <1326804542-22285-6-git-send-email-tomi.valkeinen@ti.com>
On Tuesday 17 January 2012 06:19 PM, Tomi Valkeinen wrote:
> Both Panda and 4430SDP use GPIO 64 as HDMI hot-plug-detect. Configure
> this GPIO in the board files.
Minor comment: the commit message says GPIO 64, and the macros use gpio
63. Is this done intentionally?
Archit
>
> Signed-off-by: Tomi Valkeinen<tomi.valkeinen@ti.com>
> ---
> arch/arm/mach-omap2/board-4430sdp.c | 3 +++
> arch/arm/mach-omap2/board-omap4panda.c | 3 +++
> 2 files changed, 6 insertions(+), 0 deletions(-)
>
> diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c
> index 5dcc8df..a776c26 100644
> --- a/arch/arm/mach-omap2/board-4430sdp.c
> +++ b/arch/arm/mach-omap2/board-4430sdp.c
> @@ -54,6 +54,7 @@
> #define OMAP4_SFH7741_ENABLE_GPIO 188
> #define HDMI_GPIO_CT_CP_HPD 60 /* HPD mode enable/disable */
> #define HDMI_GPIO_LS_OE 41 /* Level shifter for HDMI */
> +#define HDMI_GPIO_HPD 63 /* Hotplug detect */
> #define DISPLAY_SEL_GPIO 59 /* LCD2/PicoDLP switch */
> #define DLP_POWER_ON_GPIO 40
>
> @@ -598,6 +599,7 @@ static void __init omap_sfh7741prox_init(void)
> static struct gpio sdp4430_hdmi_gpios[] = {
> { HDMI_GPIO_CT_CP_HPD, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ct_cp_hpd" },
> { HDMI_GPIO_LS_OE, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ls_oe" },
> + { HDMI_GPIO_HPD, GPIOF_DIR_IN, "hdmi_gpio_hpd" },
> };
>
> static int sdp4430_panel_enable_hdmi(struct omap_dss_device *dssdev)
> @@ -836,6 +838,7 @@ static void omap_4430sdp_display_init(void)
>
> omap_mux_init_gpio(HDMI_GPIO_LS_OE, OMAP_PIN_OUTPUT);
> omap_mux_init_gpio(HDMI_GPIO_CT_CP_HPD, OMAP_PIN_OUTPUT);
> + omap_mux_init_gpio(HDMI_GPIO_HPD, OMAP_PIN_INPUT_PULLDOWN);
> }
>
> #ifdef CONFIG_OMAP_MUX
> diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c
> index 06a7075..b22a288 100644
> --- a/arch/arm/mach-omap2/board-omap4panda.c
> +++ b/arch/arm/mach-omap2/board-omap4panda.c
> @@ -53,6 +53,7 @@
> #define GPIO_WIFI_IRQ 53
> #define HDMI_GPIO_CT_CP_HPD 60 /* HPD mode enable/disable */
> #define HDMI_GPIO_LS_OE 41 /* Level shifter for HDMI */
> +#define HDMI_GPIO_HPD 63 /* Hotplug detect */
>
> /* wl127x BT, FM, GPS connectivity chip */
> static int wl1271_gpios[] = {46, -1, -1};
> @@ -481,6 +482,7 @@ int __init omap4_panda_dvi_init(void)
> static struct gpio panda_hdmi_gpios[] = {
> { HDMI_GPIO_CT_CP_HPD, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ct_cp_hpd" },
> { HDMI_GPIO_LS_OE, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ls_oe" },
> + { HDMI_GPIO_HPD, GPIOF_DIR_IN, "hdmi_gpio_hpd" },
> };
>
> static int omap4_panda_panel_enable_hdmi(struct omap_dss_device *dssdev)
> @@ -552,6 +554,7 @@ void omap4_panda_display_init(void)
>
> omap_mux_init_gpio(HDMI_GPIO_LS_OE, OMAP_PIN_OUTPUT);
> omap_mux_init_gpio(HDMI_GPIO_CT_CP_HPD, OMAP_PIN_OUTPUT);
> + omap_mux_init_gpio(HDMI_GPIO_HPD, OMAP_PIN_INPUT_PULLDOWN);
> }
>
> static void __init omap4_panda_init(void)
^ permalink raw reply
* [PATCH 6/6] OMAPDSS: HDMI: PHY burnout fix
From: Tomi Valkeinen @ 2012-01-17 13:04 UTC (permalink / raw)
To: linux-omap, linux-fbdev, mythripk; +Cc: archit, x0132446, Tomi Valkeinen
In-Reply-To: <1326804542-22285-1-git-send-email-tomi.valkeinen@ti.com>
A hardware bug in the OMAP4 HDMI PHY causes physical damage to the board
if the HDMI PHY is powered on when the cable is not connected.
This patch solves the problem by adding hot-plug-detection into the HDMI
IP driver. This is not a real HPD support in the sense that nobody else
than the IP driver gets to know about the HPD events, but is only meant
to fix the HW bug.
The strategy is simple: If the display device is turned off by the user,
the PHY power is set to OFF. When the display device is turned on by the
user, the PHY power is set either to LDOON or TXON, depending on whether
the HDMI cable is connected.
The reason to avoid PHY OFF when the display device is on, but the cable
is disconnected, is that when the PHY is turned OFF, the HDMI IP is not
"ticking" and thus the DISPC does not receive pixel clock from the HDMI
IP. This would, for example, prevent any VSYNCs from happening, and
would thus affect the users of omapdss. By using LDOON when the cable is
disconnected we'll avoid the HW bug, but keep the HDMI working as usual
from the user's point of view.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
arch/arm/mach-omap2/board-4430sdp.c | 5 ++
arch/arm/mach-omap2/board-omap4panda.c | 5 ++
drivers/video/omap2/dss/hdmi.c | 3 +
drivers/video/omap2/dss/ti_hdmi.h | 4 ++
drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c | 68 +++++++++++++++++++++++++++--
include/video/omapdss.h | 5 ++
6 files changed, 86 insertions(+), 4 deletions(-)
diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c
index a776c26..d4fe511 100644
--- a/arch/arm/mach-omap2/board-4430sdp.c
+++ b/arch/arm/mach-omap2/board-4430sdp.c
@@ -732,6 +732,10 @@ static void sdp4430_lcd_init(void)
pr_err("%s: Could not get lcd2_reset_gpio\n", __func__);
}
+static struct omap_dss_hdmi_data sdp4430_hdmi_data = {
+ .hpd_gpio = HDMI_GPIO_HPD,
+};
+
static struct omap_dss_device sdp4430_hdmi_device = {
.name = "hdmi",
.driver_name = "hdmi_panel",
@@ -739,6 +743,7 @@ static struct omap_dss_device sdp4430_hdmi_device = {
.platform_enable = sdp4430_panel_enable_hdmi,
.platform_disable = sdp4430_panel_disable_hdmi,
.channel = OMAP_DSS_CHANNEL_DIGIT,
+ .data = &sdp4430_hdmi_data,
};
static struct picodlp_panel_data sdp4430_picodlp_pdata = {
diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c
index b22a288..c28ef20 100644
--- a/arch/arm/mach-omap2/board-omap4panda.c
+++ b/arch/arm/mach-omap2/board-omap4panda.c
@@ -502,6 +502,10 @@ static void omap4_panda_panel_disable_hdmi(struct omap_dss_device *dssdev)
gpio_free_array(panda_hdmi_gpios, ARRAY_SIZE(panda_hdmi_gpios));
}
+static struct omap_dss_hdmi_data omap4_panda_hdmi_data = {
+ .hpd_gpio = HDMI_GPIO_HPD,
+};
+
static struct omap_dss_device omap4_panda_hdmi_device = {
.name = "hdmi",
.driver_name = "hdmi_panel",
@@ -509,6 +513,7 @@ static struct omap_dss_device omap4_panda_hdmi_device = {
.platform_enable = omap4_panda_panel_enable_hdmi,
.platform_disable = omap4_panda_panel_disable_hdmi,
.channel = OMAP_DSS_CHANNEL_DIGIT,
+ .data = &omap4_panda_hdmi_data,
};
static struct omap_dss_device *omap4_panda_dss_devices[] = {
diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c
index 92a6679..3b76a20 100644
--- a/drivers/video/omap2/dss/hdmi.c
+++ b/drivers/video/omap2/dss/hdmi.c
@@ -469,6 +469,7 @@ bool omapdss_hdmi_detect(void)
int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev)
{
+ struct omap_dss_hdmi_data *priv = dssdev->data;
int r = 0;
DSSDBG("ENTER hdmi_display_enable\n");
@@ -481,6 +482,8 @@ int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev)
goto err0;
}
+ hdmi.ip_data.hpd_gpio = priv->hpd_gpio;
+
r = omap_dss_start_device(dssdev);
if (r) {
DSSERR("failed to start device\n");
diff --git a/drivers/video/omap2/dss/ti_hdmi.h b/drivers/video/omap2/dss/ti_hdmi.h
index 26ec6d1..cb6f0f2 100644
--- a/drivers/video/omap2/dss/ti_hdmi.h
+++ b/drivers/video/omap2/dss/ti_hdmi.h
@@ -122,6 +122,10 @@ struct hdmi_ip_data {
const struct ti_hdmi_ip_ops *ops;
struct hdmi_config cfg;
struct hdmi_pll_info pll_data;
+
+ /* ti_hdmi_4xxx_ip private data. These should be in a separate struct */
+ int hpd_gpio;
+ bool phy_tx_enabled;
};
int ti_hdmi_4xxx_phy_enable(struct hdmi_ip_data *ip_data);
void ti_hdmi_4xxx_phy_disable(struct hdmi_ip_data *ip_data);
diff --git a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c
index a229ae7..34e58dd 100644
--- a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c
+++ b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c
@@ -28,6 +28,7 @@
#include <linux/delay.h>
#include <linux/string.h>
#include <linux/seq_file.h>
+#include <linux/gpio.h>
#include "ti_hdmi_4xxx_ip.h"
#include "dss.h"
@@ -223,6 +224,49 @@ void ti_hdmi_4xxx_pll_disable(struct hdmi_ip_data *ip_data)
hdmi_set_pll_pwr(ip_data, HDMI_PLLPWRCMD_ALLOFF);
}
+static int hdmi_check_hpd_state(struct hdmi_ip_data *ip_data)
+{
+ unsigned long flags;
+ bool hpd;
+ int r;
+ /* this should be in ti_hdmi_4xxx_ip private data */
+ static DEFINE_SPINLOCK(phy_tx_lock);
+
+ spin_lock_irqsave(&phy_tx_lock, flags);
+
+ hpd = gpio_get_value(ip_data->hpd_gpio);
+
+ if (hpd = ip_data->phy_tx_enabled) {
+ spin_unlock_irqrestore(&phy_tx_lock, flags);
+ return 0;
+ }
+
+ if (hpd)
+ r = hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_TXON);
+ else
+ r = hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_LDOON);
+
+ if (r) {
+ DSSERR("Failed to %s PHY TX power\n",
+ hpd ? "enable" : "disable");
+ goto err;
+ }
+
+ ip_data->phy_tx_enabled = hpd;
+err:
+ spin_unlock_irqrestore(&phy_tx_lock, flags);
+ return r;
+}
+
+static irqreturn_t hpd_irq_handler(int irq, void *data)
+{
+ struct hdmi_ip_data *ip_data = data;
+
+ hdmi_check_hpd_state(ip_data);
+
+ return IRQ_HANDLED;
+}
+
int ti_hdmi_4xxx_phy_enable(struct hdmi_ip_data *ip_data)
{
u16 r = 0;
@@ -232,10 +276,6 @@ int ti_hdmi_4xxx_phy_enable(struct hdmi_ip_data *ip_data)
if (r)
return r;
- r = hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_TXON);
- if (r)
- return r;
-
/*
* Read address 0 in order to get the SCP reset done completed
* Dummy access performed to make sure reset is done
@@ -257,12 +297,32 @@ int ti_hdmi_4xxx_phy_enable(struct hdmi_ip_data *ip_data)
/* Write to phy address 3 to change the polarity control */
REG_FLD_MOD(phy_base, HDMI_TXPHY_PAD_CFG_CTRL, 0x1, 27, 27);
+ r = request_threaded_irq(gpio_to_irq(ip_data->hpd_gpio),
+ NULL, hpd_irq_handler,
+ IRQF_DISABLED | IRQF_TRIGGER_RISING |
+ IRQF_TRIGGER_FALLING, "hpd", ip_data);
+ if (r) {
+ DSSERR("HPD IRQ request failed\n");
+ hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_OFF);
+ return r;
+ }
+
+ r = hdmi_check_hpd_state(ip_data);
+ if (r) {
+ free_irq(gpio_to_irq(ip_data->hpd_gpio), ip_data);
+ hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_OFF);
+ return r;
+ }
+
return 0;
}
void ti_hdmi_4xxx_phy_disable(struct hdmi_ip_data *ip_data)
{
+ free_irq(gpio_to_irq(ip_data->hpd_gpio), ip_data);
+
hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_OFF);
+ ip_data->phy_tx_enabled = false;
}
static int hdmi_core_ddc_init(struct hdmi_ip_data *ip_data)
diff --git a/include/video/omapdss.h b/include/video/omapdss.h
index 062b3b2..483f67c 100644
--- a/include/video/omapdss.h
+++ b/include/video/omapdss.h
@@ -590,6 +590,11 @@ struct omap_dss_device {
int (*get_backlight)(struct omap_dss_device *dssdev);
};
+struct omap_dss_hdmi_data
+{
+ int hpd_gpio;
+};
+
struct omap_dss_driver {
struct device_driver driver;
--
1.7.4.1
^ permalink raw reply related
* [PATCH 5/6] OMAP: 4430SDP/Panda: add HDMI HPD gpio
From: Tomi Valkeinen @ 2012-01-17 12:49 UTC (permalink / raw)
To: linux-omap, linux-fbdev, mythripk; +Cc: archit, x0132446, Tomi Valkeinen
In-Reply-To: <1326804542-22285-1-git-send-email-tomi.valkeinen@ti.com>
Both Panda and 4430SDP use GPIO 64 as HDMI hot-plug-detect. Configure
this GPIO in the board files.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
arch/arm/mach-omap2/board-4430sdp.c | 3 +++
arch/arm/mach-omap2/board-omap4panda.c | 3 +++
2 files changed, 6 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c
index 5dcc8df..a776c26 100644
--- a/arch/arm/mach-omap2/board-4430sdp.c
+++ b/arch/arm/mach-omap2/board-4430sdp.c
@@ -54,6 +54,7 @@
#define OMAP4_SFH7741_ENABLE_GPIO 188
#define HDMI_GPIO_CT_CP_HPD 60 /* HPD mode enable/disable */
#define HDMI_GPIO_LS_OE 41 /* Level shifter for HDMI */
+#define HDMI_GPIO_HPD 63 /* Hotplug detect */
#define DISPLAY_SEL_GPIO 59 /* LCD2/PicoDLP switch */
#define DLP_POWER_ON_GPIO 40
@@ -598,6 +599,7 @@ static void __init omap_sfh7741prox_init(void)
static struct gpio sdp4430_hdmi_gpios[] = {
{ HDMI_GPIO_CT_CP_HPD, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ct_cp_hpd" },
{ HDMI_GPIO_LS_OE, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ls_oe" },
+ { HDMI_GPIO_HPD, GPIOF_DIR_IN, "hdmi_gpio_hpd" },
};
static int sdp4430_panel_enable_hdmi(struct omap_dss_device *dssdev)
@@ -836,6 +838,7 @@ static void omap_4430sdp_display_init(void)
omap_mux_init_gpio(HDMI_GPIO_LS_OE, OMAP_PIN_OUTPUT);
omap_mux_init_gpio(HDMI_GPIO_CT_CP_HPD, OMAP_PIN_OUTPUT);
+ omap_mux_init_gpio(HDMI_GPIO_HPD, OMAP_PIN_INPUT_PULLDOWN);
}
#ifdef CONFIG_OMAP_MUX
diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c
index 06a7075..b22a288 100644
--- a/arch/arm/mach-omap2/board-omap4panda.c
+++ b/arch/arm/mach-omap2/board-omap4panda.c
@@ -53,6 +53,7 @@
#define GPIO_WIFI_IRQ 53
#define HDMI_GPIO_CT_CP_HPD 60 /* HPD mode enable/disable */
#define HDMI_GPIO_LS_OE 41 /* Level shifter for HDMI */
+#define HDMI_GPIO_HPD 63 /* Hotplug detect */
/* wl127x BT, FM, GPS connectivity chip */
static int wl1271_gpios[] = {46, -1, -1};
@@ -481,6 +482,7 @@ int __init omap4_panda_dvi_init(void)
static struct gpio panda_hdmi_gpios[] = {
{ HDMI_GPIO_CT_CP_HPD, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ct_cp_hpd" },
{ HDMI_GPIO_LS_OE, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ls_oe" },
+ { HDMI_GPIO_HPD, GPIOF_DIR_IN, "hdmi_gpio_hpd" },
};
static int omap4_panda_panel_enable_hdmi(struct omap_dss_device *dssdev)
@@ -552,6 +554,7 @@ void omap4_panda_display_init(void)
omap_mux_init_gpio(HDMI_GPIO_LS_OE, OMAP_PIN_OUTPUT);
omap_mux_init_gpio(HDMI_GPIO_CT_CP_HPD, OMAP_PIN_OUTPUT);
+ omap_mux_init_gpio(HDMI_GPIO_HPD, OMAP_PIN_INPUT_PULLDOWN);
}
static void __init omap4_panda_init(void)
--
1.7.4.1
^ permalink raw reply related
* [PATCH 4/6] OMAP: 4430SDP/Panda: setup HDMI GPIO muxes
From: Tomi Valkeinen @ 2012-01-17 12:49 UTC (permalink / raw)
To: linux-omap, linux-fbdev, mythripk; +Cc: archit, x0132446, Tomi Valkeinen
In-Reply-To: <1326804542-22285-1-git-send-email-tomi.valkeinen@ti.com>
The HDMI GPIO pins LS_OE and CT_CP_HPD are not currently configured.
This patch configures them as output pins.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
arch/arm/mach-omap2/board-4430sdp.c | 3 +++
arch/arm/mach-omap2/board-omap4panda.c | 3 +++
2 files changed, 6 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c
index ae0c09f..5dcc8df 100644
--- a/arch/arm/mach-omap2/board-4430sdp.c
+++ b/arch/arm/mach-omap2/board-4430sdp.c
@@ -833,6 +833,9 @@ static void omap_4430sdp_display_init(void)
omap_hdmi_init(OMAP_HDMI_SDA_SCL_EXTERNAL_PULLUP);
else
omap_hdmi_init(0);
+
+ omap_mux_init_gpio(HDMI_GPIO_LS_OE, OMAP_PIN_OUTPUT);
+ omap_mux_init_gpio(HDMI_GPIO_CT_CP_HPD, OMAP_PIN_OUTPUT);
}
#ifdef CONFIG_OMAP_MUX
diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c
index 133b5a7..06a7075 100644
--- a/arch/arm/mach-omap2/board-omap4panda.c
+++ b/arch/arm/mach-omap2/board-omap4panda.c
@@ -549,6 +549,9 @@ void omap4_panda_display_init(void)
omap_hdmi_init(OMAP_HDMI_SDA_SCL_EXTERNAL_PULLUP);
else
omap_hdmi_init(0);
+
+ omap_mux_init_gpio(HDMI_GPIO_LS_OE, OMAP_PIN_OUTPUT);
+ omap_mux_init_gpio(HDMI_GPIO_CT_CP_HPD, OMAP_PIN_OUTPUT);
}
static void __init omap4_panda_init(void)
--
1.7.4.1
^ permalink raw reply related
* [PATCH 3/6] OMAPDSS: remove wrong HDMI HPD muxing
From: Tomi Valkeinen @ 2012-01-17 12:48 UTC (permalink / raw)
To: linux-omap, linux-fbdev, mythripk; +Cc: archit, x0132446, Tomi Valkeinen
In-Reply-To: <1326804542-22285-1-git-send-email-tomi.valkeinen@ti.com>
"hdmi_hpd" pin is muxed to INPUT and PULLUP, but the pin is not
currently used, and in the future when it is used, the pin is used as a
GPIO and is board specific, not an OMAP4 wide thing.
So remove the muxing for now.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
arch/arm/mach-omap2/display.c | 4 ----
1 files changed, 0 insertions(+), 4 deletions(-)
diff --git a/arch/arm/mach-omap2/display.c b/arch/arm/mach-omap2/display.c
index ffd9bd9..d6e65e2 100644
--- a/arch/arm/mach-omap2/display.c
+++ b/arch/arm/mach-omap2/display.c
@@ -102,12 +102,8 @@ static void omap4_hdmi_mux_pads(enum omap_hdmi_flags flags)
u32 reg;
u16 control_i2c_1;
- /* PAD0_HDMI_HPD_PAD1_HDMI_CEC */
- omap_mux_init_signal("hdmi_hpd",
- OMAP_PIN_INPUT_PULLUP);
omap_mux_init_signal("hdmi_cec",
OMAP_PIN_INPUT_PULLUP);
- /* PAD0_HDMI_DDC_SCL_PAD1_HDMI_DDC_SDA */
omap_mux_init_signal("hdmi_ddc_scl",
OMAP_PIN_INPUT_PULLUP);
omap_mux_init_signal("hdmi_ddc_sda",
--
1.7.4.1
^ permalink raw reply related
* [PATCH 2/6] OMAP: 4430SDP/Panda: rename HPD GPIO to CT_CP_HPD
From: Tomi Valkeinen @ 2012-01-17 12:48 UTC (permalink / raw)
To: linux-fbdev
The GPIO 60 on 4430sdp and Panda is not HPD GPIO, as currently marked in
the board files, but CT_CP_HPD, which is used to enable/disable HPD
functionality.
This patch renames the GPIO.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
arch/arm/mach-omap2/board-4430sdp.c | 4 ++--
arch/arm/mach-omap2/board-omap4panda.c | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c
index d7017f2..ae0c09f 100644
--- a/arch/arm/mach-omap2/board-4430sdp.c
+++ b/arch/arm/mach-omap2/board-4430sdp.c
@@ -52,7 +52,7 @@
#define ETH_KS8851_QUART 138
#define OMAP4_SFH7741_SENSOR_OUTPUT_GPIO 184
#define OMAP4_SFH7741_ENABLE_GPIO 188
-#define HDMI_GPIO_HPD 60 /* Hot plug pin for HDMI */
+#define HDMI_GPIO_CT_CP_HPD 60 /* HPD mode enable/disable */
#define HDMI_GPIO_LS_OE 41 /* Level shifter for HDMI */
#define DISPLAY_SEL_GPIO 59 /* LCD2/PicoDLP switch */
#define DLP_POWER_ON_GPIO 40
@@ -596,7 +596,7 @@ static void __init omap_sfh7741prox_init(void)
}
static struct gpio sdp4430_hdmi_gpios[] = {
- { HDMI_GPIO_HPD, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_hpd" },
+ { HDMI_GPIO_CT_CP_HPD, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ct_cp_hpd" },
{ HDMI_GPIO_LS_OE, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ls_oe" },
};
diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c
index b9f90ba..133b5a7 100644
--- a/arch/arm/mach-omap2/board-omap4panda.c
+++ b/arch/arm/mach-omap2/board-omap4panda.c
@@ -51,7 +51,7 @@
#define GPIO_HUB_NRESET 62
#define GPIO_WIFI_PMENA 43
#define GPIO_WIFI_IRQ 53
-#define HDMI_GPIO_HPD 60 /* Hot plug pin for HDMI */
+#define HDMI_GPIO_CT_CP_HPD 60 /* HPD mode enable/disable */
#define HDMI_GPIO_LS_OE 41 /* Level shifter for HDMI */
/* wl127x BT, FM, GPS connectivity chip */
@@ -479,7 +479,7 @@ int __init omap4_panda_dvi_init(void)
}
static struct gpio panda_hdmi_gpios[] = {
- { HDMI_GPIO_HPD, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_hpd" },
+ { HDMI_GPIO_CT_CP_HPD, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ct_cp_hpd" },
{ HDMI_GPIO_LS_OE, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ls_oe" },
};
--
1.7.4.1
^ permalink raw reply related
* [PATCH 1/6] OMAP: 4430SDP/Panda: use gpio_free_array to free HDMI gpios
From: Tomi Valkeinen @ 2012-01-17 12:48 UTC (permalink / raw)
To: linux-omap, linux-fbdev, mythripk; +Cc: archit, x0132446, Tomi Valkeinen
In-Reply-To: <1326804542-22285-1-git-send-email-tomi.valkeinen@ti.com>
Instead of freeing the GPIOs individually, use gpio_free_array().
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
---
arch/arm/mach-omap2/board-4430sdp.c | 3 +--
arch/arm/mach-omap2/board-omap4panda.c | 3 +--
2 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c
index 4af874a..d7017f2 100644
--- a/arch/arm/mach-omap2/board-4430sdp.c
+++ b/arch/arm/mach-omap2/board-4430sdp.c
@@ -614,8 +614,7 @@ static int sdp4430_panel_enable_hdmi(struct omap_dss_device *dssdev)
static void sdp4430_panel_disable_hdmi(struct omap_dss_device *dssdev)
{
- gpio_free(HDMI_GPIO_LS_OE);
- gpio_free(HDMI_GPIO_HPD);
+ gpio_free_array(sdp4430_hdmi_gpios, ARRAY_SIZE(sdp4430_hdmi_gpios));
}
static struct nokia_dsi_panel_data dsi1_panel = {
diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c
index 00103e3..b9f90ba 100644
--- a/arch/arm/mach-omap2/board-omap4panda.c
+++ b/arch/arm/mach-omap2/board-omap4panda.c
@@ -497,8 +497,7 @@ static int omap4_panda_panel_enable_hdmi(struct omap_dss_device *dssdev)
static void omap4_panda_panel_disable_hdmi(struct omap_dss_device *dssdev)
{
- gpio_free(HDMI_GPIO_LS_OE);
- gpio_free(HDMI_GPIO_HPD);
+ gpio_free_array(panda_hdmi_gpios, ARRAY_SIZE(panda_hdmi_gpios));
}
static struct omap_dss_device omap4_panda_hdmi_device = {
--
1.7.4.1
^ permalink raw reply related
* [PATCH 0/6] OMAPDSS: HDMI PHY burnout fix
From: Tomi Valkeinen @ 2012-01-17 12:48 UTC (permalink / raw)
To: linux-omap, linux-fbdev, mythripk; +Cc: archit, x0132446, Tomi Valkeinen
The main patch in this set is the last one, which implements a fix for the HW
bug on OMAP4 which causes physical damage to the board if the HDMI cable is not
connected but HDMI output is enabled.
The preceding patches are small cleanups/fixes for HDMI GPIOs so that the fix
can be implemented.
Note that I haven't gotten a confirmation that using LDO_ON for the HDMI PHY
power fixes the issue. So whether the fix works or not is unclear.
Tomi
Tomi Valkeinen (6):
OMAP: 4430SDP/Panda: use gpio_free_array to free HDMI gpios
OMAP: 4430SDP/Panda: rename HPD GPIO to CT_CP_HPD
OMAPDSS: remove wrong HDMI HPD muxing
OMAP: 4430SDP/Panda: setup HDMI GPIO muxes
OMAP: 4430SDP/Panda: add HDMI HPD gpio
OMAPDSS: HDMI: PHY burnout fix
arch/arm/mach-omap2/board-4430sdp.c | 18 ++++++--
arch/arm/mach-omap2/board-omap4panda.c | 18 ++++++--
arch/arm/mach-omap2/display.c | 4 --
drivers/video/omap2/dss/hdmi.c | 3 +
drivers/video/omap2/dss/ti_hdmi.h | 4 ++
drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c | 68 +++++++++++++++++++++++++++--
include/video/omapdss.h | 5 ++
7 files changed, 104 insertions(+), 16 deletions(-)
--
1.7.4.1
^ permalink raw reply
* Re: [PATCH] video: s3c-fb: Add device tree support
From: Thomas Abraham @ 2012-01-17 5:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <4F10A267.2020608@gmail.com>
Hi Sylwester,
On 14 January 2012 03:00, Sylwester Nawrocki <snjw23@gmail.com> wrote:
> On 01/13/2012 10:03 PM, Sylwester Nawrocki wrote:
>> On 01/09/2012 09:01 PM, Thomas Abraham wrote:
>>>
>>> + for (idx = 0; idx< nr_gpios; idx++) {
>>> + gpio = of_get_gpio(dev->of_node, idx);
>>> + if (!gpio_is_valid(gpio)) {
>>> + dev_err(dev, "invalid gpio[%d]: %d\n", idx, gpio);
>>> + return -EINVAL;
>>> + }
>>> +
>>> + if (!request)
>>> + continue;
>>> +
>>> + ret = gpio_request(gpio, "fimd");
>>
>> Is it how it normally is supposed to be done, i.e. configuring a gpio
>> _before_ it has been requested ? of_get_gpio() indirectly touches the
>> gpio controller and gpio_request() doesn't seem to serve its purpose
>> in this case, i.e. if there is situation like:
>>
>> driver A driver B
>>
>> of_get_gpio(nodeA, gpioA);
>> of_get_gpio(nodeB, gpioA);
>> gpio_request(gpioA);
>> gpio_request(gpioB);
> s/B/A
>>
>> driver B will end up with configuration of gpioA from nodeA, not from
>> nodeB.
>
> ugh, I put it wrong, it should instead read:
>
> "driver A will end up with configuration of gpioA from nodeB, not from
> nodeA."
>
>> As there are few drivers doing that I must be missing something,
>> not sure what..
>> I realize the GPIO number needs to be known in order for a GPIO to be
>> requested. Shouldn't of_get_gpio() be extended to allow locking gpio
>> controller's module and marking a GPIO as requested in advance ?
>>
>>> + if (ret) {
>>> + dev_err(dev, "gpio [%d] request failed\n", gpio);
>>> + goto gpio_free;
>>> + }
>>> + sfb->gpios[idx] = gpio;
>>> + }
>>> + return 0;
>>> +
>>> +gpio_free:
>>> + while (--idx>= 0)
>>> + gpio_free(sfb->gpios[idx]);
>>> + return ret;
>>> +}
>>> +
>>> +static void s3c_fb_dt_free_gpios(struct s3c_fb *sfb)
>>> +{
>>> + unsigned int idx, nr_gpio;
>>> +
>>> + nr_gpio = sfb->pdata->win[0]->max_bpp + 4;
>>> + for (idx = 0; idx< nr_gpio; idx++)
>>> + gpio_free(sfb->gpios[idx]);
>>> +}
>
Yes, I agree that there is a problem here. DT bindings for
pinmux/pinconfig would solve this. But the sequence of of_get_gpio()
and gpio_request() in the above code will stay even when using the dt
bindings for pinmux/pinconfig. There will be only incremental changes
required to adapt to dt bindings for pinmux/pinconfig.
Thanks,
Thomas.
^ permalink raw reply
* Re: [PATCH] drivers/video: compile fixes for fsl-diu-fb.c
From: Timur Tabi @ 2012-01-16 16:12 UTC (permalink / raw)
To: Michael Neuling, Florian Tobias Schandinat
Cc: linuxppc-dev@ozlabs.org, linux-fbdev@vger.kernel.org
In-Reply-To: <21370.1326683320@neuling.org>
Michael Neuling wrote:
> From: Michael Neuling <mikey@neuling.org>
>
> [PATCH] drivers/video: compile fixes for fsl-diu-fb.c
>
> Fix a compiler errors introduced in:
> commit ddd3d905436b572ebadc09dcf2d12ca5b37020a0
> Author: Timur Tabi <timur@freescale.com>
> drivers/video: fsl-diu-fb: merge all allocated data into one block
>
> Signed-off-by: Michael Neuling <mikey@neuling.org>
Acked-by: Timur Tabi <timur@freescale.com>
--
Timur Tabi
Linux kernel developer at Freescale
^ permalink raw reply
* Re: [PATCH] drivers/video: compile fixes for fsl-diu-fb.c
From: Timur Tabi @ 2012-01-16 16:12 UTC (permalink / raw)
To: Michael Neuling
Cc: linuxppc-dev@ozlabs.org, linux-fbdev@vger.kernel.org,
Florian Tobias Schandinat
In-Reply-To: <21370.1326683320@neuling.org>
Michael Neuling wrote:
> drivers/video/fsl-diu-fb.c: In function 'fsl_diu_suspend':
> drivers/video/fsl-diu-fb.c:1435: error: incompatible type for argument 1 of 'disable_lcdc'
> drivers/video/fsl-diu-fb.c:592: note: expected 'struct fb_info *' but argument is of type 'struct fb_info'
> drivers/video/fsl-diu-fb.c: In function 'fsl_diu_resume':
> drivers/video/fsl-diu-fb.c:1445: error: incompatible type for argument 1 of 'enable_lcdc'
> drivers/video/fsl-diu-fb.c:583: note: expected 'struct fb_info *' but argument is of type 'struct fb_info'
I figured out what the problem is. I never compiled a configuration with
CONFIG_PM enabled. For some reason, CONFIG_PM is disabled when SMP is
enabled, and I only tested with mpc85xx_smp_defconfig.
--
Timur Tabi
Linux kernel developer at Freescale
^ permalink raw reply
* Re: [PATCH 5/6] OMAPDSS: DISPC: move fifo threhold calc to dispc.c
From: Archit @ 2012-01-16 10:11 UTC (permalink / raw)
To: Tomi Valkeinen; +Cc: linux-omap, linux-fbdev, archit, rob
In-Reply-To: <1326707861.1875.1.camel@deskari>
On Monday 16 January 2012 03:27 PM, Tomi Valkeinen wrote:
> On Sat, 2012-01-14 at 01:30 +0530, Archit wrote:
>> Hi,
>>
>> On Friday 13 January 2012 05:16 PM, Tomi Valkeinen wrote:
>>> Move fifo threshold calculation into dispc.c, as the thresholds are
>>> really dispc internal thing.
>>>
>>> Signed-off-by: Tomi Valkeinen<tomi.valkeinen@ti.com>
>>
>> <snip>
>>
>>> diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
>>> index 511ae2a..1cbb7a5 100644
>>> --- a/drivers/video/omap2/dss/dsi.c
>>> +++ b/drivers/video/omap2/dss/dsi.c
>>> @@ -4524,14 +4524,6 @@ int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable)
>>> }
>>> EXPORT_SYMBOL(omapdss_dsi_enable_te);
>>>
>>> -void dsi_get_overlay_fifo_thresholds(enum omap_plane plane,
>>> - u32 fifo_size, u32 burst_size,
>>> - u32 *fifo_low, u32 *fifo_high)
>>> -{
>>> - *fifo_high = fifo_size - burst_size;
>>> - *fifo_low = fifo_size - burst_size * 2;
>>> -}
>>
>> We are removing the special treatment for overlays connected to DSI done
>> before. Won't this cause the issues you saw with DSI in OMAP3?
>
> That's true. I had it in mind at some point, but I seem to have
> forgotten it.
>
> The problem with OMAP3, DSI and fifo thresholds was never cleared, and I
> haven't seen an errata about it, so there's a slim chance that it was
> only a problem with the particular setup.
>
> Are you back at the office yet? If I recall right, you had an OMAP3 DSI
> cmd mode board?
Not yet, I'll try it out when I get back.
>
> Anyway, I guess it's safest if I add a hack there, which tunes the
> thresholds a bit differently for OMAP3 DSI.
Yes, you could have that, we have to rewrite the whole threshold
calculation later on anyway.
Archit
>
> Tomi
>
^ permalink raw reply
* Re: [PATCH 5/6] OMAPDSS: DISPC: move fifo threhold calc to dispc.c
From: Tomi Valkeinen @ 2012-01-16 9:57 UTC (permalink / raw)
To: Archit; +Cc: linux-omap, linux-fbdev, archit, rob
In-Reply-To: <4F108D7A.4010802@ti.com>
[-- Attachment #1: Type: text/plain, Size: 1553 bytes --]
On Sat, 2012-01-14 at 01:30 +0530, Archit wrote:
> Hi,
>
> On Friday 13 January 2012 05:16 PM, Tomi Valkeinen wrote:
> > Move fifo threshold calculation into dispc.c, as the thresholds are
> > really dispc internal thing.
> >
> > Signed-off-by: Tomi Valkeinen<tomi.valkeinen@ti.com>
>
> <snip>
>
> > diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
> > index 511ae2a..1cbb7a5 100644
> > --- a/drivers/video/omap2/dss/dsi.c
> > +++ b/drivers/video/omap2/dss/dsi.c
> > @@ -4524,14 +4524,6 @@ int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable)
> > }
> > EXPORT_SYMBOL(omapdss_dsi_enable_te);
> >
> > -void dsi_get_overlay_fifo_thresholds(enum omap_plane plane,
> > - u32 fifo_size, u32 burst_size,
> > - u32 *fifo_low, u32 *fifo_high)
> > -{
> > - *fifo_high = fifo_size - burst_size;
> > - *fifo_low = fifo_size - burst_size * 2;
> > -}
>
> We are removing the special treatment for overlays connected to DSI done
> before. Won't this cause the issues you saw with DSI in OMAP3?
That's true. I had it in mind at some point, but I seem to have
forgotten it.
The problem with OMAP3, DSI and fifo thresholds was never cleared, and I
haven't seen an errata about it, so there's a slim chance that it was
only a problem with the particular setup.
Are you back at the office yet? If I recall right, you had an OMAP3 DSI
cmd mode board?
Anyway, I guess it's safest if I add a hack there, which tunes the
thresholds a bit differently for OMAP3 DSI.
Tomi
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* Re: [PATCH] drivers/video: compile fixes for fsl-diu-fb.c
From: Michael Neuling @ 2012-01-16 3:08 UTC (permalink / raw)
To: Tabi Timur-B04825
Cc: linuxppc-dev@ozlabs.org, linux-fbdev@vger.kernel.org,
Florian Tobias Schandinat
In-Reply-To: <4F138CBB.1080901@freescale.com>
In message <4F138CBB.1080901@freescale.com> you wrote:
> Michael Neuling wrote:
> > In message<4F1370C9.9010400@freescale.com> you wrote:
> >> Michael Neuling wrote:
> >>> Fix a bunch of compiler errors and warnings introduced in:
> >>> commit ddd3d905436b572ebadc09dcf2d12ca5b37020a0
> >>> Author: Timur Tabi<timur@freescale.com>
> >>> drivers/video: fsl-diu-fb: merge all allocated data into one block
> >>>
> >>> Signed-off-by: Michael Neuling<mikey@neuling.org>
> >>> ---
> >>> Timur: you do compile test your patches, right? :-P
> >>
> >> I have a script that tests each commit in a set to make sure it compiles> ,
> >> so that git-bisect isn't broken.
> >
> > May I suggest you actually run the script next time :-P
>
> Tomorrow, when I get into the office, I'll take a look. But my code has
> always compiled. Can you give me the output of your compiler?
drivers/video/fsl-diu-fb.c: In function 'fsl_diu_suspend':
drivers/video/fsl-diu-fb.c:1435: error: incompatible type for argument 1 of 'disable_lcdc'
drivers/video/fsl-diu-fb.c:592: note: expected 'struct fb_info *' but argument is of type 'struct fb_info'
drivers/video/fsl-diu-fb.c: In function 'fsl_diu_resume':
drivers/video/fsl-diu-fb.c:1445: error: incompatible type for argument 1 of 'enable_lcdc'
drivers/video/fsl-diu-fb.c:583: note: expected 'struct fb_info *' but argument is of type 'struct fb_info'
>
> > diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
> > index acf292b..3006b2b 100644
> > --- a/drivers/video/fsl-diu-fb.c
> > +++ b/drivers/video/fsl-diu-fb.c
> > @@ -1432,7 +1432,7 @@ static int fsl_diu_suspend(struct platform_device *> ofdev, pm_message_t state)
> > struct fsl_diu_data *data;
> >
> > data = dev_get_drvdata(&ofdev->dev);
> > - disable_lcdc(data->fsl_diu_info[0]);
> > + disable_lcdc(&(data->fsl_diu_info[0]));
> >
> > return 0;
> > }
> > @@ -1442,7 +1442,7 @@ static int fsl_diu_resume(struct platform_device *o> fdev)
> > struct fsl_diu_data *data;
> >
> > data = dev_get_drvdata(&ofdev->dev);
> > - enable_lcdc(data->fsl_diu_info[0]);
> > + enable_lcdc(&(data->fsl_diu_info[0]));
>
> I prefer this:
>
> disable_lcdc(data->fsl_diu_info);
>
> Your change makes sense. I don't understand why it compiles on my system.
> Something strange is going on.
Sure.
Mikey
From: Michael Neuling <mikey@neuling.org>
[PATCH] drivers/video: compile fixes for fsl-diu-fb.c
Fix a compiler errors introduced in:
commit ddd3d905436b572ebadc09dcf2d12ca5b37020a0
Author: Timur Tabi <timur@freescale.com>
drivers/video: fsl-diu-fb: merge all allocated data into one block
Signed-off-by: Michael Neuling <mikey@neuling.org>
diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
index acf292b..6af3f16 100644
--- a/drivers/video/fsl-diu-fb.c
+++ b/drivers/video/fsl-diu-fb.c
@@ -1432,7 +1432,7 @@ static int fsl_diu_suspend(struct platform_device *ofdev, pm_message_t state)
struct fsl_diu_data *data;
data = dev_get_drvdata(&ofdev->dev);
- disable_lcdc(data->fsl_diu_info[0]);
+ disable_lcdc(data->fsl_diu_info);
return 0;
}
@@ -1442,7 +1442,7 @@ static int fsl_diu_resume(struct platform_device *ofdev)
struct fsl_diu_data *data;
data = dev_get_drvdata(&ofdev->dev);
- enable_lcdc(data->fsl_diu_info[0]);
+ enable_lcdc(data->fsl_diu_info);
return 0;
}
^ permalink raw reply related
* Re: [PATCH] drivers/video: compile fixes for fsl-diu-fb.c
From: Tabi Timur-B04825 @ 2012-01-16 2:34 UTC (permalink / raw)
To: Michael Neuling
Cc: linuxppc-dev@ozlabs.org, linux-fbdev@vger.kernel.org,
Florian Tobias Schandinat
In-Reply-To: <21913.1326675139@neuling.org>
Michael Neuling wrote:
> In message<4F1370C9.9010400@freescale.com> you wrote:
>> Michael Neuling wrote:
>>> Fix a bunch of compiler errors and warnings introduced in:
>>> commit ddd3d905436b572ebadc09dcf2d12ca5b37020a0
>>> Author: Timur Tabi<timur@freescale.com>
>>> drivers/video: fsl-diu-fb: merge all allocated data into one block
>>>
>>> Signed-off-by: Michael Neuling<mikey@neuling.org>
>>> ---
>>> Timur: you do compile test your patches, right? :-P
>>
>> I have a script that tests each commit in a set to make sure it compiles,
>> so that git-bisect isn't broken.
>
> May I suggest you actually run the script next time :-P
Tomorrow, when I get into the office, I'll take a look. But my code has
always compiled. Can you give me the output of your compiler?
> diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
> index acf292b..3006b2b 100644
> --- a/drivers/video/fsl-diu-fb.c
> +++ b/drivers/video/fsl-diu-fb.c
> @@ -1432,7 +1432,7 @@ static int fsl_diu_suspend(struct platform_device *ofdev, pm_message_t state)
> struct fsl_diu_data *data;
>
> data = dev_get_drvdata(&ofdev->dev);
> - disable_lcdc(data->fsl_diu_info[0]);
> + disable_lcdc(&(data->fsl_diu_info[0]));
>
> return 0;
> }
> @@ -1442,7 +1442,7 @@ static int fsl_diu_resume(struct platform_device *ofdev)
> struct fsl_diu_data *data;
>
> data = dev_get_drvdata(&ofdev->dev);
> - enable_lcdc(data->fsl_diu_info[0]);
> + enable_lcdc(&(data->fsl_diu_info[0]));
I prefer this:
disable_lcdc(data->fsl_diu_info);
Your change makes sense. I don't understand why it compiles on my system.
Something strange is going on.
--
Timur Tabi
Linux kernel developer at Freescale
^ permalink raw reply
* Re: [PATCH] drivers/video: compile fixes for fsl-diu-fb.c
From: Michael Neuling @ 2012-01-16 0:52 UTC (permalink / raw)
To: Tabi Timur-B04825
Cc: linuxppc-dev@ozlabs.org, linux-fbdev@vger.kernel.org,
Florian Tobias Schandinat
In-Reply-To: <4F1370C9.9010400@freescale.com>
In message <4F1370C9.9010400@freescale.com> you wrote:
> Michael Neuling wrote:
> > Fix a bunch of compiler errors and warnings introduced in:
> > commit ddd3d905436b572ebadc09dcf2d12ca5b37020a0
> > Author: Timur Tabi<timur@freescale.com>
> > drivers/video: fsl-diu-fb: merge all allocated data into one block
> >
> > Signed-off-by: Michael Neuling<mikey@neuling.org>
> > ---
> > Timur: you do compile test your patches, right? :-P
>
> I have a script that tests each commit in a set to make sure it compiles,
> so that git-bisect isn't broken.
May I suggest you actually run the script next time :-P
> > This is effecting mpc85xx_defconfig on mainline (and has been in
> > linux-next for while already).
> >
> > diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
> > index acf292b..78cac52 100644
> > --- a/drivers/video/fsl-diu-fb.c
> > +++ b/drivers/video/fsl-diu-fb.c
> > @@ -366,7 +366,7 @@ struct mfb_info {
> > */
> > struct fsl_diu_data {
> > dma_addr_t dma_addr;
> > - struct fb_info fsl_diu_info[NUM_AOIS];
> > + struct fb_info *fsl_diu_info[NUM_AOIS];
>
> This doesn't make any sense. If you change fsl_diu_info into a pointer,
> then where is the object being allocated?
OK, how about this?
From: Michael Neuling <mikey@neuling.org>
[PATCH] drivers/video: compile fixes for fsl-diu-fb.c
Fix a compiler errors introduced in:
commit ddd3d905436b572ebadc09dcf2d12ca5b37020a0
Author: Timur Tabi <timur@freescale.com>
drivers/video: fsl-diu-fb: merge all allocated data into one block
Signed-off-by: Michael Neuling <mikey@neuling.org>
diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
index acf292b..3006b2b 100644
--- a/drivers/video/fsl-diu-fb.c
+++ b/drivers/video/fsl-diu-fb.c
@@ -1432,7 +1432,7 @@ static int fsl_diu_suspend(struct platform_device *ofdev, pm_message_t state)
struct fsl_diu_data *data;
data = dev_get_drvdata(&ofdev->dev);
- disable_lcdc(data->fsl_diu_info[0]);
+ disable_lcdc(&(data->fsl_diu_info[0]));
return 0;
}
@@ -1442,7 +1442,7 @@ static int fsl_diu_resume(struct platform_device *ofdev)
struct fsl_diu_data *data;
data = dev_get_drvdata(&ofdev->dev);
- enable_lcdc(data->fsl_diu_info[0]);
+ enable_lcdc(&(data->fsl_diu_info[0]));
return 0;
}
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox