aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/fbdev/exynos
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/fbdev/exynos')
-rw-r--r--drivers/video/fbdev/exynos/Kconfig32
-rw-r--r--drivers/video/fbdev/exynos/Makefile7
-rw-r--r--drivers/video/fbdev/exynos/exynos_mipi_dsi.c574
-rw-r--r--drivers/video/fbdev/exynos/exynos_mipi_dsi_common.c880
-rw-r--r--drivers/video/fbdev/exynos/exynos_mipi_dsi_common.h46
-rw-r--r--drivers/video/fbdev/exynos/exynos_mipi_dsi_lowlevel.c618
-rw-r--r--drivers/video/fbdev/exynos/exynos_mipi_dsi_lowlevel.h112
-rw-r--r--drivers/video/fbdev/exynos/exynos_mipi_dsi_regs.h149
-rw-r--r--drivers/video/fbdev/exynos/s6e8ax0.c898
9 files changed, 3316 insertions, 0 deletions
diff --git a/drivers/video/fbdev/exynos/Kconfig b/drivers/video/fbdev/exynos/Kconfig
new file mode 100644
index 000000000000..fcf2d48ac6d1
--- /dev/null
+++ b/drivers/video/fbdev/exynos/Kconfig
@@ -0,0 +1,32 @@
1#
2# Exynos Video configuration
3#
4
5menuconfig EXYNOS_VIDEO
6 bool "Exynos Video driver support"
7 help
8 This enables support for EXYNOS Video device.
9
10if EXYNOS_VIDEO
11
12#
13# MIPI DSI driver
14#
15
16config EXYNOS_MIPI_DSI
17 bool "EXYNOS MIPI DSI driver support."
18 depends on ARCH_S5PV210 || ARCH_EXYNOS
19 select GENERIC_PHY
20 help
21 This enables support for MIPI-DSI device.
22
23config EXYNOS_LCD_S6E8AX0
24 bool "S6E8AX0 MIPI AMOLED LCD Driver"
25 depends on EXYNOS_MIPI_DSI && BACKLIGHT_CLASS_DEVICE
26 depends on (LCD_CLASS_DEVICE = y)
27 default n
28 help
29 If you have an S6E8AX0 MIPI AMOLED LCD Panel, say Y to enable its
30 LCD control driver.
31
32endif # EXYNOS_VIDEO
diff --git a/drivers/video/fbdev/exynos/Makefile b/drivers/video/fbdev/exynos/Makefile
new file mode 100644
index 000000000000..b5b1bd228abb
--- /dev/null
+++ b/drivers/video/fbdev/exynos/Makefile
@@ -0,0 +1,7 @@
1#
2# Makefile for the exynos video drivers.
3#
4
5obj-$(CONFIG_EXYNOS_MIPI_DSI) += exynos_mipi_dsi.o exynos_mipi_dsi_common.o \
6 exynos_mipi_dsi_lowlevel.o
7obj-$(CONFIG_EXYNOS_LCD_S6E8AX0) += s6e8ax0.o
diff --git a/drivers/video/fbdev/exynos/exynos_mipi_dsi.c b/drivers/video/fbdev/exynos/exynos_mipi_dsi.c
new file mode 100644
index 000000000000..cee9602f9a7b
--- /dev/null
+++ b/drivers/video/fbdev/exynos/exynos_mipi_dsi.c
@@ -0,0 +1,574 @@
1/* linux/drivers/video/exynos/exynos_mipi_dsi.c
2 *
3 * Samsung SoC MIPI-DSIM driver.
4 *
5 * Copyright (c) 2012 Samsung Electronics Co., Ltd
6 *
7 * InKi Dae, <inki.dae@samsung.com>
8 * Donghwa Lee, <dh09.lee@samsung.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13*/
14
15#include <linux/module.h>
16#include <linux/kernel.h>
17#include <linux/errno.h>
18#include <linux/clk.h>
19#include <linux/mutex.h>
20#include <linux/wait.h>
21#include <linux/fs.h>
22#include <linux/mm.h>
23#include <linux/fb.h>
24#include <linux/ctype.h>
25#include <linux/platform_device.h>
26#include <linux/io.h>
27#include <linux/irq.h>
28#include <linux/memory.h>
29#include <linux/delay.h>
30#include <linux/interrupt.h>
31#include <linux/kthread.h>
32#include <linux/notifier.h>
33#include <linux/phy/phy.h>
34#include <linux/regulator/consumer.h>
35#include <linux/pm_runtime.h>
36#include <linux/err.h>
37
38#include <video/exynos_mipi_dsim.h>
39
40#include "exynos_mipi_dsi_common.h"
41#include "exynos_mipi_dsi_lowlevel.h"
42
43struct mipi_dsim_ddi {
44 int bus_id;
45 struct list_head list;
46 struct mipi_dsim_lcd_device *dsim_lcd_dev;
47 struct mipi_dsim_lcd_driver *dsim_lcd_drv;
48};
49
50static LIST_HEAD(dsim_ddi_list);
51
52static DEFINE_MUTEX(mipi_dsim_lock);
53
54static struct mipi_dsim_platform_data *to_dsim_plat(struct platform_device
55 *pdev)
56{
57 return pdev->dev.platform_data;
58}
59
60static struct regulator_bulk_data supplies[] = {
61 { .supply = "vdd11", },
62 { .supply = "vdd18", },
63};
64
65static int exynos_mipi_regulator_enable(struct mipi_dsim_device *dsim)
66{
67 int ret;
68
69 mutex_lock(&dsim->lock);
70 ret = regulator_bulk_enable(ARRAY_SIZE(supplies), supplies);
71 mutex_unlock(&dsim->lock);
72
73 return ret;
74}
75
76static int exynos_mipi_regulator_disable(struct mipi_dsim_device *dsim)
77{
78 int ret;
79
80 mutex_lock(&dsim->lock);
81 ret = regulator_bulk_disable(ARRAY_SIZE(supplies), supplies);
82 mutex_unlock(&dsim->lock);
83
84 return ret;
85}
86
87/* update all register settings to MIPI DSI controller. */
88static void exynos_mipi_update_cfg(struct mipi_dsim_device *dsim)
89{
90 /*
91 * data from Display controller(FIMD) is not transferred in video mode
92 * but in case of command mode, all settings is not updated to
93 * registers.
94 */
95 exynos_mipi_dsi_stand_by(dsim, 0);
96
97 exynos_mipi_dsi_init_dsim(dsim);
98 exynos_mipi_dsi_init_link(dsim);
99
100 exynos_mipi_dsi_set_hs_enable(dsim);
101
102 /* set display timing. */
103 exynos_mipi_dsi_set_display_mode(dsim, dsim->dsim_config);
104
105 exynos_mipi_dsi_init_interrupt(dsim);
106
107 /*
108 * data from Display controller(FIMD) is transferred in video mode
109 * but in case of command mode, all settings are updated to registers.
110 */
111 exynos_mipi_dsi_stand_by(dsim, 1);
112}
113
114static int exynos_mipi_dsi_early_blank_mode(struct mipi_dsim_device *dsim,
115 int power)
116{
117 struct mipi_dsim_lcd_driver *client_drv = dsim->dsim_lcd_drv;
118 struct mipi_dsim_lcd_device *client_dev = dsim->dsim_lcd_dev;
119
120 switch (power) {
121 case FB_BLANK_POWERDOWN:
122 if (dsim->suspended)
123 return 0;
124
125 if (client_drv && client_drv->suspend)
126 client_drv->suspend(client_dev);
127
128 clk_disable(dsim->clock);
129
130 exynos_mipi_regulator_disable(dsim);
131
132 dsim->suspended = true;
133
134 break;
135 default:
136 break;
137 }
138
139 return 0;
140}
141
142static int exynos_mipi_dsi_blank_mode(struct mipi_dsim_device *dsim, int power)
143{
144 struct mipi_dsim_lcd_driver *client_drv = dsim->dsim_lcd_drv;
145 struct mipi_dsim_lcd_device *client_dev = dsim->dsim_lcd_dev;
146
147 switch (power) {
148 case FB_BLANK_UNBLANK:
149 if (!dsim->suspended)
150 return 0;
151
152 /* lcd panel power on. */
153 if (client_drv && client_drv->power_on)
154 client_drv->power_on(client_dev, 1);
155
156 exynos_mipi_regulator_enable(dsim);
157
158 /* enable MIPI-DSI PHY. */
159 phy_power_on(dsim->phy);
160
161 clk_enable(dsim->clock);
162
163 exynos_mipi_update_cfg(dsim);
164
165 /* set lcd panel sequence commands. */
166 if (client_drv && client_drv->set_sequence)
167 client_drv->set_sequence(client_dev);
168
169 dsim->suspended = false;
170
171 break;
172 case FB_BLANK_NORMAL:
173 /* TODO. */
174 break;
175 default:
176 break;
177 }
178
179 return 0;
180}
181
182int exynos_mipi_dsi_register_lcd_device(struct mipi_dsim_lcd_device *lcd_dev)
183{
184 struct mipi_dsim_ddi *dsim_ddi;
185
186 if (!lcd_dev->name) {
187 pr_err("dsim_lcd_device name is NULL.\n");
188 return -EFAULT;
189 }
190
191 dsim_ddi = kzalloc(sizeof(struct mipi_dsim_ddi), GFP_KERNEL);
192 if (!dsim_ddi) {
193 pr_err("failed to allocate dsim_ddi object.\n");
194 return -ENOMEM;
195 }
196
197 dsim_ddi->dsim_lcd_dev = lcd_dev;
198
199 mutex_lock(&mipi_dsim_lock);
200 list_add_tail(&dsim_ddi->list, &dsim_ddi_list);
201 mutex_unlock(&mipi_dsim_lock);
202
203 return 0;
204}
205
206static struct mipi_dsim_ddi *exynos_mipi_dsi_find_lcd_device(
207 struct mipi_dsim_lcd_driver *lcd_drv)
208{
209 struct mipi_dsim_ddi *dsim_ddi, *next;
210 struct mipi_dsim_lcd_device *lcd_dev;
211
212 mutex_lock(&mipi_dsim_lock);
213
214 list_for_each_entry_safe(dsim_ddi, next, &dsim_ddi_list, list) {
215 if (!dsim_ddi)
216 goto out;
217
218 lcd_dev = dsim_ddi->dsim_lcd_dev;
219 if (!lcd_dev)
220 continue;
221
222 if ((strcmp(lcd_drv->name, lcd_dev->name)) == 0) {
223 /**
224 * bus_id would be used to identify
225 * connected bus.
226 */
227 dsim_ddi->bus_id = lcd_dev->bus_id;
228 mutex_unlock(&mipi_dsim_lock);
229
230 return dsim_ddi;
231 }
232
233 list_del(&dsim_ddi->list);
234 kfree(dsim_ddi);
235 }
236
237out:
238 mutex_unlock(&mipi_dsim_lock);
239
240 return NULL;
241}
242
243int exynos_mipi_dsi_register_lcd_driver(struct mipi_dsim_lcd_driver *lcd_drv)
244{
245 struct mipi_dsim_ddi *dsim_ddi;
246
247 if (!lcd_drv->name) {
248 pr_err("dsim_lcd_driver name is NULL.\n");
249 return -EFAULT;
250 }
251
252 dsim_ddi = exynos_mipi_dsi_find_lcd_device(lcd_drv);
253 if (!dsim_ddi) {
254 pr_err("mipi_dsim_ddi object not found.\n");
255 return -EFAULT;
256 }
257
258 dsim_ddi->dsim_lcd_drv = lcd_drv;
259
260 pr_info("registered panel driver(%s) to mipi-dsi driver.\n",
261 lcd_drv->name);
262
263 return 0;
264
265}
266
267static struct mipi_dsim_ddi *exynos_mipi_dsi_bind_lcd_ddi(
268 struct mipi_dsim_device *dsim,
269 const char *name)
270{
271 struct mipi_dsim_ddi *dsim_ddi, *next;
272 struct mipi_dsim_lcd_driver *lcd_drv;
273 struct mipi_dsim_lcd_device *lcd_dev;
274 int ret;
275
276 mutex_lock(&dsim->lock);
277
278 list_for_each_entry_safe(dsim_ddi, next, &dsim_ddi_list, list) {
279 lcd_drv = dsim_ddi->dsim_lcd_drv;
280 lcd_dev = dsim_ddi->dsim_lcd_dev;
281 if (!lcd_drv || !lcd_dev ||
282 (dsim->id != dsim_ddi->bus_id))
283 continue;
284
285 dev_dbg(dsim->dev, "lcd_drv->id = %d, lcd_dev->id = %d\n",
286 lcd_drv->id, lcd_dev->id);
287 dev_dbg(dsim->dev, "lcd_dev->bus_id = %d, dsim->id = %d\n",
288 lcd_dev->bus_id, dsim->id);
289
290 if ((strcmp(lcd_drv->name, name) == 0)) {
291 lcd_dev->master = dsim;
292
293 lcd_dev->dev.parent = dsim->dev;
294 dev_set_name(&lcd_dev->dev, "%s", lcd_drv->name);
295
296 ret = device_register(&lcd_dev->dev);
297 if (ret < 0) {
298 dev_err(dsim->dev,
299 "can't register %s, status %d\n",
300 dev_name(&lcd_dev->dev), ret);
301 mutex_unlock(&dsim->lock);
302
303 return NULL;
304 }
305
306 dsim->dsim_lcd_dev = lcd_dev;
307 dsim->dsim_lcd_drv = lcd_drv;
308
309 mutex_unlock(&dsim->lock);
310
311 return dsim_ddi;
312 }
313 }
314
315 mutex_unlock(&dsim->lock);
316
317 return NULL;
318}
319
320/* define MIPI-DSI Master operations. */
321static struct mipi_dsim_master_ops master_ops = {
322 .cmd_read = exynos_mipi_dsi_rd_data,
323 .cmd_write = exynos_mipi_dsi_wr_data,
324 .get_dsim_frame_done = exynos_mipi_dsi_get_frame_done_status,
325 .clear_dsim_frame_done = exynos_mipi_dsi_clear_frame_done,
326 .set_early_blank_mode = exynos_mipi_dsi_early_blank_mode,
327 .set_blank_mode = exynos_mipi_dsi_blank_mode,
328};
329
330static int exynos_mipi_dsi_probe(struct platform_device *pdev)
331{
332 struct resource *res;
333 struct mipi_dsim_device *dsim;
334 struct mipi_dsim_config *dsim_config;
335 struct mipi_dsim_platform_data *dsim_pd;
336 struct mipi_dsim_ddi *dsim_ddi;
337 int ret = -EINVAL;
338
339 dsim = devm_kzalloc(&pdev->dev, sizeof(struct mipi_dsim_device),
340 GFP_KERNEL);
341 if (!dsim) {
342 dev_err(&pdev->dev, "failed to allocate dsim object.\n");
343 return -ENOMEM;
344 }
345
346 dsim->pd = to_dsim_plat(pdev);
347 dsim->dev = &pdev->dev;
348 dsim->id = pdev->id;
349
350 /* get mipi_dsim_platform_data. */
351 dsim_pd = (struct mipi_dsim_platform_data *)dsim->pd;
352 if (dsim_pd == NULL) {
353 dev_err(&pdev->dev, "failed to get platform data for dsim.\n");
354 return -EINVAL;
355 }
356 /* get mipi_dsim_config. */
357 dsim_config = dsim_pd->dsim_config;
358 if (dsim_config == NULL) {
359 dev_err(&pdev->dev, "failed to get dsim config data.\n");
360 return -EINVAL;
361 }
362
363 dsim->dsim_config = dsim_config;
364 dsim->master_ops = &master_ops;
365
366 mutex_init(&dsim->lock);
367
368 ret = devm_regulator_bulk_get(&pdev->dev, ARRAY_SIZE(supplies),
369 supplies);
370 if (ret) {
371 dev_err(&pdev->dev, "Failed to get regulators: %d\n", ret);
372 return ret;
373 }
374
375 dsim->phy = devm_phy_get(&pdev->dev, "dsim");
376 if (IS_ERR(dsim->phy))
377 return PTR_ERR(dsim->phy);
378
379 dsim->clock = devm_clk_get(&pdev->dev, "dsim0");
380 if (IS_ERR(dsim->clock)) {
381 dev_err(&pdev->dev, "failed to get dsim clock source\n");
382 return -ENODEV;
383 }
384
385 clk_enable(dsim->clock);
386
387 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
388
389 dsim->reg_base = devm_ioremap_resource(&pdev->dev, res);
390 if (IS_ERR(dsim->reg_base)) {
391 ret = PTR_ERR(dsim->reg_base);
392 goto error;
393 }
394
395 mutex_init(&dsim->lock);
396
397 /* bind lcd ddi matched with panel name. */
398 dsim_ddi = exynos_mipi_dsi_bind_lcd_ddi(dsim, dsim_pd->lcd_panel_name);
399 if (!dsim_ddi) {
400 dev_err(&pdev->dev, "mipi_dsim_ddi object not found.\n");
401 ret = -EINVAL;
402 goto error;
403 }
404
405 dsim->irq = platform_get_irq(pdev, 0);
406 if (IS_ERR_VALUE(dsim->irq)) {
407 dev_err(&pdev->dev, "failed to request dsim irq resource\n");
408 ret = -EINVAL;
409 goto error;
410 }
411
412 init_completion(&dsim_wr_comp);
413 init_completion(&dsim_rd_comp);
414 platform_set_drvdata(pdev, dsim);
415
416 ret = devm_request_irq(&pdev->dev, dsim->irq,
417 exynos_mipi_dsi_interrupt_handler,
418 IRQF_SHARED, dev_name(&pdev->dev), dsim);
419 if (ret != 0) {
420 dev_err(&pdev->dev, "failed to request dsim irq\n");
421 ret = -EINVAL;
422 goto error;
423 }
424
425 /* enable interrupts */
426 exynos_mipi_dsi_init_interrupt(dsim);
427
428 /* initialize mipi-dsi client(lcd panel). */
429 if (dsim_ddi->dsim_lcd_drv && dsim_ddi->dsim_lcd_drv->probe)
430 dsim_ddi->dsim_lcd_drv->probe(dsim_ddi->dsim_lcd_dev);
431
432 /* in case mipi-dsi has been enabled by bootloader */
433 if (dsim_pd->enabled) {
434 exynos_mipi_regulator_enable(dsim);
435 goto done;
436 }
437
438 /* lcd panel power on. */
439 if (dsim_ddi->dsim_lcd_drv && dsim_ddi->dsim_lcd_drv->power_on)
440 dsim_ddi->dsim_lcd_drv->power_on(dsim_ddi->dsim_lcd_dev, 1);
441
442 exynos_mipi_regulator_enable(dsim);
443
444 /* enable MIPI-DSI PHY. */
445 phy_power_on(dsim->phy);
446
447 exynos_mipi_update_cfg(dsim);
448
449 /* set lcd panel sequence commands. */
450 if (dsim_ddi->dsim_lcd_drv && dsim_ddi->dsim_lcd_drv->set_sequence)
451 dsim_ddi->dsim_lcd_drv->set_sequence(dsim_ddi->dsim_lcd_dev);
452
453 dsim->suspended = false;
454
455done:
456 platform_set_drvdata(pdev, dsim);
457
458 dev_dbg(&pdev->dev, "%s() completed successfully (%s mode)\n", __func__,
459 dsim_config->e_interface == DSIM_COMMAND ? "CPU" : "RGB");
460
461 return 0;
462
463error:
464 clk_disable(dsim->clock);
465 return ret;
466}
467
468static int exynos_mipi_dsi_remove(struct platform_device *pdev)
469{
470 struct mipi_dsim_device *dsim = platform_get_drvdata(pdev);
471 struct mipi_dsim_ddi *dsim_ddi, *next;
472 struct mipi_dsim_lcd_driver *dsim_lcd_drv;
473
474 clk_disable(dsim->clock);
475
476 list_for_each_entry_safe(dsim_ddi, next, &dsim_ddi_list, list) {
477 if (dsim_ddi) {
478 if (dsim->id != dsim_ddi->bus_id)
479 continue;
480
481 dsim_lcd_drv = dsim_ddi->dsim_lcd_drv;
482
483 if (dsim_lcd_drv->remove)
484 dsim_lcd_drv->remove(dsim_ddi->dsim_lcd_dev);
485
486 kfree(dsim_ddi);
487 }
488 }
489
490 return 0;
491}
492
493#ifdef CONFIG_PM_SLEEP
494static int exynos_mipi_dsi_suspend(struct device *dev)
495{
496 struct platform_device *pdev = to_platform_device(dev);
497 struct mipi_dsim_device *dsim = platform_get_drvdata(pdev);
498 struct mipi_dsim_lcd_driver *client_drv = dsim->dsim_lcd_drv;
499 struct mipi_dsim_lcd_device *client_dev = dsim->dsim_lcd_dev;
500
501 disable_irq(dsim->irq);
502
503 if (dsim->suspended)
504 return 0;
505
506 if (client_drv && client_drv->suspend)
507 client_drv->suspend(client_dev);
508
509 /* disable MIPI-DSI PHY. */
510 phy_power_off(dsim->phy);
511
512 clk_disable(dsim->clock);
513
514 exynos_mipi_regulator_disable(dsim);
515
516 dsim->suspended = true;
517
518 return 0;
519}
520
521static int exynos_mipi_dsi_resume(struct device *dev)
522{
523 struct platform_device *pdev = to_platform_device(dev);
524 struct mipi_dsim_device *dsim = platform_get_drvdata(pdev);
525 struct mipi_dsim_lcd_driver *client_drv = dsim->dsim_lcd_drv;
526 struct mipi_dsim_lcd_device *client_dev = dsim->dsim_lcd_dev;
527
528 enable_irq(dsim->irq);
529
530 if (!dsim->suspended)
531 return 0;
532
533 /* lcd panel power on. */
534 if (client_drv && client_drv->power_on)
535 client_drv->power_on(client_dev, 1);
536
537 exynos_mipi_regulator_enable(dsim);
538
539 /* enable MIPI-DSI PHY. */
540 phy_power_on(dsim->phy);
541
542 clk_enable(dsim->clock);
543
544 exynos_mipi_update_cfg(dsim);
545
546 /* set lcd panel sequence commands. */
547 if (client_drv && client_drv->set_sequence)
548 client_drv->set_sequence(client_dev);
549
550 dsim->suspended = false;
551
552 return 0;
553}
554#endif
555
556static const struct dev_pm_ops exynos_mipi_dsi_pm_ops = {
557 SET_SYSTEM_SLEEP_PM_OPS(exynos_mipi_dsi_suspend, exynos_mipi_dsi_resume)
558};
559
560static struct platform_driver exynos_mipi_dsi_driver = {
561 .probe = exynos_mipi_dsi_probe,
562 .remove = exynos_mipi_dsi_remove,
563 .driver = {
564 .name = "exynos-mipi-dsim",
565 .owner = THIS_MODULE,
566 .pm = &exynos_mipi_dsi_pm_ops,
567 },
568};
569
570module_platform_driver(exynos_mipi_dsi_driver);
571
572MODULE_AUTHOR("InKi Dae <inki.dae@samsung.com>");
573MODULE_DESCRIPTION("Samusung SoC MIPI-DSI driver");
574MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/exynos/exynos_mipi_dsi_common.c b/drivers/video/fbdev/exynos/exynos_mipi_dsi_common.c
new file mode 100644
index 000000000000..85edabfdef5a
--- /dev/null
+++ b/drivers/video/fbdev/exynos/exynos_mipi_dsi_common.c
@@ -0,0 +1,880 @@
1/* linux/drivers/video/exynos/exynos_mipi_dsi_common.c
2 *
3 * Samsung SoC MIPI-DSI common driver.
4 *
5 * Copyright (c) 2012 Samsung Electronics Co., Ltd
6 *
7 * InKi Dae, <inki.dae@samsung.com>
8 * Donghwa Lee, <dh09.lee@samsung.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13*/
14
15#include <linux/module.h>
16#include <linux/kernel.h>
17#include <linux/errno.h>
18#include <linux/mutex.h>
19#include <linux/wait.h>
20#include <linux/fs.h>
21#include <linux/mm.h>
22#include <linux/fb.h>
23#include <linux/ctype.h>
24#include <linux/platform_device.h>
25#include <linux/io.h>
26#include <linux/memory.h>
27#include <linux/delay.h>
28#include <linux/irqreturn.h>
29#include <linux/kthread.h>
30
31#include <video/mipi_display.h>
32#include <video/exynos_mipi_dsim.h>
33
34#include "exynos_mipi_dsi_regs.h"
35#include "exynos_mipi_dsi_lowlevel.h"
36#include "exynos_mipi_dsi_common.h"
37
38#define MIPI_FIFO_TIMEOUT msecs_to_jiffies(250)
39#define MIPI_RX_FIFO_READ_DONE 0x30800002
40#define MIPI_MAX_RX_FIFO 20
41#define MHZ (1000 * 1000)
42#define FIN_HZ (24 * MHZ)
43
44#define DFIN_PLL_MIN_HZ (6 * MHZ)
45#define DFIN_PLL_MAX_HZ (12 * MHZ)
46
47#define DFVCO_MIN_HZ (500 * MHZ)
48#define DFVCO_MAX_HZ (1000 * MHZ)
49
50#define TRY_GET_FIFO_TIMEOUT (5000 * 2)
51#define TRY_FIFO_CLEAR (10)
52
53/* MIPI-DSIM status types. */
54enum {
55 DSIM_STATE_INIT, /* should be initialized. */
56 DSIM_STATE_STOP, /* CPU and LCDC are LP mode. */
57 DSIM_STATE_HSCLKEN, /* HS clock was enabled. */
58 DSIM_STATE_ULPS
59};
60
61/* define DSI lane types. */
62enum {
63 DSIM_LANE_CLOCK = (1 << 0),
64 DSIM_LANE_DATA0 = (1 << 1),
65 DSIM_LANE_DATA1 = (1 << 2),
66 DSIM_LANE_DATA2 = (1 << 3),
67 DSIM_LANE_DATA3 = (1 << 4)
68};
69
70static unsigned int dpll_table[15] = {
71 100, 120, 170, 220, 270,
72 320, 390, 450, 510, 560,
73 640, 690, 770, 870, 950
74};
75
76irqreturn_t exynos_mipi_dsi_interrupt_handler(int irq, void *dev_id)
77{
78 struct mipi_dsim_device *dsim = dev_id;
79 unsigned int intsrc, intmsk;
80
81 intsrc = exynos_mipi_dsi_read_interrupt(dsim);
82 intmsk = exynos_mipi_dsi_read_interrupt_mask(dsim);
83 intmsk = ~intmsk & intsrc;
84
85 if (intsrc & INTMSK_RX_DONE) {
86 complete(&dsim_rd_comp);
87 dev_dbg(dsim->dev, "MIPI INTMSK_RX_DONE\n");
88 }
89 if (intsrc & INTMSK_FIFO_EMPTY) {
90 complete(&dsim_wr_comp);
91 dev_dbg(dsim->dev, "MIPI INTMSK_FIFO_EMPTY\n");
92 }
93
94 exynos_mipi_dsi_clear_interrupt(dsim, intmsk);
95
96 return IRQ_HANDLED;
97}
98
99/*
100 * write long packet to mipi dsi slave
101 * @dsim: mipi dsim device structure.
102 * @data0: packet data to send.
103 * @data1: size of packet data
104 */
105static void exynos_mipi_dsi_long_data_wr(struct mipi_dsim_device *dsim,
106 const unsigned char *data0, unsigned int data_size)
107{
108 unsigned int data_cnt = 0, payload = 0;
109
110 /* in case that data count is more then 4 */
111 for (data_cnt = 0; data_cnt < data_size; data_cnt += 4) {
112 /*
113 * after sending 4bytes per one time,
114 * send remainder data less then 4.
115 */
116 if ((data_size - data_cnt) < 4) {
117 if ((data_size - data_cnt) == 3) {
118 payload = data0[data_cnt] |
119 data0[data_cnt + 1] << 8 |
120 data0[data_cnt + 2] << 16;
121 dev_dbg(dsim->dev, "count = 3 payload = %x, %x %x %x\n",
122 payload, data0[data_cnt],
123 data0[data_cnt + 1],
124 data0[data_cnt + 2]);
125 } else if ((data_size - data_cnt) == 2) {
126 payload = data0[data_cnt] |
127 data0[data_cnt + 1] << 8;
128 dev_dbg(dsim->dev,
129 "count = 2 payload = %x, %x %x\n", payload,
130 data0[data_cnt],
131 data0[data_cnt + 1]);
132 } else if ((data_size - data_cnt) == 1) {
133 payload = data0[data_cnt];
134 }
135
136 exynos_mipi_dsi_wr_tx_data(dsim, payload);
137 /* send 4bytes per one time. */
138 } else {
139 payload = data0[data_cnt] |
140 data0[data_cnt + 1] << 8 |
141 data0[data_cnt + 2] << 16 |
142 data0[data_cnt + 3] << 24;
143
144 dev_dbg(dsim->dev,
145 "count = 4 payload = %x, %x %x %x %x\n",
146 payload, *(u8 *)(data0 + data_cnt),
147 data0[data_cnt + 1],
148 data0[data_cnt + 2],
149 data0[data_cnt + 3]);
150
151 exynos_mipi_dsi_wr_tx_data(dsim, payload);
152 }
153 }
154}
155
156int exynos_mipi_dsi_wr_data(struct mipi_dsim_device *dsim, unsigned int data_id,
157 const unsigned char *data0, unsigned int data_size)
158{
159 unsigned int check_rx_ack = 0;
160
161 if (dsim->state == DSIM_STATE_ULPS) {
162 dev_err(dsim->dev, "state is ULPS.\n");
163
164 return -EINVAL;
165 }
166
167 /* FIXME!!! why does it need this delay? */
168 msleep(20);
169
170 mutex_lock(&dsim->lock);
171
172 switch (data_id) {
173 /* short packet types of packet types for command. */
174 case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM:
175 case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM:
176 case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM:
177 case MIPI_DSI_DCS_SHORT_WRITE:
178 case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
179 case MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE:
180 exynos_mipi_dsi_wr_tx_header(dsim, data_id, data0[0], data0[1]);
181 if (check_rx_ack) {
182 /* process response func should be implemented */
183 mutex_unlock(&dsim->lock);
184 return 0;
185 } else {
186 mutex_unlock(&dsim->lock);
187 return -EINVAL;
188 }
189
190 /* general command */
191 case MIPI_DSI_COLOR_MODE_OFF:
192 case MIPI_DSI_COLOR_MODE_ON:
193 case MIPI_DSI_SHUTDOWN_PERIPHERAL:
194 case MIPI_DSI_TURN_ON_PERIPHERAL:
195 exynos_mipi_dsi_wr_tx_header(dsim, data_id, data0[0], data0[1]);
196 if (check_rx_ack) {
197 /* process response func should be implemented. */
198 mutex_unlock(&dsim->lock);
199 return 0;
200 } else {
201 mutex_unlock(&dsim->lock);
202 return -EINVAL;
203 }
204
205 /* packet types for video data */
206 case MIPI_DSI_V_SYNC_START:
207 case MIPI_DSI_V_SYNC_END:
208 case MIPI_DSI_H_SYNC_START:
209 case MIPI_DSI_H_SYNC_END:
210 case MIPI_DSI_END_OF_TRANSMISSION:
211 mutex_unlock(&dsim->lock);
212 return 0;
213
214 /* long packet type and null packet */
215 case MIPI_DSI_NULL_PACKET:
216 case MIPI_DSI_BLANKING_PACKET:
217 mutex_unlock(&dsim->lock);
218 return 0;
219 case MIPI_DSI_GENERIC_LONG_WRITE:
220 case MIPI_DSI_DCS_LONG_WRITE:
221 {
222 unsigned int size, payload = 0;
223 reinit_completion(&dsim_wr_comp);
224
225 size = data_size * 4;
226
227 /* if data count is less then 4, then send 3bytes data. */
228 if (data_size < 4) {
229 payload = data0[0] |
230 data0[1] << 8 |
231 data0[2] << 16;
232
233 exynos_mipi_dsi_wr_tx_data(dsim, payload);
234
235 dev_dbg(dsim->dev, "count = %d payload = %x,%x %x %x\n",
236 data_size, payload, data0[0],
237 data0[1], data0[2]);
238
239 /* in case that data count is more then 4 */
240 } else
241 exynos_mipi_dsi_long_data_wr(dsim, data0, data_size);
242
243 /* put data into header fifo */
244 exynos_mipi_dsi_wr_tx_header(dsim, data_id, data_size & 0xff,
245 (data_size & 0xff00) >> 8);
246
247 if (!wait_for_completion_interruptible_timeout(&dsim_wr_comp,
248 MIPI_FIFO_TIMEOUT)) {
249 dev_warn(dsim->dev, "command write timeout.\n");
250 mutex_unlock(&dsim->lock);
251 return -EAGAIN;
252 }
253
254 if (check_rx_ack) {
255 /* process response func should be implemented. */
256 mutex_unlock(&dsim->lock);
257 return 0;
258 } else {
259 mutex_unlock(&dsim->lock);
260 return -EINVAL;
261 }
262 }
263
264 /* packet typo for video data */
265 case MIPI_DSI_PACKED_PIXEL_STREAM_16:
266 case MIPI_DSI_PACKED_PIXEL_STREAM_18:
267 case MIPI_DSI_PIXEL_STREAM_3BYTE_18:
268 case MIPI_DSI_PACKED_PIXEL_STREAM_24:
269 if (check_rx_ack) {
270 /* process response func should be implemented. */
271 mutex_unlock(&dsim->lock);
272 return 0;
273 } else {
274 mutex_unlock(&dsim->lock);
275 return -EINVAL;
276 }
277 default:
278 dev_warn(dsim->dev,
279 "data id %x is not supported current DSI spec.\n",
280 data_id);
281
282 mutex_unlock(&dsim->lock);
283 return -EINVAL;
284 }
285}
286
287static unsigned int exynos_mipi_dsi_long_data_rd(struct mipi_dsim_device *dsim,
288 unsigned int req_size, unsigned int rx_data, u8 *rx_buf)
289{
290 unsigned int rcv_pkt, i, j;
291 u16 rxsize;
292
293 /* for long packet */
294 rxsize = (u16)((rx_data & 0x00ffff00) >> 8);
295 dev_dbg(dsim->dev, "mipi dsi rx size : %d\n", rxsize);
296 if (rxsize != req_size) {
297 dev_dbg(dsim->dev,
298 "received size mismatch received: %d, requested: %d\n",
299 rxsize, req_size);
300 goto err;
301 }
302
303 for (i = 0; i < (rxsize >> 2); i++) {
304 rcv_pkt = exynos_mipi_dsi_rd_rx_fifo(dsim);
305 dev_dbg(dsim->dev, "received pkt : %08x\n", rcv_pkt);
306 for (j = 0; j < 4; j++) {
307 rx_buf[(i * 4) + j] =
308 (u8)(rcv_pkt >> (j * 8)) & 0xff;
309 dev_dbg(dsim->dev, "received value : %02x\n",
310 (rcv_pkt >> (j * 8)) & 0xff);
311 }
312 }
313 if (rxsize % 4) {
314 rcv_pkt = exynos_mipi_dsi_rd_rx_fifo(dsim);
315 dev_dbg(dsim->dev, "received pkt : %08x\n", rcv_pkt);
316 for (j = 0; j < (rxsize % 4); j++) {
317 rx_buf[(i * 4) + j] =
318 (u8)(rcv_pkt >> (j * 8)) & 0xff;
319 dev_dbg(dsim->dev, "received value : %02x\n",
320 (rcv_pkt >> (j * 8)) & 0xff);
321 }
322 }
323
324 return rxsize;
325
326err:
327 return -EINVAL;
328}
329
330static unsigned int exynos_mipi_dsi_response_size(unsigned int req_size)
331{
332 switch (req_size) {
333 case 1:
334 return MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE;
335 case 2:
336 return MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE;
337 default:
338 return MIPI_DSI_RX_GENERIC_LONG_READ_RESPONSE;
339 }
340}
341
342int exynos_mipi_dsi_rd_data(struct mipi_dsim_device *dsim, unsigned int data_id,
343 unsigned int data0, unsigned int req_size, u8 *rx_buf)
344{
345 unsigned int rx_data, rcv_pkt, i;
346 u8 response = 0;
347 u16 rxsize;
348
349 if (dsim->state == DSIM_STATE_ULPS) {
350 dev_err(dsim->dev, "state is ULPS.\n");
351
352 return -EINVAL;
353 }
354
355 /* FIXME!!! */
356 msleep(20);
357
358 mutex_lock(&dsim->lock);
359 reinit_completion(&dsim_rd_comp);
360 exynos_mipi_dsi_rd_tx_header(dsim,
361 MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE, req_size);
362
363 response = exynos_mipi_dsi_response_size(req_size);
364
365 switch (data_id) {
366 case MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM:
367 case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM:
368 case MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM:
369 case MIPI_DSI_DCS_READ:
370 exynos_mipi_dsi_rd_tx_header(dsim,
371 data_id, data0);
372 /* process response func should be implemented. */
373 break;
374 default:
375 dev_warn(dsim->dev,
376 "data id %x is not supported current DSI spec.\n",
377 data_id);
378
379 mutex_unlock(&dsim->lock);
380 return -EINVAL;
381 }
382
383 if (!wait_for_completion_interruptible_timeout(&dsim_rd_comp,
384 MIPI_FIFO_TIMEOUT)) {
385 pr_err("RX done interrupt timeout\n");
386 mutex_unlock(&dsim->lock);
387 return 0;
388 }
389
390 msleep(20);
391
392 rx_data = exynos_mipi_dsi_rd_rx_fifo(dsim);
393
394 if ((u8)(rx_data & 0xff) != response) {
395 printk(KERN_ERR
396 "mipi dsi wrong response rx_data : %x, response:%x\n",
397 rx_data, response);
398 goto clear_rx_fifo;
399 }
400
401 if (req_size <= 2) {
402 /* for short packet */
403 for (i = 0; i < req_size; i++)
404 rx_buf[i] = (rx_data >> (8 + (i * 8))) & 0xff;
405 rxsize = req_size;
406 } else {
407 /* for long packet */
408 rxsize = exynos_mipi_dsi_long_data_rd(dsim, req_size, rx_data,
409 rx_buf);
410 if (rxsize != req_size)
411 goto clear_rx_fifo;
412 }
413
414 rcv_pkt = exynos_mipi_dsi_rd_rx_fifo(dsim);
415
416 msleep(20);
417
418 if (rcv_pkt != MIPI_RX_FIFO_READ_DONE) {
419 dev_info(dsim->dev,
420 "Can't found RX FIFO READ DONE FLAG : %x\n", rcv_pkt);
421 goto clear_rx_fifo;
422 }
423
424 mutex_unlock(&dsim->lock);
425
426 return rxsize;
427
428clear_rx_fifo:
429 i = 0;
430 while (1) {
431 rcv_pkt = exynos_mipi_dsi_rd_rx_fifo(dsim);
432 if ((rcv_pkt == MIPI_RX_FIFO_READ_DONE)
433 || (i > MIPI_MAX_RX_FIFO))
434 break;
435 dev_dbg(dsim->dev,
436 "mipi dsi clear rx fifo : %08x\n", rcv_pkt);
437 i++;
438 }
439 dev_info(dsim->dev,
440 "mipi dsi rx done count : %d, rcv_pkt : %08x\n", i, rcv_pkt);
441
442 mutex_unlock(&dsim->lock);
443
444 return 0;
445}
446
447static int exynos_mipi_dsi_pll_on(struct mipi_dsim_device *dsim,
448 unsigned int enable)
449{
450 int sw_timeout;
451
452 if (enable) {
453 sw_timeout = 1000;
454
455 exynos_mipi_dsi_enable_pll(dsim, 1);
456 while (1) {
457 sw_timeout--;
458 if (exynos_mipi_dsi_is_pll_stable(dsim))
459 return 0;
460 if (sw_timeout == 0)
461 return -EINVAL;
462 }
463 } else
464 exynos_mipi_dsi_enable_pll(dsim, 0);
465
466 return 0;
467}
468
469static unsigned long exynos_mipi_dsi_change_pll(struct mipi_dsim_device *dsim,
470 unsigned int pre_divider, unsigned int main_divider,
471 unsigned int scaler)
472{
473 unsigned long dfin_pll, dfvco, dpll_out;
474 unsigned int i, freq_band = 0xf;
475
476 dfin_pll = (FIN_HZ / pre_divider);
477
478 /******************************************************
479 * Serial Clock(=ByteClk X 8) FreqBand[3:0] *
480 ******************************************************
481 * ~ 99.99 MHz 0000
482 * 100 ~ 119.99 MHz 0001
483 * 120 ~ 159.99 MHz 0010
484 * 160 ~ 199.99 MHz 0011
485 * 200 ~ 239.99 MHz 0100
486 * 140 ~ 319.99 MHz 0101
487 * 320 ~ 389.99 MHz 0110
488 * 390 ~ 449.99 MHz 0111
489 * 450 ~ 509.99 MHz 1000
490 * 510 ~ 559.99 MHz 1001
491 * 560 ~ 639.99 MHz 1010
492 * 640 ~ 689.99 MHz 1011
493 * 690 ~ 769.99 MHz 1100
494 * 770 ~ 869.99 MHz 1101
495 * 870 ~ 949.99 MHz 1110
496 * 950 ~ 1000 MHz 1111
497 ******************************************************/
498 if (dfin_pll < DFIN_PLL_MIN_HZ || dfin_pll > DFIN_PLL_MAX_HZ) {
499 dev_warn(dsim->dev, "fin_pll range should be 6MHz ~ 12MHz\n");
500 exynos_mipi_dsi_enable_afc(dsim, 0, 0);
501 } else {
502 if (dfin_pll < 7 * MHZ)
503 exynos_mipi_dsi_enable_afc(dsim, 1, 0x1);
504 else if (dfin_pll < 8 * MHZ)
505 exynos_mipi_dsi_enable_afc(dsim, 1, 0x0);
506 else if (dfin_pll < 9 * MHZ)
507 exynos_mipi_dsi_enable_afc(dsim, 1, 0x3);
508 else if (dfin_pll < 10 * MHZ)
509 exynos_mipi_dsi_enable_afc(dsim, 1, 0x2);
510 else if (dfin_pll < 11 * MHZ)
511 exynos_mipi_dsi_enable_afc(dsim, 1, 0x5);
512 else
513 exynos_mipi_dsi_enable_afc(dsim, 1, 0x4);
514 }
515
516 dfvco = dfin_pll * main_divider;
517 dev_dbg(dsim->dev, "dfvco = %lu, dfin_pll = %lu, main_divider = %d\n",
518 dfvco, dfin_pll, main_divider);
519 if (dfvco < DFVCO_MIN_HZ || dfvco > DFVCO_MAX_HZ)
520 dev_warn(dsim->dev, "fvco range should be 500MHz ~ 1000MHz\n");
521
522 dpll_out = dfvco / (1 << scaler);
523 dev_dbg(dsim->dev, "dpll_out = %lu, dfvco = %lu, scaler = %d\n",
524 dpll_out, dfvco, scaler);
525
526 for (i = 0; i < ARRAY_SIZE(dpll_table); i++) {
527 if (dpll_out < dpll_table[i] * MHZ) {
528 freq_band = i;
529 break;
530 }
531 }
532
533 dev_dbg(dsim->dev, "freq_band = %d\n", freq_band);
534
535 exynos_mipi_dsi_pll_freq(dsim, pre_divider, main_divider, scaler);
536
537 exynos_mipi_dsi_hs_zero_ctrl(dsim, 0);
538 exynos_mipi_dsi_prep_ctrl(dsim, 0);
539
540 /* Freq Band */
541 exynos_mipi_dsi_pll_freq_band(dsim, freq_band);
542
543 /* Stable time */
544 exynos_mipi_dsi_pll_stable_time(dsim, dsim->dsim_config->pll_stable_time);
545
546 /* Enable PLL */
547 dev_dbg(dsim->dev, "FOUT of mipi dphy pll is %luMHz\n",
548 (dpll_out / MHZ));
549
550 return dpll_out;
551}
552
553static int exynos_mipi_dsi_set_clock(struct mipi_dsim_device *dsim,
554 unsigned int byte_clk_sel, unsigned int enable)
555{
556 unsigned int esc_div;
557 unsigned long esc_clk_error_rate;
558 unsigned long hs_clk = 0, byte_clk = 0, escape_clk = 0;
559
560 if (enable) {
561 dsim->e_clk_src = byte_clk_sel;
562
563 /* Escape mode clock and byte clock source */
564 exynos_mipi_dsi_set_byte_clock_src(dsim, byte_clk_sel);
565
566 /* DPHY, DSIM Link : D-PHY clock out */
567 if (byte_clk_sel == DSIM_PLL_OUT_DIV8) {
568 hs_clk = exynos_mipi_dsi_change_pll(dsim,
569 dsim->dsim_config->p, dsim->dsim_config->m,
570 dsim->dsim_config->s);
571 if (hs_clk == 0) {
572 dev_err(dsim->dev,
573 "failed to get hs clock.\n");
574 return -EINVAL;
575 }
576
577 byte_clk = hs_clk / 8;
578 exynos_mipi_dsi_enable_pll_bypass(dsim, 0);
579 exynos_mipi_dsi_pll_on(dsim, 1);
580 /* DPHY : D-PHY clock out, DSIM link : external clock out */
581 } else if (byte_clk_sel == DSIM_EXT_CLK_DIV8) {
582 dev_warn(dsim->dev, "this project is not support\n");
583 dev_warn(dsim->dev,
584 "external clock source for MIPI DSIM.\n");
585 } else if (byte_clk_sel == DSIM_EXT_CLK_BYPASS) {
586 dev_warn(dsim->dev, "this project is not support\n");
587 dev_warn(dsim->dev,
588 "external clock source for MIPI DSIM\n");
589 }
590
591 /* escape clock divider */
592 esc_div = byte_clk / (dsim->dsim_config->esc_clk);
593 dev_dbg(dsim->dev,
594 "esc_div = %d, byte_clk = %lu, esc_clk = %lu\n",
595 esc_div, byte_clk, dsim->dsim_config->esc_clk);
596 if ((byte_clk / esc_div) >= (20 * MHZ) ||
597 (byte_clk / esc_div) >
598 dsim->dsim_config->esc_clk)
599 esc_div += 1;
600
601 escape_clk = byte_clk / esc_div;
602 dev_dbg(dsim->dev,
603 "escape_clk = %lu, byte_clk = %lu, esc_div = %d\n",
604 escape_clk, byte_clk, esc_div);
605
606 /* enable escape clock. */
607 exynos_mipi_dsi_enable_byte_clock(dsim, 1);
608
609 /* enable byte clk and escape clock */
610 exynos_mipi_dsi_set_esc_clk_prs(dsim, 1, esc_div);
611 /* escape clock on lane */
612 exynos_mipi_dsi_enable_esc_clk_on_lane(dsim,
613 (DSIM_LANE_CLOCK | dsim->data_lane), 1);
614
615 dev_dbg(dsim->dev, "byte clock is %luMHz\n",
616 (byte_clk / MHZ));
617 dev_dbg(dsim->dev, "escape clock that user's need is %lu\n",
618 (dsim->dsim_config->esc_clk / MHZ));
619 dev_dbg(dsim->dev, "escape clock divider is %x\n", esc_div);
620 dev_dbg(dsim->dev, "escape clock is %luMHz\n",
621 ((byte_clk / esc_div) / MHZ));
622
623 if ((byte_clk / esc_div) > escape_clk) {
624 esc_clk_error_rate = escape_clk /
625 (byte_clk / esc_div);
626 dev_warn(dsim->dev, "error rate is %lu over.\n",
627 (esc_clk_error_rate / 100));
628 } else if ((byte_clk / esc_div) < (escape_clk)) {
629 esc_clk_error_rate = (byte_clk / esc_div) /
630 escape_clk;
631 dev_warn(dsim->dev, "error rate is %lu under.\n",
632 (esc_clk_error_rate / 100));
633 }
634 } else {
635 exynos_mipi_dsi_enable_esc_clk_on_lane(dsim,
636 (DSIM_LANE_CLOCK | dsim->data_lane), 0);
637 exynos_mipi_dsi_set_esc_clk_prs(dsim, 0, 0);
638
639 /* disable escape clock. */
640 exynos_mipi_dsi_enable_byte_clock(dsim, 0);
641
642 if (byte_clk_sel == DSIM_PLL_OUT_DIV8)
643 exynos_mipi_dsi_pll_on(dsim, 0);
644 }
645
646 return 0;
647}
648
649int exynos_mipi_dsi_init_dsim(struct mipi_dsim_device *dsim)
650{
651 dsim->state = DSIM_STATE_INIT;
652
653 switch (dsim->dsim_config->e_no_data_lane) {
654 case DSIM_DATA_LANE_1:
655 dsim->data_lane = DSIM_LANE_DATA0;
656 break;
657 case DSIM_DATA_LANE_2:
658 dsim->data_lane = DSIM_LANE_DATA0 | DSIM_LANE_DATA1;
659 break;
660 case DSIM_DATA_LANE_3:
661 dsim->data_lane = DSIM_LANE_DATA0 | DSIM_LANE_DATA1 |
662 DSIM_LANE_DATA2;
663 break;
664 case DSIM_DATA_LANE_4:
665 dsim->data_lane = DSIM_LANE_DATA0 | DSIM_LANE_DATA1 |
666 DSIM_LANE_DATA2 | DSIM_LANE_DATA3;
667 break;
668 default:
669 dev_info(dsim->dev, "data lane is invalid.\n");
670 return -EINVAL;
671 }
672
673 exynos_mipi_dsi_sw_reset(dsim);
674 exynos_mipi_dsi_func_reset(dsim);
675
676 exynos_mipi_dsi_dp_dn_swap(dsim, 0);
677
678 return 0;
679}
680
681void exynos_mipi_dsi_init_interrupt(struct mipi_dsim_device *dsim)
682{
683 unsigned int src = 0;
684
685 src = (INTSRC_SFR_FIFO_EMPTY | INTSRC_RX_DATA_DONE);
686 exynos_mipi_dsi_set_interrupt(dsim, src, 1);
687
688 src = 0;
689 src = ~(INTMSK_RX_DONE | INTMSK_FIFO_EMPTY);
690 exynos_mipi_dsi_set_interrupt_mask(dsim, src, 1);
691}
692
693int exynos_mipi_dsi_enable_frame_done_int(struct mipi_dsim_device *dsim,
694 unsigned int enable)
695{
696 /* enable only frame done interrupt */
697 exynos_mipi_dsi_set_interrupt_mask(dsim, INTMSK_FRAME_DONE, enable);
698
699 return 0;
700}
701
702void exynos_mipi_dsi_stand_by(struct mipi_dsim_device *dsim,
703 unsigned int enable)
704{
705
706 /* consider Main display and Sub display. */
707
708 exynos_mipi_dsi_set_main_stand_by(dsim, enable);
709}
710
711int exynos_mipi_dsi_set_display_mode(struct mipi_dsim_device *dsim,
712 struct mipi_dsim_config *dsim_config)
713{
714 struct mipi_dsim_platform_data *dsim_pd;
715 struct fb_videomode *timing;
716
717 dsim_pd = (struct mipi_dsim_platform_data *)dsim->pd;
718 timing = (struct fb_videomode *)dsim_pd->lcd_panel_info;
719
720 /* in case of VIDEO MODE (RGB INTERFACE), it sets polarities. */
721 if (dsim_config->e_interface == (u32) DSIM_VIDEO) {
722 if (dsim_config->auto_vertical_cnt == 0) {
723 exynos_mipi_dsi_set_main_disp_vporch(dsim,
724 dsim_config->cmd_allow,
725 timing->lower_margin,
726 timing->upper_margin);
727 exynos_mipi_dsi_set_main_disp_hporch(dsim,
728 timing->right_margin,
729 timing->left_margin);
730 exynos_mipi_dsi_set_main_disp_sync_area(dsim,
731 timing->vsync_len,
732 timing->hsync_len);
733 }
734 }
735
736 exynos_mipi_dsi_set_main_disp_resol(dsim, timing->xres,
737 timing->yres);
738
739 exynos_mipi_dsi_display_config(dsim, dsim_config);
740
741 dev_info(dsim->dev, "lcd panel ==> width = %d, height = %d\n",
742 timing->xres, timing->yres);
743
744 return 0;
745}
746
747int exynos_mipi_dsi_init_link(struct mipi_dsim_device *dsim)
748{
749 unsigned int time_out = 100;
750
751 switch (dsim->state) {
752 case DSIM_STATE_INIT:
753 exynos_mipi_dsi_init_fifo_pointer(dsim, 0x1f);
754
755 /* dsi configuration */
756 exynos_mipi_dsi_init_config(dsim);
757 exynos_mipi_dsi_enable_lane(dsim, DSIM_LANE_CLOCK, 1);
758 exynos_mipi_dsi_enable_lane(dsim, dsim->data_lane, 1);
759
760 /* set clock configuration */
761 exynos_mipi_dsi_set_clock(dsim, dsim->dsim_config->e_byte_clk, 1);
762
763 /* check clock and data lane state are stop state */
764 while (!(exynos_mipi_dsi_is_lane_state(dsim))) {
765 time_out--;
766 if (time_out == 0) {
767 dev_err(dsim->dev,
768 "DSI Master is not stop state.\n");
769 dev_err(dsim->dev,
770 "Check initialization process\n");
771
772 return -EINVAL;
773 }
774 }
775 if (time_out != 0) {
776 dev_info(dsim->dev,
777 "DSI Master driver has been completed.\n");
778 dev_info(dsim->dev, "DSI Master state is stop state\n");
779 }
780
781 dsim->state = DSIM_STATE_STOP;
782
783 /* BTA sequence counters */
784 exynos_mipi_dsi_set_stop_state_counter(dsim,
785 dsim->dsim_config->stop_holding_cnt);
786 exynos_mipi_dsi_set_bta_timeout(dsim,
787 dsim->dsim_config->bta_timeout);
788 exynos_mipi_dsi_set_lpdr_timeout(dsim,
789 dsim->dsim_config->rx_timeout);
790
791 return 0;
792 default:
793 dev_info(dsim->dev, "DSI Master is already init.\n");
794 return 0;
795 }
796
797 return 0;
798}
799
800int exynos_mipi_dsi_set_hs_enable(struct mipi_dsim_device *dsim)
801{
802 if (dsim->state != DSIM_STATE_STOP) {
803 dev_warn(dsim->dev, "DSIM is not in stop state.\n");
804 return 0;
805 }
806
807 if (dsim->e_clk_src == DSIM_EXT_CLK_BYPASS) {
808 dev_warn(dsim->dev, "clock source is external bypass.\n");
809 return 0;
810 }
811
812 dsim->state = DSIM_STATE_HSCLKEN;
813
814 /* set LCDC and CPU transfer mode to HS. */
815 exynos_mipi_dsi_set_lcdc_transfer_mode(dsim, 0);
816 exynos_mipi_dsi_set_cpu_transfer_mode(dsim, 0);
817 exynos_mipi_dsi_enable_hs_clock(dsim, 1);
818
819 return 0;
820}
821
822int exynos_mipi_dsi_set_data_transfer_mode(struct mipi_dsim_device *dsim,
823 unsigned int mode)
824{
825 if (mode) {
826 if (dsim->state != DSIM_STATE_HSCLKEN) {
827 dev_err(dsim->dev, "HS Clock lane is not enabled.\n");
828 return -EINVAL;
829 }
830
831 exynos_mipi_dsi_set_lcdc_transfer_mode(dsim, 0);
832 } else {
833 if (dsim->state == DSIM_STATE_INIT || dsim->state ==
834 DSIM_STATE_ULPS) {
835 dev_err(dsim->dev,
836 "DSI Master is not STOP or HSDT state.\n");
837 return -EINVAL;
838 }
839
840 exynos_mipi_dsi_set_cpu_transfer_mode(dsim, 0);
841 }
842
843 return 0;
844}
845
846int exynos_mipi_dsi_get_frame_done_status(struct mipi_dsim_device *dsim)
847{
848 return _exynos_mipi_dsi_get_frame_done_status(dsim);
849}
850
851int exynos_mipi_dsi_clear_frame_done(struct mipi_dsim_device *dsim)
852{
853 _exynos_mipi_dsi_clear_frame_done(dsim);
854
855 return 0;
856}
857
858int exynos_mipi_dsi_fifo_clear(struct mipi_dsim_device *dsim,
859 unsigned int val)
860{
861 int try = TRY_FIFO_CLEAR;
862
863 exynos_mipi_dsi_sw_reset_release(dsim);
864 exynos_mipi_dsi_func_reset(dsim);
865
866 do {
867 if (exynos_mipi_dsi_get_sw_reset_release(dsim)) {
868 exynos_mipi_dsi_init_interrupt(dsim);
869 dev_dbg(dsim->dev, "reset release done.\n");
870 return 0;
871 }
872 } while (--try);
873
874 dev_err(dsim->dev, "failed to clear dsim fifo.\n");
875 return -EAGAIN;
876}
877
878MODULE_AUTHOR("InKi Dae <inki.dae@samsung.com>");
879MODULE_DESCRIPTION("Samusung SoC MIPI-DSI common driver");
880MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/exynos/exynos_mipi_dsi_common.h b/drivers/video/fbdev/exynos/exynos_mipi_dsi_common.h
new file mode 100644
index 000000000000..412552274df3
--- /dev/null
+++ b/drivers/video/fbdev/exynos/exynos_mipi_dsi_common.h
@@ -0,0 +1,46 @@
1/* linux/drivers/video/exynos_mipi_dsi_common.h
2 *
3 * Header file for Samsung SoC MIPI-DSI common driver.
4 *
5 * Copyright (c) 2012 Samsung Electronics Co., Ltd
6 *
7 * InKi Dae <inki.dae@samsung.com>
8 * Donghwa Lee <dh09.lee@samsung.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13*/
14
15#ifndef _EXYNOS_MIPI_DSI_COMMON_H
16#define _EXYNOS_MIPI_DSI_COMMON_H
17
18static DECLARE_COMPLETION(dsim_rd_comp);
19static DECLARE_COMPLETION(dsim_wr_comp);
20
21int exynos_mipi_dsi_wr_data(struct mipi_dsim_device *dsim, unsigned int data_id,
22 const unsigned char *data0, unsigned int data_size);
23int exynos_mipi_dsi_rd_data(struct mipi_dsim_device *dsim, unsigned int data_id,
24 unsigned int data0, unsigned int req_size, u8 *rx_buf);
25irqreturn_t exynos_mipi_dsi_interrupt_handler(int irq, void *dev_id);
26void exynos_mipi_dsi_init_interrupt(struct mipi_dsim_device *dsim);
27int exynos_mipi_dsi_init_dsim(struct mipi_dsim_device *dsim);
28void exynos_mipi_dsi_stand_by(struct mipi_dsim_device *dsim,
29 unsigned int enable);
30int exynos_mipi_dsi_set_display_mode(struct mipi_dsim_device *dsim,
31 struct mipi_dsim_config *dsim_info);
32int exynos_mipi_dsi_init_link(struct mipi_dsim_device *dsim);
33int exynos_mipi_dsi_set_hs_enable(struct mipi_dsim_device *dsim);
34int exynos_mipi_dsi_set_data_transfer_mode(struct mipi_dsim_device *dsim,
35 unsigned int mode);
36int exynos_mipi_dsi_enable_frame_done_int(struct mipi_dsim_device *dsim,
37 unsigned int enable);
38int exynos_mipi_dsi_get_frame_done_status(struct mipi_dsim_device *dsim);
39int exynos_mipi_dsi_clear_frame_done(struct mipi_dsim_device *dsim);
40
41extern struct fb_info *registered_fb[FB_MAX] __read_mostly;
42
43int exynos_mipi_dsi_fifo_clear(struct mipi_dsim_device *dsim,
44 unsigned int val);
45
46#endif /* _EXYNOS_MIPI_DSI_COMMON_H */
diff --git a/drivers/video/fbdev/exynos/exynos_mipi_dsi_lowlevel.c b/drivers/video/fbdev/exynos/exynos_mipi_dsi_lowlevel.c
new file mode 100644
index 000000000000..c148d06540c1
--- /dev/null
+++ b/drivers/video/fbdev/exynos/exynos_mipi_dsi_lowlevel.c
@@ -0,0 +1,618 @@
1/* linux/drivers/video/exynos/exynos_mipi_dsi_lowlevel.c
2 *
3 * Samsung SoC MIPI-DSI lowlevel driver.
4 *
5 * Copyright (c) 2012 Samsung Electronics Co., Ltd
6 *
7 * InKi Dae, <inki.dae@samsung.com>
8 * Donghwa Lee, <dh09.lee@samsung.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13*/
14
15#include <linux/module.h>
16#include <linux/kernel.h>
17#include <linux/errno.h>
18#include <linux/mutex.h>
19#include <linux/wait.h>
20#include <linux/delay.h>
21#include <linux/fs.h>
22#include <linux/mm.h>
23#include <linux/ctype.h>
24#include <linux/platform_device.h>
25#include <linux/io.h>
26
27#include <video/exynos_mipi_dsim.h>
28
29#include "exynos_mipi_dsi_regs.h"
30#include "exynos_mipi_dsi_lowlevel.h"
31
32void exynos_mipi_dsi_func_reset(struct mipi_dsim_device *dsim)
33{
34 unsigned int reg;
35
36 reg = readl(dsim->reg_base + EXYNOS_DSIM_SWRST);
37
38 reg |= DSIM_FUNCRST;
39
40 writel(reg, dsim->reg_base + EXYNOS_DSIM_SWRST);
41}
42
43void exynos_mipi_dsi_sw_reset(struct mipi_dsim_device *dsim)
44{
45 unsigned int reg;
46
47 reg = readl(dsim->reg_base + EXYNOS_DSIM_SWRST);
48
49 reg |= DSIM_SWRST;
50
51 writel(reg, dsim->reg_base + EXYNOS_DSIM_SWRST);
52}
53
54void exynos_mipi_dsi_sw_reset_release(struct mipi_dsim_device *dsim)
55{
56 unsigned int reg;
57
58 reg = readl(dsim->reg_base + EXYNOS_DSIM_INTSRC);
59
60 reg |= INTSRC_SW_RST_RELEASE;
61
62 writel(reg, dsim->reg_base + EXYNOS_DSIM_INTSRC);
63}
64
65int exynos_mipi_dsi_get_sw_reset_release(struct mipi_dsim_device *dsim)
66{
67 return (readl(dsim->reg_base + EXYNOS_DSIM_INTSRC)) &
68 INTSRC_SW_RST_RELEASE;
69}
70
71unsigned int exynos_mipi_dsi_read_interrupt_mask(struct mipi_dsim_device *dsim)
72{
73 unsigned int reg;
74
75 reg = readl(dsim->reg_base + EXYNOS_DSIM_INTMSK);
76
77 return reg;
78}
79
80void exynos_mipi_dsi_set_interrupt_mask(struct mipi_dsim_device *dsim,
81 unsigned int mode, unsigned int mask)
82{
83 unsigned int reg = 0;
84
85 if (mask)
86 reg |= mode;
87 else
88 reg &= ~mode;
89
90 writel(reg, dsim->reg_base + EXYNOS_DSIM_INTMSK);
91}
92
93void exynos_mipi_dsi_init_fifo_pointer(struct mipi_dsim_device *dsim,
94 unsigned int cfg)
95{
96 unsigned int reg;
97
98 reg = readl(dsim->reg_base + EXYNOS_DSIM_FIFOCTRL);
99
100 writel(reg & ~(cfg), dsim->reg_base + EXYNOS_DSIM_FIFOCTRL);
101 mdelay(10);
102 reg |= cfg;
103
104 writel(reg, dsim->reg_base + EXYNOS_DSIM_FIFOCTRL);
105}
106
107/*
108 * this function set PLL P, M and S value in D-PHY
109 */
110void exynos_mipi_dsi_set_phy_tunning(struct mipi_dsim_device *dsim,
111 unsigned int value)
112{
113 writel(DSIM_AFC_CTL(value), dsim->reg_base + EXYNOS_DSIM_PHYACCHR);
114}
115
116void exynos_mipi_dsi_set_main_stand_by(struct mipi_dsim_device *dsim,
117 unsigned int enable)
118{
119 unsigned int reg;
120
121 reg = readl(dsim->reg_base + EXYNOS_DSIM_MDRESOL);
122
123 reg &= ~DSIM_MAIN_STAND_BY;
124
125 if (enable)
126 reg |= DSIM_MAIN_STAND_BY;
127
128 writel(reg, dsim->reg_base + EXYNOS_DSIM_MDRESOL);
129}
130
131void exynos_mipi_dsi_set_main_disp_resol(struct mipi_dsim_device *dsim,
132 unsigned int width_resol, unsigned int height_resol)
133{
134 unsigned int reg;
135
136 /* standby should be set after configuration so set to not ready*/
137 reg = (readl(dsim->reg_base + EXYNOS_DSIM_MDRESOL)) &
138 ~(DSIM_MAIN_STAND_BY);
139 writel(reg, dsim->reg_base + EXYNOS_DSIM_MDRESOL);
140
141 reg &= ~((0x7ff << 16) | (0x7ff << 0));
142 reg |= DSIM_MAIN_VRESOL(height_resol) | DSIM_MAIN_HRESOL(width_resol);
143
144 reg |= DSIM_MAIN_STAND_BY;
145 writel(reg, dsim->reg_base + EXYNOS_DSIM_MDRESOL);
146}
147
148void exynos_mipi_dsi_set_main_disp_vporch(struct mipi_dsim_device *dsim,
149 unsigned int cmd_allow, unsigned int vfront, unsigned int vback)
150{
151 unsigned int reg;
152
153 reg = (readl(dsim->reg_base + EXYNOS_DSIM_MVPORCH)) &
154 ~((DSIM_CMD_ALLOW_MASK) | (DSIM_STABLE_VFP_MASK) |
155 (DSIM_MAIN_VBP_MASK));
156
157 reg |= (DSIM_CMD_ALLOW_SHIFT(cmd_allow & 0xf) |
158 DSIM_STABLE_VFP_SHIFT(vfront & 0x7ff) |
159 DSIM_MAIN_VBP_SHIFT(vback & 0x7ff));
160
161 writel(reg, dsim->reg_base + EXYNOS_DSIM_MVPORCH);
162}
163
164void exynos_mipi_dsi_set_main_disp_hporch(struct mipi_dsim_device *dsim,
165 unsigned int front, unsigned int back)
166{
167 unsigned int reg;
168
169 reg = (readl(dsim->reg_base + EXYNOS_DSIM_MHPORCH)) &
170 ~((DSIM_MAIN_HFP_MASK) | (DSIM_MAIN_HBP_MASK));
171
172 reg |= DSIM_MAIN_HFP_SHIFT(front) | DSIM_MAIN_HBP_SHIFT(back);
173
174 writel(reg, dsim->reg_base + EXYNOS_DSIM_MHPORCH);
175}
176
177void exynos_mipi_dsi_set_main_disp_sync_area(struct mipi_dsim_device *dsim,
178 unsigned int vert, unsigned int hori)
179{
180 unsigned int reg;
181
182 reg = (readl(dsim->reg_base + EXYNOS_DSIM_MSYNC)) &
183 ~((DSIM_MAIN_VSA_MASK) | (DSIM_MAIN_HSA_MASK));
184
185 reg |= (DSIM_MAIN_VSA_SHIFT(vert & 0x3ff) |
186 DSIM_MAIN_HSA_SHIFT(hori));
187
188 writel(reg, dsim->reg_base + EXYNOS_DSIM_MSYNC);
189}
190
191void exynos_mipi_dsi_set_sub_disp_resol(struct mipi_dsim_device *dsim,
192 unsigned int vert, unsigned int hori)
193{
194 unsigned int reg;
195
196 reg = (readl(dsim->reg_base + EXYNOS_DSIM_SDRESOL)) &
197 ~(DSIM_SUB_STANDY_MASK);
198
199 writel(reg, dsim->reg_base + EXYNOS_DSIM_SDRESOL);
200
201 reg &= ~(DSIM_SUB_VRESOL_MASK) | ~(DSIM_SUB_HRESOL_MASK);
202 reg |= (DSIM_SUB_VRESOL_SHIFT(vert & 0x7ff) |
203 DSIM_SUB_HRESOL_SHIFT(hori & 0x7ff));
204 writel(reg, dsim->reg_base + EXYNOS_DSIM_SDRESOL);
205
206 reg |= DSIM_SUB_STANDY_SHIFT(1);
207 writel(reg, dsim->reg_base + EXYNOS_DSIM_SDRESOL);
208}
209
210void exynos_mipi_dsi_init_config(struct mipi_dsim_device *dsim)
211{
212 struct mipi_dsim_config *dsim_config = dsim->dsim_config;
213
214 unsigned int cfg = (readl(dsim->reg_base + EXYNOS_DSIM_CONFIG)) &
215 ~((1 << 28) | (0x1f << 20) | (0x3 << 5));
216
217 cfg = ((DSIM_AUTO_FLUSH(dsim_config->auto_flush)) |
218 (DSIM_EOT_DISABLE(dsim_config->eot_disable)) |
219 (DSIM_AUTO_MODE_SHIFT(dsim_config->auto_vertical_cnt)) |
220 (DSIM_HSE_MODE_SHIFT(dsim_config->hse)) |
221 (DSIM_HFP_MODE_SHIFT(dsim_config->hfp)) |
222 (DSIM_HBP_MODE_SHIFT(dsim_config->hbp)) |
223 (DSIM_HSA_MODE_SHIFT(dsim_config->hsa)) |
224 (DSIM_NUM_OF_DATALANE_SHIFT(dsim_config->e_no_data_lane)));
225
226 writel(cfg, dsim->reg_base + EXYNOS_DSIM_CONFIG);
227}
228
229void exynos_mipi_dsi_display_config(struct mipi_dsim_device *dsim,
230 struct mipi_dsim_config *dsim_config)
231{
232 u32 reg = (readl(dsim->reg_base + EXYNOS_DSIM_CONFIG)) &
233 ~((0x3 << 26) | (1 << 25) | (0x3 << 18) | (0x7 << 12) |
234 (0x3 << 16) | (0x7 << 8));
235
236 if (dsim_config->e_interface == DSIM_VIDEO)
237 reg |= (1 << 25);
238 else if (dsim_config->e_interface == DSIM_COMMAND)
239 reg &= ~(1 << 25);
240 else {
241 dev_err(dsim->dev, "unknown lcd type.\n");
242 return;
243 }
244
245 /* main lcd */
246 reg |= ((u8) (dsim_config->e_burst_mode) & 0x3) << 26 |
247 ((u8) (dsim_config->e_virtual_ch) & 0x3) << 18 |
248 ((u8) (dsim_config->e_pixel_format) & 0x7) << 12;
249
250 writel(reg, dsim->reg_base + EXYNOS_DSIM_CONFIG);
251}
252
253void exynos_mipi_dsi_enable_lane(struct mipi_dsim_device *dsim, unsigned int lane,
254 unsigned int enable)
255{
256 unsigned int reg;
257
258 reg = readl(dsim->reg_base + EXYNOS_DSIM_CONFIG);
259
260 if (enable)
261 reg |= DSIM_LANE_ENx(lane);
262 else
263 reg &= ~DSIM_LANE_ENx(lane);
264
265 writel(reg, dsim->reg_base + EXYNOS_DSIM_CONFIG);
266}
267
268
269void exynos_mipi_dsi_set_data_lane_number(struct mipi_dsim_device *dsim,
270 unsigned int count)
271{
272 unsigned int cfg;
273
274 /* get the data lane number. */
275 cfg = DSIM_NUM_OF_DATALANE_SHIFT(count);
276
277 writel(cfg, dsim->reg_base + EXYNOS_DSIM_CONFIG);
278}
279
280void exynos_mipi_dsi_enable_afc(struct mipi_dsim_device *dsim, unsigned int enable,
281 unsigned int afc_code)
282{
283 unsigned int reg = readl(dsim->reg_base + EXYNOS_DSIM_PHYACCHR);
284
285 if (enable) {
286 reg |= (1 << 14);
287 reg &= ~(0x7 << 5);
288 reg |= (afc_code & 0x7) << 5;
289 } else
290 reg &= ~(1 << 14);
291
292 writel(reg, dsim->reg_base + EXYNOS_DSIM_PHYACCHR);
293}
294
295void exynos_mipi_dsi_enable_pll_bypass(struct mipi_dsim_device *dsim,
296 unsigned int enable)
297{
298 unsigned int reg = (readl(dsim->reg_base + EXYNOS_DSIM_CLKCTRL)) &
299 ~(DSIM_PLL_BYPASS_SHIFT(0x1));
300
301 reg |= DSIM_PLL_BYPASS_SHIFT(enable);
302
303 writel(reg, dsim->reg_base + EXYNOS_DSIM_CLKCTRL);
304}
305
306void exynos_mipi_dsi_set_pll_pms(struct mipi_dsim_device *dsim, unsigned int p,
307 unsigned int m, unsigned int s)
308{
309 unsigned int reg = readl(dsim->reg_base + EXYNOS_DSIM_PLLCTRL);
310
311 reg |= ((p & 0x3f) << 13) | ((m & 0x1ff) << 4) | ((s & 0x7) << 1);
312
313 writel(reg, dsim->reg_base + EXYNOS_DSIM_PLLCTRL);
314}
315
316void exynos_mipi_dsi_pll_freq_band(struct mipi_dsim_device *dsim,
317 unsigned int freq_band)
318{
319 unsigned int reg = (readl(dsim->reg_base + EXYNOS_DSIM_PLLCTRL)) &
320 ~(DSIM_FREQ_BAND_SHIFT(0x1f));
321
322 reg |= DSIM_FREQ_BAND_SHIFT(freq_band & 0x1f);
323
324 writel(reg, dsim->reg_base + EXYNOS_DSIM_PLLCTRL);
325}
326
327void exynos_mipi_dsi_pll_freq(struct mipi_dsim_device *dsim,
328 unsigned int pre_divider, unsigned int main_divider,
329 unsigned int scaler)
330{
331 unsigned int reg = (readl(dsim->reg_base + EXYNOS_DSIM_PLLCTRL)) &
332 ~(0x7ffff << 1);
333
334 reg |= (pre_divider & 0x3f) << 13 | (main_divider & 0x1ff) << 4 |
335 (scaler & 0x7) << 1;
336
337 writel(reg, dsim->reg_base + EXYNOS_DSIM_PLLCTRL);
338}
339
340void exynos_mipi_dsi_pll_stable_time(struct mipi_dsim_device *dsim,
341 unsigned int lock_time)
342{
343 writel(lock_time, dsim->reg_base + EXYNOS_DSIM_PLLTMR);
344}
345
346void exynos_mipi_dsi_enable_pll(struct mipi_dsim_device *dsim, unsigned int enable)
347{
348 unsigned int reg = (readl(dsim->reg_base + EXYNOS_DSIM_PLLCTRL)) &
349 ~(DSIM_PLL_EN_SHIFT(0x1));
350
351 reg |= DSIM_PLL_EN_SHIFT(enable & 0x1);
352
353 writel(reg, dsim->reg_base + EXYNOS_DSIM_PLLCTRL);
354}
355
356void exynos_mipi_dsi_set_byte_clock_src(struct mipi_dsim_device *dsim,
357 unsigned int src)
358{
359 unsigned int reg = (readl(dsim->reg_base + EXYNOS_DSIM_CLKCTRL)) &
360 ~(DSIM_BYTE_CLK_SRC_SHIFT(0x3));
361
362 reg |= (DSIM_BYTE_CLK_SRC_SHIFT(src));
363
364 writel(reg, dsim->reg_base + EXYNOS_DSIM_CLKCTRL);
365}
366
367void exynos_mipi_dsi_enable_byte_clock(struct mipi_dsim_device *dsim,
368 unsigned int enable)
369{
370 unsigned int reg = (readl(dsim->reg_base + EXYNOS_DSIM_CLKCTRL)) &
371 ~(DSIM_BYTE_CLKEN_SHIFT(0x1));
372
373 reg |= DSIM_BYTE_CLKEN_SHIFT(enable);
374
375 writel(reg, dsim->reg_base + EXYNOS_DSIM_CLKCTRL);
376}
377
378void exynos_mipi_dsi_set_esc_clk_prs(struct mipi_dsim_device *dsim,
379 unsigned int enable, unsigned int prs_val)
380{
381 unsigned int reg = (readl(dsim->reg_base + EXYNOS_DSIM_CLKCTRL)) &
382 ~(DSIM_ESC_CLKEN_SHIFT(0x1) | 0xffff);
383
384 reg |= DSIM_ESC_CLKEN_SHIFT(enable);
385 if (enable)
386 reg |= prs_val;
387
388 writel(reg, dsim->reg_base + EXYNOS_DSIM_CLKCTRL);
389}
390
391void exynos_mipi_dsi_enable_esc_clk_on_lane(struct mipi_dsim_device *dsim,
392 unsigned int lane_sel, unsigned int enable)
393{
394 unsigned int reg = readl(dsim->reg_base + EXYNOS_DSIM_CLKCTRL);
395
396 if (enable)
397 reg |= DSIM_LANE_ESC_CLKEN(lane_sel);
398 else
399
400 reg &= ~DSIM_LANE_ESC_CLKEN(lane_sel);
401
402 writel(reg, dsim->reg_base + EXYNOS_DSIM_CLKCTRL);
403}
404
405void exynos_mipi_dsi_force_dphy_stop_state(struct mipi_dsim_device *dsim,
406 unsigned int enable)
407{
408 unsigned int reg = (readl(dsim->reg_base + EXYNOS_DSIM_ESCMODE)) &
409 ~(DSIM_FORCE_STOP_STATE_SHIFT(0x1));
410
411 reg |= (DSIM_FORCE_STOP_STATE_SHIFT(enable & 0x1));
412
413 writel(reg, dsim->reg_base + EXYNOS_DSIM_ESCMODE);
414}
415
416unsigned int exynos_mipi_dsi_is_lane_state(struct mipi_dsim_device *dsim)
417{
418 unsigned int reg = readl(dsim->reg_base + EXYNOS_DSIM_STATUS);
419
420 /**
421 * check clock and data lane states.
422 * if MIPI-DSI controller was enabled at bootloader then
423 * TX_READY_HS_CLK is enabled otherwise STOP_STATE_CLK.
424 * so it should be checked for two case.
425 */
426 if ((reg & DSIM_STOP_STATE_DAT(0xf)) &&
427 ((reg & DSIM_STOP_STATE_CLK) ||
428 (reg & DSIM_TX_READY_HS_CLK)))
429 return 1;
430
431 return 0;
432}
433
434void exynos_mipi_dsi_set_stop_state_counter(struct mipi_dsim_device *dsim,
435 unsigned int cnt_val)
436{
437 unsigned int reg = (readl(dsim->reg_base + EXYNOS_DSIM_ESCMODE)) &
438 ~(DSIM_STOP_STATE_CNT_SHIFT(0x7ff));
439
440 reg |= (DSIM_STOP_STATE_CNT_SHIFT(cnt_val & 0x7ff));
441
442 writel(reg, dsim->reg_base + EXYNOS_DSIM_ESCMODE);
443}
444
445void exynos_mipi_dsi_set_bta_timeout(struct mipi_dsim_device *dsim,
446 unsigned int timeout)
447{
448 unsigned int reg = (readl(dsim->reg_base + EXYNOS_DSIM_TIMEOUT)) &
449 ~(DSIM_BTA_TOUT_SHIFT(0xff));
450
451 reg |= (DSIM_BTA_TOUT_SHIFT(timeout));
452
453 writel(reg, dsim->reg_base + EXYNOS_DSIM_TIMEOUT);
454}
455
456void exynos_mipi_dsi_set_lpdr_timeout(struct mipi_dsim_device *dsim,
457 unsigned int timeout)
458{
459 unsigned int reg = (readl(dsim->reg_base + EXYNOS_DSIM_TIMEOUT)) &
460 ~(DSIM_LPDR_TOUT_SHIFT(0xffff));
461
462 reg |= (DSIM_LPDR_TOUT_SHIFT(timeout));
463
464 writel(reg, dsim->reg_base + EXYNOS_DSIM_TIMEOUT);
465}
466
467void exynos_mipi_dsi_set_cpu_transfer_mode(struct mipi_dsim_device *dsim,
468 unsigned int lp)
469{
470 unsigned int reg = readl(dsim->reg_base + EXYNOS_DSIM_ESCMODE);
471
472 reg &= ~DSIM_CMD_LPDT_LP;
473
474 if (lp)
475 reg |= DSIM_CMD_LPDT_LP;
476
477 writel(reg, dsim->reg_base + EXYNOS_DSIM_ESCMODE);
478}
479
480void exynos_mipi_dsi_set_lcdc_transfer_mode(struct mipi_dsim_device *dsim,
481 unsigned int lp)
482{
483 unsigned int reg = readl(dsim->reg_base + EXYNOS_DSIM_ESCMODE);
484
485 reg &= ~DSIM_TX_LPDT_LP;
486
487 if (lp)
488 reg |= DSIM_TX_LPDT_LP;
489
490 writel(reg, dsim->reg_base + EXYNOS_DSIM_ESCMODE);
491}
492
493void exynos_mipi_dsi_enable_hs_clock(struct mipi_dsim_device *dsim,
494 unsigned int enable)
495{
496 unsigned int reg = (readl(dsim->reg_base + EXYNOS_DSIM_CLKCTRL)) &
497 ~(DSIM_TX_REQUEST_HSCLK_SHIFT(0x1));
498
499 reg |= DSIM_TX_REQUEST_HSCLK_SHIFT(enable);
500
501 writel(reg, dsim->reg_base + EXYNOS_DSIM_CLKCTRL);
502}
503
504void exynos_mipi_dsi_dp_dn_swap(struct mipi_dsim_device *dsim,
505 unsigned int swap_en)
506{
507 unsigned int reg = readl(dsim->reg_base + EXYNOS_DSIM_PHYACCHR1);
508
509 reg &= ~(0x3 << 0);
510 reg |= (swap_en & 0x3) << 0;
511
512 writel(reg, dsim->reg_base + EXYNOS_DSIM_PHYACCHR1);
513}
514
515void exynos_mipi_dsi_hs_zero_ctrl(struct mipi_dsim_device *dsim,
516 unsigned int hs_zero)
517{
518 unsigned int reg = (readl(dsim->reg_base + EXYNOS_DSIM_PLLCTRL)) &
519 ~(0xf << 28);
520
521 reg |= ((hs_zero & 0xf) << 28);
522
523 writel(reg, dsim->reg_base + EXYNOS_DSIM_PLLCTRL);
524}
525
526void exynos_mipi_dsi_prep_ctrl(struct mipi_dsim_device *dsim, unsigned int prep)
527{
528 unsigned int reg = (readl(dsim->reg_base + EXYNOS_DSIM_PLLCTRL)) &
529 ~(0x7 << 20);
530
531 reg |= ((prep & 0x7) << 20);
532
533 writel(reg, dsim->reg_base + EXYNOS_DSIM_PLLCTRL);
534}
535
536unsigned int exynos_mipi_dsi_read_interrupt(struct mipi_dsim_device *dsim)
537{
538 return readl(dsim->reg_base + EXYNOS_DSIM_INTSRC);
539}
540
541void exynos_mipi_dsi_clear_interrupt(struct mipi_dsim_device *dsim,
542 unsigned int src)
543{
544 unsigned int reg = readl(dsim->reg_base + EXYNOS_DSIM_INTSRC);
545
546 reg |= src;
547
548 writel(reg, dsim->reg_base + EXYNOS_DSIM_INTSRC);
549}
550
551void exynos_mipi_dsi_set_interrupt(struct mipi_dsim_device *dsim,
552 unsigned int src, unsigned int enable)
553{
554 unsigned int reg = 0;
555
556 if (enable)
557 reg |= src;
558 else
559 reg &= ~src;
560
561 writel(reg, dsim->reg_base + EXYNOS_DSIM_INTSRC);
562}
563
564unsigned int exynos_mipi_dsi_is_pll_stable(struct mipi_dsim_device *dsim)
565{
566 unsigned int reg;
567
568 reg = readl(dsim->reg_base + EXYNOS_DSIM_STATUS);
569
570 return reg & (1 << 31) ? 1 : 0;
571}
572
573unsigned int exynos_mipi_dsi_get_fifo_state(struct mipi_dsim_device *dsim)
574{
575 return readl(dsim->reg_base + EXYNOS_DSIM_FIFOCTRL) & ~(0x1f);
576}
577
578void exynos_mipi_dsi_wr_tx_header(struct mipi_dsim_device *dsim,
579 unsigned int di, unsigned int data0, unsigned int data1)
580{
581 unsigned int reg = (data1 << 16) | (data0 << 8) | ((di & 0x3f) << 0);
582
583 writel(reg, dsim->reg_base + EXYNOS_DSIM_PKTHDR);
584}
585
586void exynos_mipi_dsi_rd_tx_header(struct mipi_dsim_device *dsim,
587 unsigned int di, unsigned int data0)
588{
589 unsigned int reg = (data0 << 8) | (di << 0);
590
591 writel(reg, dsim->reg_base + EXYNOS_DSIM_PKTHDR);
592}
593
594unsigned int exynos_mipi_dsi_rd_rx_fifo(struct mipi_dsim_device *dsim)
595{
596 return readl(dsim->reg_base + EXYNOS_DSIM_RXFIFO);
597}
598
599unsigned int _exynos_mipi_dsi_get_frame_done_status(struct mipi_dsim_device *dsim)
600{
601 unsigned int reg = readl(dsim->reg_base + EXYNOS_DSIM_INTSRC);
602
603 return (reg & INTSRC_FRAME_DONE) ? 1 : 0;
604}
605
606void _exynos_mipi_dsi_clear_frame_done(struct mipi_dsim_device *dsim)
607{
608 unsigned int reg = readl(dsim->reg_base + EXYNOS_DSIM_INTSRC);
609
610 writel(reg | INTSRC_FRAME_DONE, dsim->reg_base +
611 EXYNOS_DSIM_INTSRC);
612}
613
614void exynos_mipi_dsi_wr_tx_data(struct mipi_dsim_device *dsim,
615 unsigned int tx_data)
616{
617 writel(tx_data, dsim->reg_base + EXYNOS_DSIM_PAYLOAD);
618}
diff --git a/drivers/video/fbdev/exynos/exynos_mipi_dsi_lowlevel.h b/drivers/video/fbdev/exynos/exynos_mipi_dsi_lowlevel.h
new file mode 100644
index 000000000000..85460701c7ea
--- /dev/null
+++ b/drivers/video/fbdev/exynos/exynos_mipi_dsi_lowlevel.h
@@ -0,0 +1,112 @@
1/* linux/drivers/video/exynos/exynos_mipi_dsi_lowlevel.h
2 *
3 * Header file for Samsung SoC MIPI-DSI lowlevel driver.
4 *
5 * Copyright (c) 2012 Samsung Electronics Co., Ltd
6 *
7 * InKi Dae <inki.dae@samsung.com>
8 * Donghwa Lee <dh09.lee@samsung.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13*/
14
15#ifndef _EXYNOS_MIPI_DSI_LOWLEVEL_H
16#define _EXYNOS_MIPI_DSI_LOWLEVEL_H
17
18void exynos_mipi_dsi_func_reset(struct mipi_dsim_device *dsim);
19void exynos_mipi_dsi_sw_reset(struct mipi_dsim_device *dsim);
20void exynos_mipi_dsi_sw_reset_release(struct mipi_dsim_device *dsim);
21int exynos_mipi_dsi_get_sw_reset_release(struct mipi_dsim_device *dsim);
22void exynos_mipi_dsi_set_interrupt_mask(struct mipi_dsim_device *dsim,
23 unsigned int mode, unsigned int mask);
24void exynos_mipi_dsi_set_data_lane_number(struct mipi_dsim_device *dsim,
25 unsigned int count);
26void exynos_mipi_dsi_init_fifo_pointer(struct mipi_dsim_device *dsim,
27 unsigned int cfg);
28void exynos_mipi_dsi_set_phy_tunning(struct mipi_dsim_device *dsim,
29 unsigned int value);
30void exynos_mipi_dsi_set_phy_tunning(struct mipi_dsim_device *dsim,
31 unsigned int value);
32void exynos_mipi_dsi_set_main_stand_by(struct mipi_dsim_device *dsim,
33 unsigned int enable);
34void exynos_mipi_dsi_set_main_disp_resol(struct mipi_dsim_device *dsim,
35 unsigned int width_resol, unsigned int height_resol);
36void exynos_mipi_dsi_set_main_disp_vporch(struct mipi_dsim_device *dsim,
37 unsigned int cmd_allow, unsigned int vfront, unsigned int vback);
38void exynos_mipi_dsi_set_main_disp_hporch(struct mipi_dsim_device *dsim,
39 unsigned int front, unsigned int back);
40void exynos_mipi_dsi_set_main_disp_sync_area(struct mipi_dsim_device *dsim,
41 unsigned int vert, unsigned int hori);
42void exynos_mipi_dsi_set_sub_disp_resol(struct mipi_dsim_device *dsim,
43 unsigned int vert, unsigned int hori);
44void exynos_mipi_dsi_init_config(struct mipi_dsim_device *dsim);
45void exynos_mipi_dsi_display_config(struct mipi_dsim_device *dsim,
46 struct mipi_dsim_config *dsim_config);
47void exynos_mipi_dsi_set_data_lane_number(struct mipi_dsim_device *dsim,
48 unsigned int count);
49void exynos_mipi_dsi_enable_lane(struct mipi_dsim_device *dsim, unsigned int lane,
50 unsigned int enable);
51void exynos_mipi_dsi_enable_afc(struct mipi_dsim_device *dsim, unsigned int enable,
52 unsigned int afc_code);
53void exynos_mipi_dsi_enable_pll_bypass(struct mipi_dsim_device *dsim,
54 unsigned int enable);
55void exynos_mipi_dsi_set_pll_pms(struct mipi_dsim_device *dsim, unsigned int p,
56 unsigned int m, unsigned int s);
57void exynos_mipi_dsi_pll_freq_band(struct mipi_dsim_device *dsim,
58 unsigned int freq_band);
59void exynos_mipi_dsi_pll_freq(struct mipi_dsim_device *dsim,
60 unsigned int pre_divider, unsigned int main_divider,
61 unsigned int scaler);
62void exynos_mipi_dsi_pll_stable_time(struct mipi_dsim_device *dsim,
63 unsigned int lock_time);
64void exynos_mipi_dsi_enable_pll(struct mipi_dsim_device *dsim,
65 unsigned int enable);
66void exynos_mipi_dsi_set_byte_clock_src(struct mipi_dsim_device *dsim,
67 unsigned int src);
68void exynos_mipi_dsi_enable_byte_clock(struct mipi_dsim_device *dsim,
69 unsigned int enable);
70void exynos_mipi_dsi_set_esc_clk_prs(struct mipi_dsim_device *dsim,
71 unsigned int enable, unsigned int prs_val);
72void exynos_mipi_dsi_enable_esc_clk_on_lane(struct mipi_dsim_device *dsim,
73 unsigned int lane_sel, unsigned int enable);
74void exynos_mipi_dsi_force_dphy_stop_state(struct mipi_dsim_device *dsim,
75 unsigned int enable);
76unsigned int exynos_mipi_dsi_is_lane_state(struct mipi_dsim_device *dsim);
77void exynos_mipi_dsi_set_stop_state_counter(struct mipi_dsim_device *dsim,
78 unsigned int cnt_val);
79void exynos_mipi_dsi_set_bta_timeout(struct mipi_dsim_device *dsim,
80 unsigned int timeout);
81void exynos_mipi_dsi_set_lpdr_timeout(struct mipi_dsim_device *dsim,
82 unsigned int timeout);
83void exynos_mipi_dsi_set_lcdc_transfer_mode(struct mipi_dsim_device *dsim,
84 unsigned int lp);
85void exynos_mipi_dsi_set_cpu_transfer_mode(struct mipi_dsim_device *dsim,
86 unsigned int lp);
87void exynos_mipi_dsi_enable_hs_clock(struct mipi_dsim_device *dsim,
88 unsigned int enable);
89void exynos_mipi_dsi_dp_dn_swap(struct mipi_dsim_device *dsim,
90 unsigned int swap_en);
91void exynos_mipi_dsi_hs_zero_ctrl(struct mipi_dsim_device *dsim,
92 unsigned int hs_zero);
93void exynos_mipi_dsi_prep_ctrl(struct mipi_dsim_device *dsim, unsigned int prep);
94unsigned int exynos_mipi_dsi_read_interrupt(struct mipi_dsim_device *dsim);
95unsigned int exynos_mipi_dsi_read_interrupt_mask(struct mipi_dsim_device *dsim);
96void exynos_mipi_dsi_clear_interrupt(struct mipi_dsim_device *dsim,
97 unsigned int src);
98void exynos_mipi_dsi_set_interrupt(struct mipi_dsim_device *dsim,
99 unsigned int src, unsigned int enable);
100unsigned int exynos_mipi_dsi_is_pll_stable(struct mipi_dsim_device *dsim);
101unsigned int exynos_mipi_dsi_get_fifo_state(struct mipi_dsim_device *dsim);
102unsigned int _exynos_mipi_dsi_get_frame_done_status(struct mipi_dsim_device *dsim);
103void _exynos_mipi_dsi_clear_frame_done(struct mipi_dsim_device *dsim);
104void exynos_mipi_dsi_wr_tx_header(struct mipi_dsim_device *dsim, unsigned int di,
105 unsigned int data0, unsigned int data1);
106void exynos_mipi_dsi_wr_tx_data(struct mipi_dsim_device *dsim,
107 unsigned int tx_data);
108void exynos_mipi_dsi_rd_tx_header(struct mipi_dsim_device *dsim,
109 unsigned int data0, unsigned int data1);
110unsigned int exynos_mipi_dsi_rd_rx_fifo(struct mipi_dsim_device *dsim);
111
112#endif /* _EXYNOS_MIPI_DSI_LOWLEVEL_H */
diff --git a/drivers/video/fbdev/exynos/exynos_mipi_dsi_regs.h b/drivers/video/fbdev/exynos/exynos_mipi_dsi_regs.h
new file mode 100644
index 000000000000..4227106d3fd0
--- /dev/null
+++ b/drivers/video/fbdev/exynos/exynos_mipi_dsi_regs.h
@@ -0,0 +1,149 @@
1/* linux/driver/video/exynos/exynos_mipi_dsi_regs.h
2 *
3 * Register definition file for Samsung MIPI-DSIM driver
4 *
5 * Copyright (c) 2012 Samsung Electronics Co., Ltd
6 *
7 * InKi Dae <inki.dae@samsung.com>
8 * Donghwa Lee <dh09.lee@samsung.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13*/
14
15#ifndef _EXYNOS_MIPI_DSI_REGS_H
16#define _EXYNOS_MIPI_DSI_REGS_H
17
18#define EXYNOS_DSIM_STATUS 0x0 /* Status register */
19#define EXYNOS_DSIM_SWRST 0x4 /* Software reset register */
20#define EXYNOS_DSIM_CLKCTRL 0x8 /* Clock control register */
21#define EXYNOS_DSIM_TIMEOUT 0xc /* Time out register */
22#define EXYNOS_DSIM_CONFIG 0x10 /* Configuration register */
23#define EXYNOS_DSIM_ESCMODE 0x14 /* Escape mode register */
24
25/* Main display image resolution register */
26#define EXYNOS_DSIM_MDRESOL 0x18
27#define EXYNOS_DSIM_MVPORCH 0x1c /* Main display Vporch register */
28#define EXYNOS_DSIM_MHPORCH 0x20 /* Main display Hporch register */
29#define EXYNOS_DSIM_MSYNC 0x24 /* Main display sync area register */
30
31/* Sub display image resolution register */
32#define EXYNOS_DSIM_SDRESOL 0x28
33#define EXYNOS_DSIM_INTSRC 0x2c /* Interrupt source register */
34#define EXYNOS_DSIM_INTMSK 0x30 /* Interrupt mask register */
35#define EXYNOS_DSIM_PKTHDR 0x34 /* Packet Header FIFO register */
36#define EXYNOS_DSIM_PAYLOAD 0x38 /* Payload FIFO register */
37#define EXYNOS_DSIM_RXFIFO 0x3c /* Read FIFO register */
38#define EXYNOS_DSIM_FIFOTHLD 0x40 /* FIFO threshold level register */
39#define EXYNOS_DSIM_FIFOCTRL 0x44 /* FIFO status and control register */
40
41/* FIFO memory AC characteristic register */
42#define EXYNOS_DSIM_PLLCTRL 0x4c /* PLL control register */
43#define EXYNOS_DSIM_PLLTMR 0x50 /* PLL timer register */
44#define EXYNOS_DSIM_PHYACCHR 0x54 /* D-PHY AC characteristic register */
45#define EXYNOS_DSIM_PHYACCHR1 0x58 /* D-PHY AC characteristic register1 */
46
47/* DSIM_STATUS */
48#define DSIM_STOP_STATE_DAT(x) (((x) & 0xf) << 0)
49#define DSIM_STOP_STATE_CLK (1 << 8)
50#define DSIM_TX_READY_HS_CLK (1 << 10)
51
52/* DSIM_SWRST */
53#define DSIM_FUNCRST (1 << 16)
54#define DSIM_SWRST (1 << 0)
55
56/* EXYNOS_DSIM_TIMEOUT */
57#define DSIM_LPDR_TOUT_SHIFT(x) ((x) << 0)
58#define DSIM_BTA_TOUT_SHIFT(x) ((x) << 16)
59
60/* EXYNOS_DSIM_CLKCTRL */
61#define DSIM_LANE_ESC_CLKEN(x) (((x) & 0x1f) << 19)
62#define DSIM_BYTE_CLKEN_SHIFT(x) ((x) << 24)
63#define DSIM_BYTE_CLK_SRC_SHIFT(x) ((x) << 25)
64#define DSIM_PLL_BYPASS_SHIFT(x) ((x) << 27)
65#define DSIM_ESC_CLKEN_SHIFT(x) ((x) << 28)
66#define DSIM_TX_REQUEST_HSCLK_SHIFT(x) ((x) << 31)
67
68/* EXYNOS_DSIM_CONFIG */
69#define DSIM_LANE_ENx(x) (((x) & 0x1f) << 0)
70#define DSIM_NUM_OF_DATALANE_SHIFT(x) ((x) << 5)
71#define DSIM_HSA_MODE_SHIFT(x) ((x) << 20)
72#define DSIM_HBP_MODE_SHIFT(x) ((x) << 21)
73#define DSIM_HFP_MODE_SHIFT(x) ((x) << 22)
74#define DSIM_HSE_MODE_SHIFT(x) ((x) << 23)
75#define DSIM_AUTO_MODE_SHIFT(x) ((x) << 24)
76#define DSIM_EOT_DISABLE(x) ((x) << 28)
77#define DSIM_AUTO_FLUSH(x) ((x) << 29)
78
79#define DSIM_NUM_OF_DATA_LANE(x) ((x) << DSIM_NUM_OF_DATALANE_SHIFT)
80
81/* EXYNOS_DSIM_ESCMODE */
82#define DSIM_TX_LPDT_LP (1 << 6)
83#define DSIM_CMD_LPDT_LP (1 << 7)
84#define DSIM_FORCE_STOP_STATE_SHIFT(x) ((x) << 20)
85#define DSIM_STOP_STATE_CNT_SHIFT(x) ((x) << 21)
86
87/* EXYNOS_DSIM_MDRESOL */
88#define DSIM_MAIN_STAND_BY (1 << 31)
89#define DSIM_MAIN_VRESOL(x) (((x) & 0x7ff) << 16)
90#define DSIM_MAIN_HRESOL(x) (((x) & 0X7ff) << 0)
91
92/* EXYNOS_DSIM_MVPORCH */
93#define DSIM_CMD_ALLOW_SHIFT(x) ((x) << 28)
94#define DSIM_STABLE_VFP_SHIFT(x) ((x) << 16)
95#define DSIM_MAIN_VBP_SHIFT(x) ((x) << 0)
96#define DSIM_CMD_ALLOW_MASK (0xf << 28)
97#define DSIM_STABLE_VFP_MASK (0x7ff << 16)
98#define DSIM_MAIN_VBP_MASK (0x7ff << 0)
99
100/* EXYNOS_DSIM_MHPORCH */
101#define DSIM_MAIN_HFP_SHIFT(x) ((x) << 16)
102#define DSIM_MAIN_HBP_SHIFT(x) ((x) << 0)
103#define DSIM_MAIN_HFP_MASK ((0xffff) << 16)
104#define DSIM_MAIN_HBP_MASK ((0xffff) << 0)
105
106/* EXYNOS_DSIM_MSYNC */
107#define DSIM_MAIN_VSA_SHIFT(x) ((x) << 22)
108#define DSIM_MAIN_HSA_SHIFT(x) ((x) << 0)
109#define DSIM_MAIN_VSA_MASK ((0x3ff) << 22)
110#define DSIM_MAIN_HSA_MASK ((0xffff) << 0)
111
112/* EXYNOS_DSIM_SDRESOL */
113#define DSIM_SUB_STANDY_SHIFT(x) ((x) << 31)
114#define DSIM_SUB_VRESOL_SHIFT(x) ((x) << 16)
115#define DSIM_SUB_HRESOL_SHIFT(x) ((x) << 0)
116#define DSIM_SUB_STANDY_MASK ((0x1) << 31)
117#define DSIM_SUB_VRESOL_MASK ((0x7ff) << 16)
118#define DSIM_SUB_HRESOL_MASK ((0x7ff) << 0)
119
120/* EXYNOS_DSIM_INTSRC */
121#define INTSRC_PLL_STABLE (1 << 31)
122#define INTSRC_SW_RST_RELEASE (1 << 30)
123#define INTSRC_SFR_FIFO_EMPTY (1 << 29)
124#define INTSRC_FRAME_DONE (1 << 24)
125#define INTSRC_RX_DATA_DONE (1 << 18)
126
127/* EXYNOS_DSIM_INTMSK */
128#define INTMSK_FIFO_EMPTY (1 << 29)
129#define INTMSK_BTA (1 << 25)
130#define INTMSK_FRAME_DONE (1 << 24)
131#define INTMSK_RX_TIMEOUT (1 << 21)
132#define INTMSK_BTA_TIMEOUT (1 << 20)
133#define INTMSK_RX_DONE (1 << 18)
134#define INTMSK_RX_TE (1 << 17)
135#define INTMSK_RX_ACK (1 << 16)
136#define INTMSK_RX_ECC_ERR (1 << 15)
137#define INTMSK_RX_CRC_ERR (1 << 14)
138
139/* EXYNOS_DSIM_FIFOCTRL */
140#define SFR_HEADER_EMPTY (1 << 22)
141
142/* EXYNOS_DSIM_PHYACCHR */
143#define DSIM_AFC_CTL(x) (((x) & 0x7) << 5)
144
145/* EXYNOS_DSIM_PLLCTRL */
146#define DSIM_PLL_EN_SHIFT(x) ((x) << 23)
147#define DSIM_FREQ_BAND_SHIFT(x) ((x) << 24)
148
149#endif /* _EXYNOS_MIPI_DSI_REGS_H */
diff --git a/drivers/video/fbdev/exynos/s6e8ax0.c b/drivers/video/fbdev/exynos/s6e8ax0.c
new file mode 100644
index 000000000000..29e70ed3f154
--- /dev/null
+++ b/drivers/video/fbdev/exynos/s6e8ax0.c
@@ -0,0 +1,898 @@
1/* linux/drivers/video/exynos/s6e8ax0.c
2 *
3 * MIPI-DSI based s6e8ax0 AMOLED lcd 4.65 inch panel driver.
4 *
5 * Inki Dae, <inki.dae@samsung.com>
6 * Donghwa Lee, <dh09.lee@samsung.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11*/
12
13#include <linux/module.h>
14#include <linux/kernel.h>
15#include <linux/errno.h>
16#include <linux/mutex.h>
17#include <linux/wait.h>
18#include <linux/ctype.h>
19#include <linux/io.h>
20#include <linux/delay.h>
21#include <linux/irq.h>
22#include <linux/interrupt.h>
23#include <linux/lcd.h>
24#include <linux/fb.h>
25#include <linux/backlight.h>
26#include <linux/regulator/consumer.h>
27
28#include <video/mipi_display.h>
29#include <video/exynos_mipi_dsim.h>
30
31#define LDI_MTP_LENGTH 24
32#define DSIM_PM_STABLE_TIME 10
33#define MIN_BRIGHTNESS 0
34#define MAX_BRIGHTNESS 24
35#define GAMMA_TABLE_COUNT 26
36
37#define POWER_IS_ON(pwr) ((pwr) == FB_BLANK_UNBLANK)
38#define POWER_IS_OFF(pwr) ((pwr) == FB_BLANK_POWERDOWN)
39#define POWER_IS_NRM(pwr) ((pwr) == FB_BLANK_NORMAL)
40
41#define lcd_to_master(a) (a->dsim_dev->master)
42#define lcd_to_master_ops(a) ((lcd_to_master(a))->master_ops)
43
44enum {
45 DSIM_NONE_STATE = 0,
46 DSIM_RESUME_COMPLETE = 1,
47 DSIM_FRAME_DONE = 2,
48};
49
50struct s6e8ax0 {
51 struct device *dev;
52 unsigned int power;
53 unsigned int id;
54 unsigned int gamma;
55 unsigned int acl_enable;
56 unsigned int cur_acl;
57
58 struct lcd_device *ld;
59 struct backlight_device *bd;
60
61 struct mipi_dsim_lcd_device *dsim_dev;
62 struct lcd_platform_data *ddi_pd;
63 struct mutex lock;
64 bool enabled;
65};
66
67
68static struct regulator_bulk_data supplies[] = {
69 { .supply = "vdd3", },
70 { .supply = "vci", },
71};
72
73static void s6e8ax0_regulator_enable(struct s6e8ax0 *lcd)
74{
75 int ret = 0;
76 struct lcd_platform_data *pd = NULL;
77
78 pd = lcd->ddi_pd;
79 mutex_lock(&lcd->lock);
80 if (!lcd->enabled) {
81 ret = regulator_bulk_enable(ARRAY_SIZE(supplies), supplies);
82 if (ret)
83 goto out;
84
85 lcd->enabled = true;
86 }
87 msleep(pd->power_on_delay);
88out:
89 mutex_unlock(&lcd->lock);
90}
91
92static void s6e8ax0_regulator_disable(struct s6e8ax0 *lcd)
93{
94 int ret = 0;
95
96 mutex_lock(&lcd->lock);
97 if (lcd->enabled) {
98 ret = regulator_bulk_disable(ARRAY_SIZE(supplies), supplies);
99 if (ret)
100 goto out;
101
102 lcd->enabled = false;
103 }
104out:
105 mutex_unlock(&lcd->lock);
106}
107
108static const unsigned char s6e8ax0_22_gamma_30[] = {
109 0xfa, 0x01, 0x60, 0x10, 0x60, 0xf5, 0x00, 0xff, 0xad, 0xaf,
110 0xbA, 0xc3, 0xd8, 0xc5, 0x9f, 0xc6, 0x9e, 0xc1, 0xdc, 0xc0,
111 0x00, 0x61, 0x00, 0x5a, 0x00, 0x74,
112};
113
114static const unsigned char s6e8ax0_22_gamma_50[] = {
115 0xfa, 0x01, 0x60, 0x10, 0x60, 0xe8, 0x1f, 0xf7, 0xad, 0xc0,
116 0xb5, 0xc4, 0xdc, 0xc4, 0x9e, 0xc6, 0x9c, 0xbb, 0xd8, 0xbb,
117 0x00, 0x70, 0x00, 0x68, 0x00, 0x86,
118};
119
120static const unsigned char s6e8ax0_22_gamma_60[] = {
121 0xfa, 0x01, 0x60, 0x10, 0x60, 0xde, 0x1f, 0xef, 0xad, 0xc4,
122 0xb3, 0xc3, 0xdd, 0xc4, 0x9e, 0xc6, 0x9c, 0xbc, 0xd6, 0xba,
123 0x00, 0x75, 0x00, 0x6e, 0x00, 0x8d,
124};
125
126static const unsigned char s6e8ax0_22_gamma_70[] = {
127 0xfa, 0x01, 0x60, 0x10, 0x60, 0xd8, 0x1f, 0xe7, 0xaf, 0xc8,
128 0xb4, 0xc4, 0xdd, 0xc3, 0x9d, 0xc6, 0x9c, 0xbb, 0xd6, 0xb9,
129 0x00, 0x7a, 0x00, 0x72, 0x00, 0x93,
130};
131
132static const unsigned char s6e8ax0_22_gamma_80[] = {
133 0xfa, 0x01, 0x60, 0x10, 0x60, 0xc9, 0x1f, 0xde, 0xae, 0xc9,
134 0xb1, 0xc3, 0xdd, 0xc2, 0x9d, 0xc5, 0x9b, 0xbc, 0xd6, 0xbb,
135 0x00, 0x7f, 0x00, 0x77, 0x00, 0x99,
136};
137
138static const unsigned char s6e8ax0_22_gamma_90[] = {
139 0xfa, 0x01, 0x60, 0x10, 0x60, 0xc7, 0x1f, 0xd9, 0xb0, 0xcc,
140 0xb2, 0xc3, 0xdc, 0xc1, 0x9c, 0xc6, 0x9c, 0xbc, 0xd4, 0xb9,
141 0x00, 0x83, 0x00, 0x7b, 0x00, 0x9e,
142};
143
144static const unsigned char s6e8ax0_22_gamma_100[] = {
145 0xfa, 0x01, 0x60, 0x10, 0x60, 0xbd, 0x80, 0xcd, 0xba, 0xce,
146 0xb3, 0xc4, 0xde, 0xc3, 0x9c, 0xc4, 0x9, 0xb8, 0xd3, 0xb6,
147 0x00, 0x88, 0x00, 0x80, 0x00, 0xa5,
148};
149
150static const unsigned char s6e8ax0_22_gamma_120[] = {
151 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb9, 0x95, 0xc8, 0xb1, 0xcf,
152 0xb2, 0xc6, 0xdf, 0xc5, 0x9b, 0xc3, 0x99, 0xb6, 0xd2, 0xb6,
153 0x00, 0x8f, 0x00, 0x86, 0x00, 0xac,
154};
155
156static const unsigned char s6e8ax0_22_gamma_130[] = {
157 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb7, 0xa0, 0xc7, 0xb1, 0xd0,
158 0xb2, 0xc4, 0xdd, 0xc3, 0x9a, 0xc3, 0x98, 0xb6, 0xd0, 0xb4,
159 0x00, 0x92, 0x00, 0x8a, 0x00, 0xb1,
160};
161
162static const unsigned char s6e8ax0_22_gamma_140[] = {
163 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb7, 0xa0, 0xc5, 0xb2, 0xd0,
164 0xb3, 0xc3, 0xde, 0xc3, 0x9b, 0xc2, 0x98, 0xb6, 0xd0, 0xb4,
165 0x00, 0x95, 0x00, 0x8d, 0x00, 0xb5,
166};
167
168static const unsigned char s6e8ax0_22_gamma_150[] = {
169 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb3, 0xa0, 0xc2, 0xb2, 0xd0,
170 0xb2, 0xc1, 0xdd, 0xc2, 0x9b, 0xc2, 0x98, 0xb4, 0xcf, 0xb1,
171 0x00, 0x99, 0x00, 0x90, 0x00, 0xba,
172};
173
174static const unsigned char s6e8ax0_22_gamma_160[] = {
175 0xfa, 0x01, 0x60, 0x10, 0x60, 0xaf, 0xa5, 0xbf, 0xb0, 0xd0,
176 0xb1, 0xc3, 0xde, 0xc2, 0x99, 0xc1, 0x97, 0xb4, 0xce, 0xb1,
177 0x00, 0x9c, 0x00, 0x93, 0x00, 0xbe,
178};
179
180static const unsigned char s6e8ax0_22_gamma_170[] = {
181 0xfa, 0x01, 0x60, 0x10, 0x60, 0xaf, 0xb5, 0xbf, 0xb1, 0xd1,
182 0xb1, 0xc3, 0xde, 0xc3, 0x99, 0xc0, 0x96, 0xb4, 0xce, 0xb1,
183 0x00, 0x9f, 0x00, 0x96, 0x00, 0xc2,
184};
185
186static const unsigned char s6e8ax0_22_gamma_180[] = {
187 0xfa, 0x01, 0x60, 0x10, 0x60, 0xaf, 0xb7, 0xbe, 0xb3, 0xd2,
188 0xb3, 0xc3, 0xde, 0xc2, 0x97, 0xbf, 0x95, 0xb4, 0xcd, 0xb1,
189 0x00, 0xa2, 0x00, 0x99, 0x00, 0xc5,
190};
191
192static const unsigned char s6e8ax0_22_gamma_190[] = {
193 0xfa, 0x01, 0x60, 0x10, 0x60, 0xaf, 0xb9, 0xbe, 0xb2, 0xd2,
194 0xb2, 0xc3, 0xdd, 0xc3, 0x98, 0xbf, 0x95, 0xb2, 0xcc, 0xaf,
195 0x00, 0xa5, 0x00, 0x9c, 0x00, 0xc9,
196};
197
198static const unsigned char s6e8ax0_22_gamma_200[] = {
199 0xfa, 0x01, 0x60, 0x10, 0x60, 0xaf, 0xb9, 0xbc, 0xb2, 0xd2,
200 0xb1, 0xc4, 0xdd, 0xc3, 0x97, 0xbe, 0x95, 0xb1, 0xcb, 0xae,
201 0x00, 0xa8, 0x00, 0x9f, 0x00, 0xcd,
202};
203
204static const unsigned char s6e8ax0_22_gamma_210[] = {
205 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb1, 0xc1, 0xbd, 0xb1, 0xd1,
206 0xb1, 0xc2, 0xde, 0xc2, 0x97, 0xbe, 0x94, 0xB0, 0xc9, 0xad,
207 0x00, 0xae, 0x00, 0xa4, 0x00, 0xd4,
208};
209
210static const unsigned char s6e8ax0_22_gamma_220[] = {
211 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb1, 0xc7, 0xbd, 0xb1, 0xd1,
212 0xb1, 0xc2, 0xdd, 0xc2, 0x97, 0xbd, 0x94, 0xb0, 0xc9, 0xad,
213 0x00, 0xad, 0x00, 0xa2, 0x00, 0xd3,
214};
215
216static const unsigned char s6e8ax0_22_gamma_230[] = {
217 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb1, 0xc3, 0xbd, 0xb2, 0xd1,
218 0xb1, 0xc3, 0xdd, 0xc1, 0x96, 0xbd, 0x94, 0xb0, 0xc9, 0xad,
219 0x00, 0xb0, 0x00, 0xa7, 0x00, 0xd7,
220};
221
222static const unsigned char s6e8ax0_22_gamma_240[] = {
223 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb1, 0xcb, 0xbd, 0xb1, 0xd2,
224 0xb1, 0xc3, 0xdD, 0xc2, 0x95, 0xbd, 0x93, 0xaf, 0xc8, 0xab,
225 0x00, 0xb3, 0x00, 0xa9, 0x00, 0xdb,
226};
227
228static const unsigned char s6e8ax0_22_gamma_250[] = {
229 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb3, 0xcc, 0xbe, 0xb0, 0xd2,
230 0xb0, 0xc3, 0xdD, 0xc2, 0x94, 0xbc, 0x92, 0xae, 0xc8, 0xab,
231 0x00, 0xb6, 0x00, 0xab, 0x00, 0xde,
232};
233
234static const unsigned char s6e8ax0_22_gamma_260[] = {
235 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb3, 0xd0, 0xbe, 0xaf, 0xd1,
236 0xaf, 0xc2, 0xdd, 0xc1, 0x96, 0xbc, 0x93, 0xaf, 0xc8, 0xac,
237 0x00, 0xb7, 0x00, 0xad, 0x00, 0xe0,
238};
239
240static const unsigned char s6e8ax0_22_gamma_270[] = {
241 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb2, 0xcF, 0xbd, 0xb0, 0xd2,
242 0xaf, 0xc2, 0xdc, 0xc1, 0x95, 0xbd, 0x93, 0xae, 0xc6, 0xaa,
243 0x00, 0xba, 0x00, 0xb0, 0x00, 0xe4,
244};
245
246static const unsigned char s6e8ax0_22_gamma_280[] = {
247 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb2, 0xd0, 0xbd, 0xaf, 0xd0,
248 0xad, 0xc4, 0xdd, 0xc3, 0x95, 0xbd, 0x93, 0xac, 0xc5, 0xa9,
249 0x00, 0xbd, 0x00, 0xb2, 0x00, 0xe7,
250};
251
252static const unsigned char s6e8ax0_22_gamma_300[] = {
253 0xfa, 0x01, 0x60, 0x10, 0x60, 0xb5, 0xd3, 0xbd, 0xb1, 0xd2,
254 0xb0, 0xc0, 0xdc, 0xc0, 0x94, 0xba, 0x91, 0xac, 0xc5, 0xa9,
255 0x00, 0xc2, 0x00, 0xb7, 0x00, 0xed,
256};
257
258static const unsigned char *s6e8ax0_22_gamma_table[] = {
259 s6e8ax0_22_gamma_30,
260 s6e8ax0_22_gamma_50,
261 s6e8ax0_22_gamma_60,
262 s6e8ax0_22_gamma_70,
263 s6e8ax0_22_gamma_80,
264 s6e8ax0_22_gamma_90,
265 s6e8ax0_22_gamma_100,
266 s6e8ax0_22_gamma_120,
267 s6e8ax0_22_gamma_130,
268 s6e8ax0_22_gamma_140,
269 s6e8ax0_22_gamma_150,
270 s6e8ax0_22_gamma_160,
271 s6e8ax0_22_gamma_170,
272 s6e8ax0_22_gamma_180,
273 s6e8ax0_22_gamma_190,
274 s6e8ax0_22_gamma_200,
275 s6e8ax0_22_gamma_210,
276 s6e8ax0_22_gamma_220,
277 s6e8ax0_22_gamma_230,
278 s6e8ax0_22_gamma_240,
279 s6e8ax0_22_gamma_250,
280 s6e8ax0_22_gamma_260,
281 s6e8ax0_22_gamma_270,
282 s6e8ax0_22_gamma_280,
283 s6e8ax0_22_gamma_300,
284};
285
286static void s6e8ax0_panel_cond(struct s6e8ax0 *lcd)
287{
288 struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
289
290 static const unsigned char data_to_send[] = {
291 0xf8, 0x3d, 0x35, 0x00, 0x00, 0x00, 0x93, 0x00, 0x3c, 0x7d,
292 0x08, 0x27, 0x7d, 0x3f, 0x00, 0x00, 0x00, 0x20, 0x04, 0x08,
293 0x6e, 0x00, 0x00, 0x00, 0x02, 0x08, 0x08, 0x23, 0x23, 0xc0,
294 0xc8, 0x08, 0x48, 0xc1, 0x00, 0xc1, 0xff, 0xff, 0xc8
295 };
296 static const unsigned char data_to_send_panel_reverse[] = {
297 0xf8, 0x19, 0x35, 0x00, 0x00, 0x00, 0x93, 0x00, 0x3c, 0x7d,
298 0x08, 0x27, 0x7d, 0x3f, 0x00, 0x00, 0x00, 0x20, 0x04, 0x08,
299 0x6e, 0x00, 0x00, 0x00, 0x02, 0x08, 0x08, 0x23, 0x23, 0xc0,
300 0xc1, 0x01, 0x41, 0xc1, 0x00, 0xc1, 0xf6, 0xf6, 0xc1
301 };
302
303 if (lcd->dsim_dev->panel_reverse)
304 ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
305 data_to_send_panel_reverse,
306 ARRAY_SIZE(data_to_send_panel_reverse));
307 else
308 ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
309 data_to_send, ARRAY_SIZE(data_to_send));
310}
311
312static void s6e8ax0_display_cond(struct s6e8ax0 *lcd)
313{
314 struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
315 static const unsigned char data_to_send[] = {
316 0xf2, 0x80, 0x03, 0x0d
317 };
318
319 ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
320 data_to_send, ARRAY_SIZE(data_to_send));
321}
322
323/* Gamma 2.2 Setting (200cd, 7500K, 10MPCD) */
324static void s6e8ax0_gamma_cond(struct s6e8ax0 *lcd)
325{
326 struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
327 unsigned int gamma = lcd->bd->props.brightness;
328
329 ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
330 s6e8ax0_22_gamma_table[gamma],
331 GAMMA_TABLE_COUNT);
332}
333
334static void s6e8ax0_gamma_update(struct s6e8ax0 *lcd)
335{
336 struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
337 static const unsigned char data_to_send[] = {
338 0xf7, 0x03
339 };
340
341 ops->cmd_write(lcd_to_master(lcd),
342 MIPI_DSI_DCS_SHORT_WRITE_PARAM, data_to_send,
343 ARRAY_SIZE(data_to_send));
344}
345
346static void s6e8ax0_etc_cond1(struct s6e8ax0 *lcd)
347{
348 struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
349 static const unsigned char data_to_send[] = {
350 0xd1, 0xfe, 0x80, 0x00, 0x01, 0x0b, 0x00, 0x00, 0x40,
351 0x0d, 0x00, 0x00
352 };
353
354 ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
355 data_to_send, ARRAY_SIZE(data_to_send));
356}
357
358static void s6e8ax0_etc_cond2(struct s6e8ax0 *lcd)
359{
360 struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
361 static const unsigned char data_to_send[] = {
362 0xb6, 0x0c, 0x02, 0x03, 0x32, 0xff, 0x44, 0x44, 0xc0,
363 0x00
364 };
365
366 ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
367 data_to_send, ARRAY_SIZE(data_to_send));
368}
369
370static void s6e8ax0_etc_cond3(struct s6e8ax0 *lcd)
371{
372 struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
373 static const unsigned char data_to_send[] = {
374 0xe1, 0x10, 0x1c, 0x17, 0x08, 0x1d
375 };
376
377 ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
378 data_to_send, ARRAY_SIZE(data_to_send));
379}
380
381static void s6e8ax0_etc_cond4(struct s6e8ax0 *lcd)
382{
383 struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
384 static const unsigned char data_to_send[] = {
385 0xe2, 0xed, 0x07, 0xc3, 0x13, 0x0d, 0x03
386 };
387
388 ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
389 data_to_send, ARRAY_SIZE(data_to_send));
390}
391
392static void s6e8ax0_etc_cond5(struct s6e8ax0 *lcd)
393{
394 struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
395 static const unsigned char data_to_send[] = {
396 0xf4, 0xcf, 0x0a, 0x12, 0x10, 0x19, 0x33, 0x02
397 };
398
399 ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
400 data_to_send, ARRAY_SIZE(data_to_send));
401}
402static void s6e8ax0_etc_cond6(struct s6e8ax0 *lcd)
403{
404 struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
405 static const unsigned char data_to_send[] = {
406 0xe3, 0x40
407 };
408
409 ops->cmd_write(lcd_to_master(lcd),
410 MIPI_DSI_DCS_SHORT_WRITE_PARAM,
411 data_to_send, ARRAY_SIZE(data_to_send));
412}
413
414static void s6e8ax0_etc_cond7(struct s6e8ax0 *lcd)
415{
416 struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
417 static const unsigned char data_to_send[] = {
418 0xe4, 0x00, 0x00, 0x14, 0x80, 0x00, 0x00, 0x00
419 };
420
421 ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
422 data_to_send, ARRAY_SIZE(data_to_send));
423}
424
425static void s6e8ax0_elvss_set(struct s6e8ax0 *lcd)
426{
427 struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
428 static const unsigned char data_to_send[] = {
429 0xb1, 0x04, 0x00
430 };
431
432 ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
433 data_to_send, ARRAY_SIZE(data_to_send));
434}
435
436static void s6e8ax0_elvss_nvm_set(struct s6e8ax0 *lcd)
437{
438 struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
439 static const unsigned char data_to_send[] = {
440 0xd9, 0x5c, 0x20, 0x0c, 0x0f, 0x41, 0x00, 0x10, 0x11,
441 0x12, 0xd1, 0x00, 0x00, 0x00, 0x00, 0x80, 0xcb, 0xed,
442 0x64, 0xaf
443 };
444
445 ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
446 data_to_send, ARRAY_SIZE(data_to_send));
447}
448
449static void s6e8ax0_sleep_in(struct s6e8ax0 *lcd)
450{
451 struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
452 static const unsigned char data_to_send[] = {
453 0x10, 0x00
454 };
455
456 ops->cmd_write(lcd_to_master(lcd),
457 MIPI_DSI_DCS_SHORT_WRITE,
458 data_to_send, ARRAY_SIZE(data_to_send));
459}
460
461static void s6e8ax0_sleep_out(struct s6e8ax0 *lcd)
462{
463 struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
464 static const unsigned char data_to_send[] = {
465 0x11, 0x00
466 };
467
468 ops->cmd_write(lcd_to_master(lcd),
469 MIPI_DSI_DCS_SHORT_WRITE,
470 data_to_send, ARRAY_SIZE(data_to_send));
471}
472
473static void s6e8ax0_display_on(struct s6e8ax0 *lcd)
474{
475 struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
476 static const unsigned char data_to_send[] = {
477 0x29, 0x00
478 };
479
480 ops->cmd_write(lcd_to_master(lcd),
481 MIPI_DSI_DCS_SHORT_WRITE,
482 data_to_send, ARRAY_SIZE(data_to_send));
483}
484
485static void s6e8ax0_display_off(struct s6e8ax0 *lcd)
486{
487 struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
488 static const unsigned char data_to_send[] = {
489 0x28, 0x00
490 };
491
492 ops->cmd_write(lcd_to_master(lcd),
493 MIPI_DSI_DCS_SHORT_WRITE,
494 data_to_send, ARRAY_SIZE(data_to_send));
495}
496
497static void s6e8ax0_apply_level2_key(struct s6e8ax0 *lcd)
498{
499 struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
500 static const unsigned char data_to_send[] = {
501 0xf0, 0x5a, 0x5a
502 };
503
504 ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
505 data_to_send, ARRAY_SIZE(data_to_send));
506}
507
508static void s6e8ax0_acl_on(struct s6e8ax0 *lcd)
509{
510 struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
511 static const unsigned char data_to_send[] = {
512 0xc0, 0x01
513 };
514
515 ops->cmd_write(lcd_to_master(lcd),
516 MIPI_DSI_DCS_SHORT_WRITE,
517 data_to_send, ARRAY_SIZE(data_to_send));
518}
519
520static void s6e8ax0_acl_off(struct s6e8ax0 *lcd)
521{
522 struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
523 static const unsigned char data_to_send[] = {
524 0xc0, 0x00
525 };
526
527 ops->cmd_write(lcd_to_master(lcd),
528 MIPI_DSI_DCS_SHORT_WRITE,
529 data_to_send, ARRAY_SIZE(data_to_send));
530}
531
532/* Full white 50% reducing setting */
533static void s6e8ax0_acl_ctrl_set(struct s6e8ax0 *lcd)
534{
535 struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
536 /* Full white 50% reducing setting */
537 static const unsigned char cutoff_50[] = {
538 0xc1, 0x47, 0x53, 0x13, 0x53, 0x00, 0x00, 0x02, 0xcf,
539 0x00, 0x00, 0x04, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
540 0x01, 0x08, 0x0f, 0x16, 0x1d, 0x24, 0x2a, 0x31, 0x38,
541 0x3f, 0x46
542 };
543 /* Full white 45% reducing setting */
544 static const unsigned char cutoff_45[] = {
545 0xc1, 0x47, 0x53, 0x13, 0x53, 0x00, 0x00, 0x02, 0xcf,
546 0x00, 0x00, 0x04, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
547 0x01, 0x07, 0x0d, 0x13, 0x19, 0x1f, 0x25, 0x2b, 0x31,
548 0x37, 0x3d
549 };
550 /* Full white 40% reducing setting */
551 static const unsigned char cutoff_40[] = {
552 0xc1, 0x47, 0x53, 0x13, 0x53, 0x00, 0x00, 0x02, 0xcf,
553 0x00, 0x00, 0x04, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
554 0x01, 0x06, 0x0c, 0x11, 0x16, 0x1c, 0x21, 0x26, 0x2b,
555 0x31, 0x36
556 };
557
558 if (lcd->acl_enable) {
559 if (lcd->cur_acl == 0) {
560 if (lcd->gamma == 0 || lcd->gamma == 1) {
561 s6e8ax0_acl_off(lcd);
562 dev_dbg(&lcd->ld->dev,
563 "cur_acl=%d\n", lcd->cur_acl);
564 } else
565 s6e8ax0_acl_on(lcd);
566 }
567 switch (lcd->gamma) {
568 case 0: /* 30cd */
569 s6e8ax0_acl_off(lcd);
570 lcd->cur_acl = 0;
571 break;
572 case 1 ... 3: /* 50cd ~ 90cd */
573 ops->cmd_write(lcd_to_master(lcd),
574 MIPI_DSI_DCS_LONG_WRITE,
575 cutoff_40,
576 ARRAY_SIZE(cutoff_40));
577 lcd->cur_acl = 40;
578 break;
579 case 4 ... 7: /* 120cd ~ 210cd */
580 ops->cmd_write(lcd_to_master(lcd),
581 MIPI_DSI_DCS_LONG_WRITE,
582 cutoff_45,
583 ARRAY_SIZE(cutoff_45));
584 lcd->cur_acl = 45;
585 break;
586 case 8 ... 10: /* 220cd ~ 300cd */
587 ops->cmd_write(lcd_to_master(lcd),
588 MIPI_DSI_DCS_LONG_WRITE,
589 cutoff_50,
590 ARRAY_SIZE(cutoff_50));
591 lcd->cur_acl = 50;
592 break;
593 default:
594 break;
595 }
596 } else {
597 s6e8ax0_acl_off(lcd);
598 lcd->cur_acl = 0;
599 dev_dbg(&lcd->ld->dev, "cur_acl = %d\n", lcd->cur_acl);
600 }
601}
602
603static void s6e8ax0_read_id(struct s6e8ax0 *lcd, u8 *mtp_id)
604{
605 unsigned int ret;
606 unsigned int addr = 0xd1; /* MTP ID */
607 struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
608
609 ret = ops->cmd_read(lcd_to_master(lcd),
610 MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM,
611 addr, 3, mtp_id);
612}
613
614static int s6e8ax0_panel_init(struct s6e8ax0 *lcd)
615{
616 s6e8ax0_apply_level2_key(lcd);
617 s6e8ax0_sleep_out(lcd);
618 msleep(1);
619 s6e8ax0_panel_cond(lcd);
620 s6e8ax0_display_cond(lcd);
621 s6e8ax0_gamma_cond(lcd);
622 s6e8ax0_gamma_update(lcd);
623
624 s6e8ax0_etc_cond1(lcd);
625 s6e8ax0_etc_cond2(lcd);
626 s6e8ax0_etc_cond3(lcd);
627 s6e8ax0_etc_cond4(lcd);
628 s6e8ax0_etc_cond5(lcd);
629 s6e8ax0_etc_cond6(lcd);
630 s6e8ax0_etc_cond7(lcd);
631
632 s6e8ax0_elvss_nvm_set(lcd);
633 s6e8ax0_elvss_set(lcd);
634
635 s6e8ax0_acl_ctrl_set(lcd);
636 s6e8ax0_acl_on(lcd);
637
638 /* if ID3 value is not 33h, branch private elvss mode */
639 msleep(lcd->ddi_pd->power_on_delay);
640
641 return 0;
642}
643
644static int s6e8ax0_update_gamma_ctrl(struct s6e8ax0 *lcd, int brightness)
645{
646 struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
647
648 ops->cmd_write(lcd_to_master(lcd), MIPI_DSI_DCS_LONG_WRITE,
649 s6e8ax0_22_gamma_table[brightness],
650 ARRAY_SIZE(s6e8ax0_22_gamma_table));
651
652 /* update gamma table. */
653 s6e8ax0_gamma_update(lcd);
654 lcd->gamma = brightness;
655
656 return 0;
657}
658
659static int s6e8ax0_gamma_ctrl(struct s6e8ax0 *lcd, int gamma)
660{
661 s6e8ax0_update_gamma_ctrl(lcd, gamma);
662
663 return 0;
664}
665
666static int s6e8ax0_set_power(struct lcd_device *ld, int power)
667{
668 struct s6e8ax0 *lcd = lcd_get_data(ld);
669 struct mipi_dsim_master_ops *ops = lcd_to_master_ops(lcd);
670 int ret = 0;
671
672 if (power != FB_BLANK_UNBLANK && power != FB_BLANK_POWERDOWN &&
673 power != FB_BLANK_NORMAL) {
674 dev_err(lcd->dev, "power value should be 0, 1 or 4.\n");
675 return -EINVAL;
676 }
677
678 if ((power == FB_BLANK_UNBLANK) && ops->set_blank_mode) {
679 /* LCD power on */
680 if ((POWER_IS_ON(power) && POWER_IS_OFF(lcd->power))
681 || (POWER_IS_ON(power) && POWER_IS_NRM(lcd->power))) {
682 ret = ops->set_blank_mode(lcd_to_master(lcd), power);
683 if (!ret && lcd->power != power)
684 lcd->power = power;
685 }
686 } else if ((power == FB_BLANK_POWERDOWN) && ops->set_early_blank_mode) {
687 /* LCD power off */
688 if ((POWER_IS_OFF(power) && POWER_IS_ON(lcd->power)) ||
689 (POWER_IS_ON(lcd->power) && POWER_IS_NRM(power))) {
690 ret = ops->set_early_blank_mode(lcd_to_master(lcd),
691 power);
692 if (!ret && lcd->power != power)
693 lcd->power = power;
694 }
695 }
696
697 return ret;
698}
699
700static int s6e8ax0_get_power(struct lcd_device *ld)
701{
702 struct s6e8ax0 *lcd = lcd_get_data(ld);
703
704 return lcd->power;
705}
706
707static int s6e8ax0_get_brightness(struct backlight_device *bd)
708{
709 return bd->props.brightness;
710}
711
712static int s6e8ax0_set_brightness(struct backlight_device *bd)
713{
714 int ret = 0, brightness = bd->props.brightness;
715 struct s6e8ax0 *lcd = bl_get_data(bd);
716
717 if (brightness < MIN_BRIGHTNESS ||
718 brightness > bd->props.max_brightness) {
719 dev_err(lcd->dev, "lcd brightness should be %d to %d.\n",
720 MIN_BRIGHTNESS, MAX_BRIGHTNESS);
721 return -EINVAL;
722 }
723
724 ret = s6e8ax0_gamma_ctrl(lcd, brightness);
725 if (ret) {
726 dev_err(&bd->dev, "lcd brightness setting failed.\n");
727 return -EIO;
728 }
729
730 return ret;
731}
732
733static struct lcd_ops s6e8ax0_lcd_ops = {
734 .set_power = s6e8ax0_set_power,
735 .get_power = s6e8ax0_get_power,
736};
737
738static const struct backlight_ops s6e8ax0_backlight_ops = {
739 .get_brightness = s6e8ax0_get_brightness,
740 .update_status = s6e8ax0_set_brightness,
741};
742
743static void s6e8ax0_power_on(struct mipi_dsim_lcd_device *dsim_dev, int power)
744{
745 struct s6e8ax0 *lcd = dev_get_drvdata(&dsim_dev->dev);
746
747 msleep(lcd->ddi_pd->power_on_delay);
748
749 /* lcd power on */
750 if (power)
751 s6e8ax0_regulator_enable(lcd);
752 else
753 s6e8ax0_regulator_disable(lcd);
754
755 msleep(lcd->ddi_pd->reset_delay);
756
757 /* lcd reset */
758 if (lcd->ddi_pd->reset)
759 lcd->ddi_pd->reset(lcd->ld);
760 msleep(5);
761}
762
763static void s6e8ax0_set_sequence(struct mipi_dsim_lcd_device *dsim_dev)
764{
765 struct s6e8ax0 *lcd = dev_get_drvdata(&dsim_dev->dev);
766
767 s6e8ax0_panel_init(lcd);
768 s6e8ax0_display_on(lcd);
769
770 lcd->power = FB_BLANK_UNBLANK;
771}
772
773static int s6e8ax0_probe(struct mipi_dsim_lcd_device *dsim_dev)
774{
775 struct s6e8ax0 *lcd;
776 int ret;
777 u8 mtp_id[3] = {0, };
778
779 lcd = devm_kzalloc(&dsim_dev->dev, sizeof(struct s6e8ax0), GFP_KERNEL);
780 if (!lcd) {
781 dev_err(&dsim_dev->dev, "failed to allocate s6e8ax0 structure.\n");
782 return -ENOMEM;
783 }
784
785 lcd->dsim_dev = dsim_dev;
786 lcd->ddi_pd = (struct lcd_platform_data *)dsim_dev->platform_data;
787 lcd->dev = &dsim_dev->dev;
788
789 mutex_init(&lcd->lock);
790
791 ret = devm_regulator_bulk_get(lcd->dev, ARRAY_SIZE(supplies), supplies);
792 if (ret) {
793 dev_err(lcd->dev, "Failed to get regulators: %d\n", ret);
794 return ret;
795 }
796
797 lcd->ld = devm_lcd_device_register(lcd->dev, "s6e8ax0", lcd->dev, lcd,
798 &s6e8ax0_lcd_ops);
799 if (IS_ERR(lcd->ld)) {
800 dev_err(lcd->dev, "failed to register lcd ops.\n");
801 return PTR_ERR(lcd->ld);
802 }
803
804 lcd->bd = devm_backlight_device_register(lcd->dev, "s6e8ax0-bl",
805 lcd->dev, lcd, &s6e8ax0_backlight_ops, NULL);
806 if (IS_ERR(lcd->bd)) {
807 dev_err(lcd->dev, "failed to register backlight ops.\n");
808 return PTR_ERR(lcd->bd);
809 }
810
811 lcd->bd->props.max_brightness = MAX_BRIGHTNESS;
812 lcd->bd->props.brightness = MAX_BRIGHTNESS;
813
814 s6e8ax0_read_id(lcd, mtp_id);
815 if (mtp_id[0] == 0x00)
816 dev_err(lcd->dev, "read id failed\n");
817
818 dev_info(lcd->dev, "Read ID : %x, %x, %x\n",
819 mtp_id[0], mtp_id[1], mtp_id[2]);
820
821 if (mtp_id[2] == 0x33)
822 dev_info(lcd->dev,
823 "ID-3 is 0xff does not support dynamic elvss\n");
824 else
825 dev_info(lcd->dev,
826 "ID-3 is 0x%x support dynamic elvss\n", mtp_id[2]);
827
828 lcd->acl_enable = 1;
829 lcd->cur_acl = 0;
830
831 dev_set_drvdata(&dsim_dev->dev, lcd);
832
833 dev_dbg(lcd->dev, "probed s6e8ax0 panel driver.\n");
834
835 return 0;
836}
837
838#ifdef CONFIG_PM
839static int s6e8ax0_suspend(struct mipi_dsim_lcd_device *dsim_dev)
840{
841 struct s6e8ax0 *lcd = dev_get_drvdata(&dsim_dev->dev);
842
843 s6e8ax0_sleep_in(lcd);
844 msleep(lcd->ddi_pd->power_off_delay);
845 s6e8ax0_display_off(lcd);
846
847 s6e8ax0_regulator_disable(lcd);
848
849 return 0;
850}
851
852static int s6e8ax0_resume(struct mipi_dsim_lcd_device *dsim_dev)
853{
854 struct s6e8ax0 *lcd = dev_get_drvdata(&dsim_dev->dev);
855
856 s6e8ax0_sleep_out(lcd);
857 msleep(lcd->ddi_pd->power_on_delay);
858
859 s6e8ax0_regulator_enable(lcd);
860 s6e8ax0_set_sequence(dsim_dev);
861
862 return 0;
863}
864#else
865#define s6e8ax0_suspend NULL
866#define s6e8ax0_resume NULL
867#endif
868
869static struct mipi_dsim_lcd_driver s6e8ax0_dsim_ddi_driver = {
870 .name = "s6e8ax0",
871 .id = -1,
872
873 .power_on = s6e8ax0_power_on,
874 .set_sequence = s6e8ax0_set_sequence,
875 .probe = s6e8ax0_probe,
876 .suspend = s6e8ax0_suspend,
877 .resume = s6e8ax0_resume,
878};
879
880static int s6e8ax0_init(void)
881{
882 exynos_mipi_dsi_register_lcd_driver(&s6e8ax0_dsim_ddi_driver);
883
884 return 0;
885}
886
887static void s6e8ax0_exit(void)
888{
889 return;
890}
891
892module_init(s6e8ax0_init);
893module_exit(s6e8ax0_exit);
894
895MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>");
896MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
897MODULE_DESCRIPTION("MIPI-DSI based s6e8ax0 AMOLED LCD Panel Driver");
898MODULE_LICENSE("GPL");