aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2014-04-05 02:09:15 -0400
committerDave Airlie <airlied@redhat.com>2014-04-05 02:09:15 -0400
commit13b938927412db95274a045aacadf310e6a30acb (patch)
tree028027f5dbbb374971c5f14dc4443a5b8867e08c
parent14c6d5bdf759274868c6a3534e56f1991118df63 (diff)
parent96e112c44477edea1c01fbb976205e751f4229b9 (diff)
Merge branch 'exynos-drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos into drm-next
Summaries: - Add MIPI-DSI Driver, and dt bindigs - Add S6E8AA0 MIPI-DSI based panel drivers, and dt bindings - Add LD9040 parallel panel driver . this driver is placed in drivers/gpu/drm/panel, and it seems to be used for exynos drm as of now, - Some fixups Changelog v2: - Remove super device support, and relevant dt bindings for more reviews. - Fix module build errors you pointed out. - Re-based it to drm-next again. * 'exynos-drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos: drm/bridge: export ptn3460_init function drm/exynos: remove MODULE_DEVICE_TABLE definitions ARM: dts: exynos4412-trats2: enable exynos/fimd node ARM: dts: exynos4210-trats: enable exynos/fimd node ARM: dts: exynos4412-trats2: add panel node ARM: dts: exynos4210-trats: add panel node ARM: dts: exynos4: add MIPI DSI Master node drm/panel: add S6E8AA0 driver ARM: dts: exynos4210-universal_c210: add proper panel node drm/panel: add ld9040 driver panel/ld9040: add DT bindings panel/s6e8aa0: add DT bindings drm/exynos: add DSIM driver exynos/dsim: add DT bindings drm/exynos: disallow fbdev initialization if no device is connected drm/mipi_dsi: create dsi devices only for nodes with reg property drm/mipi_dsi: add flags to DSI messages
-rw-r--r--Documentation/devicetree/bindings/panel/samsung,ld9040.txt66
-rw-r--r--Documentation/devicetree/bindings/panel/samsung,s6e8aa0.txt56
-rw-r--r--Documentation/devicetree/bindings/video/exynos_dsim.txt80
-rw-r--r--arch/arm/boot/dts/exynos4.dtsi14
-rw-r--r--arch/arm/boot/dts/exynos4210-trats.dts61
-rw-r--r--arch/arm/boot/dts/exynos4210-universal_c210.dts71
-rw-r--r--arch/arm/boot/dts/exynos4412-trats2.dts70
-rw-r--r--drivers/gpu/drm/bridge/ptn3460.c1
-rw-r--r--drivers/gpu/drm/drm_mipi_dsi.c6
-rw-r--r--drivers/gpu/drm/exynos/Kconfig9
-rw-r--r--drivers/gpu/drm/exynos/Makefile1
-rw-r--r--drivers/gpu/drm/exynos/exynos_dp_core.c1
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.c15
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.h1
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_dsi.c1524
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fbdev.c21
-rw-r--r--drivers/gpu/drm/panel/Kconfig14
-rw-r--r--drivers/gpu/drm/panel/Makefile2
-rw-r--r--drivers/gpu/drm/panel/panel-ld9040.c376
-rw-r--r--drivers/gpu/drm/panel/panel-s6e8aa0.c1069
-rw-r--r--include/drm/drm_mipi_dsi.h6
21 files changed, 3445 insertions, 19 deletions
diff --git a/Documentation/devicetree/bindings/panel/samsung,ld9040.txt b/Documentation/devicetree/bindings/panel/samsung,ld9040.txt
new file mode 100644
index 000000000000..07c36c3f7b52
--- /dev/null
+++ b/Documentation/devicetree/bindings/panel/samsung,ld9040.txt
@@ -0,0 +1,66 @@
1Samsung LD9040 AMOLED LCD parallel RGB panel with SPI control bus
2
3Required properties:
4 - compatible: "samsung,ld9040"
5 - reg: address of the panel on SPI bus
6 - vdd3-supply: core voltage supply
7 - vci-supply: voltage supply for analog circuits
8 - reset-gpios: a GPIO spec for the reset pin
9 - display-timings: timings for the connected panel according to [1]
10
11The panel must obey rules for SPI slave device specified in document [2].
12
13Optional properties:
14 - power-on-delay: delay after turning regulators on [ms]
15 - reset-delay: delay after reset sequence [ms]
16 - panel-width-mm: physical panel width [mm]
17 - panel-height-mm: physical panel height [mm]
18
19The device node can contain one 'port' child node with one child
20'endpoint' node, according to the bindings defined in [3]. This
21node should describe panel's video bus.
22
23[1]: Documentation/devicetree/bindings/video/display-timing.txt
24[2]: Documentation/devicetree/bindings/spi/spi-bus.txt
25[3]: Documentation/devicetree/bindings/media/video-interfaces.txt
26
27Example:
28
29 lcd@0 {
30 compatible = "samsung,ld9040";
31 reg = <0>;
32 vdd3-supply = <&ldo7_reg>;
33 vci-supply = <&ldo17_reg>;
34 reset-gpios = <&gpy4 5 0>;
35 spi-max-frequency = <1200000>;
36 spi-cpol;
37 spi-cpha;
38 power-on-delay = <10>;
39 reset-delay = <10>;
40 panel-width-mm = <90>;
41 panel-height-mm = <154>;
42
43 display-timings {
44 timing {
45 clock-frequency = <23492370>;
46 hactive = <480>;
47 vactive = <800>;
48 hback-porch = <16>;
49 hfront-porch = <16>;
50 vback-porch = <2>;
51 vfront-porch = <28>;
52 hsync-len = <2>;
53 vsync-len = <1>;
54 hsync-active = <0>;
55 vsync-active = <0>;
56 de-active = <0>;
57 pixelclk-active = <0>;
58 };
59 };
60
61 port {
62 lcd_ep: endpoint {
63 remote-endpoint = <&fimd_dpi_ep>;
64 };
65 };
66 };
diff --git a/Documentation/devicetree/bindings/panel/samsung,s6e8aa0.txt b/Documentation/devicetree/bindings/panel/samsung,s6e8aa0.txt
new file mode 100644
index 000000000000..e7ee988e3156
--- /dev/null
+++ b/Documentation/devicetree/bindings/panel/samsung,s6e8aa0.txt
@@ -0,0 +1,56 @@
1Samsung S6E8AA0 AMOLED LCD 5.3 inch panel
2
3Required properties:
4 - compatible: "samsung,s6e8aa0"
5 - reg: the virtual channel number of a DSI peripheral
6 - vdd3-supply: core voltage supply
7 - vci-supply: voltage supply for analog circuits
8 - reset-gpios: a GPIO spec for the reset pin
9 - display-timings: timings for the connected panel as described by [1]
10
11Optional properties:
12 - power-on-delay: delay after turning regulators on [ms]
13 - reset-delay: delay after reset sequence [ms]
14 - init-delay: delay after initialization sequence [ms]
15 - panel-width-mm: physical panel width [mm]
16 - panel-height-mm: physical panel height [mm]
17 - flip-horizontal: boolean to flip image horizontally
18 - flip-vertical: boolean to flip image vertically
19
20The device node can contain one 'port' child node with one child
21'endpoint' node, according to the bindings defined in [2]. This
22node should describe panel's video bus.
23
24[1]: Documentation/devicetree/bindings/video/display-timing.txt
25[2]: Documentation/devicetree/bindings/media/video-interfaces.txt
26
27Example:
28
29 panel {
30 compatible = "samsung,s6e8aa0";
31 reg = <0>;
32 vdd3-supply = <&vcclcd_reg>;
33 vci-supply = <&vlcd_reg>;
34 reset-gpios = <&gpy4 5 0>;
35 power-on-delay= <50>;
36 reset-delay = <100>;
37 init-delay = <100>;
38 panel-width-mm = <58>;
39 panel-height-mm = <103>;
40 flip-horizontal;
41 flip-vertical;
42
43 display-timings {
44 timing0: timing-0 {
45 clock-frequency = <57153600>;
46 hactive = <720>;
47 vactive = <1280>;
48 hfront-porch = <5>;
49 hback-porch = <5>;
50 hsync-len = <5>;
51 vfront-porch = <13>;
52 vback-porch = <1>;
53 vsync-len = <2>;
54 };
55 };
56 };
diff --git a/Documentation/devicetree/bindings/video/exynos_dsim.txt b/Documentation/devicetree/bindings/video/exynos_dsim.txt
new file mode 100644
index 000000000000..33b5730d07ba
--- /dev/null
+++ b/Documentation/devicetree/bindings/video/exynos_dsim.txt
@@ -0,0 +1,80 @@
1Exynos MIPI DSI Master
2
3Required properties:
4 - compatible: "samsung,exynos4210-mipi-dsi"
5 - reg: physical base address and length of the registers set for the device
6 - interrupts: should contain DSI interrupt
7 - clocks: list of clock specifiers, must contain an entry for each required
8 entry in clock-names
9 - clock-names: should include "bus_clk"and "pll_clk" entries
10 - phys: list of phy specifiers, must contain an entry for each required
11 entry in phy-names
12 - phy-names: should include "dsim" entry
13 - vddcore-supply: MIPI DSIM Core voltage supply (e.g. 1.1V)
14 - vddio-supply: MIPI DSIM I/O and PLL voltage supply (e.g. 1.8V)
15 - samsung,pll-clock-frequency: specifies frequency of the "pll_clk" clock
16 - #address-cells, #size-cells: should be set respectively to <1> and <0>
17 according to DSI host bindings (see MIPI DSI bindings [1])
18
19Optional properties:
20 - samsung,power-domain: a phandle to DSIM power domain node
21
22Child nodes:
23 Should contain DSI peripheral nodes (see MIPI DSI bindings [1]).
24
25Video interfaces:
26 Device node can contain video interface port nodes according to [2].
27 The following are properties specific to those nodes:
28
29 port node:
30 - reg: (required) can be 0 for input RGB/I80 port or 1 for DSI port;
31
32 endpoint node of DSI port (reg = 1):
33 - samsung,burst-clock-frequency: specifies DSI frequency in high-speed burst
34 mode
35 - samsung,esc-clock-frequency: specifies DSI frequency in escape mode
36
37[1]: Documentation/devicetree/bindings/mipi/dsi/mipi-dsi-bus.txt
38[2]: Documentation/devicetree/bindings/media/video-interfaces.txt
39
40Example:
41
42 dsi@11C80000 {
43 compatible = "samsung,exynos4210-mipi-dsi";
44 reg = <0x11C80000 0x10000>;
45 interrupts = <0 79 0>;
46 clocks = <&clock 286>, <&clock 143>;
47 clock-names = "bus_clk", "pll_clk";
48 phys = <&mipi_phy 1>;
49 phy-names = "dsim";
50 vddcore-supply = <&vusb_reg>;
51 vddio-supply = <&vmipi_reg>;
52 samsung,power-domain = <&pd_lcd0>;
53 #address-cells = <1>;
54 #size-cells = <0>;
55 samsung,pll-clock-frequency = <24000000>;
56
57 panel@1 {
58 reg = <0>;
59 ...
60 port {
61 panel_ep: endpoint {
62 remote-endpoint = <&dsi_ep>;
63 };
64 };
65 };
66
67 ports {
68 #address-cells = <1>;
69 #size-cells = <0>;
70
71 port@1 {
72 dsi_ep: endpoint {
73 reg = <0>;
74 samsung,burst-clock-frequency = <500000000>;
75 samsung,esc-clock-frequency = <20000000>;
76 remote-endpoint = <&panel_ep>;
77 };
78 };
79 };
80 };
diff --git a/arch/arm/boot/dts/exynos4.dtsi b/arch/arm/boot/dts/exynos4.dtsi
index 08452e183b57..3d14cdb0776a 100644
--- a/arch/arm/boot/dts/exynos4.dtsi
+++ b/arch/arm/boot/dts/exynos4.dtsi
@@ -104,6 +104,20 @@
104 reg = <0x10010000 0x400>; 104 reg = <0x10010000 0x400>;
105 }; 105 };
106 106
107 dsi_0: dsi@11C80000 {
108 compatible = "samsung,exynos4210-mipi-dsi";
109 reg = <0x11C80000 0x10000>;
110 interrupts = <0 79 0>;
111 samsung,power-domain = <&pd_lcd0>;
112 phys = <&mipi_phy 1>;
113 phy-names = "dsim";
114 clocks = <&clock 286>, <&clock 143>;
115 clock-names = "bus_clk", "pll_clk";
116 status = "disabled";
117 #address-cells = <1>;
118 #size-cells = <0>;
119 };
120
107 camera { 121 camera {
108 compatible = "samsung,fimc", "simple-bus"; 122 compatible = "samsung,fimc", "simple-bus";
109 status = "disabled"; 123 status = "disabled";
diff --git a/arch/arm/boot/dts/exynos4210-trats.dts b/arch/arm/boot/dts/exynos4210-trats.dts
index 63cc571ca307..02c6768f52b4 100644
--- a/arch/arm/boot/dts/exynos4210-trats.dts
+++ b/arch/arm/boot/dts/exynos4210-trats.dts
@@ -353,6 +353,67 @@
353 }; 353 };
354 }; 354 };
355 355
356 dsi_0: dsi@11C80000 {
357 vddcore-supply = <&vusb_reg>;
358 vddio-supply = <&vmipi_reg>;
359 samsung,pll-clock-frequency = <24000000>;
360 status = "okay";
361
362 ports {
363 #address-cells = <1>;
364 #size-cells = <0>;
365
366 port@1 {
367 reg = <1>;
368
369 dsi_out: endpoint {
370 remote-endpoint = <&dsi_in>;
371 samsung,burst-clock-frequency = <500000000>;
372 samsung,esc-clock-frequency = <20000000>;
373 };
374 };
375 };
376
377 panel@0 {
378 reg = <0>;
379 compatible = "samsung,s6e8aa0";
380 vdd3-supply = <&vcclcd_reg>;
381 vci-supply = <&vlcd_reg>;
382 reset-gpios = <&gpy4 5 0>;
383 power-on-delay= <50>;
384 reset-delay = <100>;
385 init-delay = <100>;
386 flip-horizontal;
387 flip-vertical;
388 panel-width-mm = <58>;
389 panel-height-mm = <103>;
390
391 display-timings {
392 timing-0 {
393 clock-frequency = <57153600>;
394 hactive = <720>;
395 vactive = <1280>;
396 hfront-porch = <5>;
397 hback-porch = <5>;
398 hsync-len = <5>;
399 vfront-porch = <13>;
400 vback-porch = <1>;
401 vsync-len = <2>;
402 };
403 };
404
405 port {
406 dsi_in: endpoint {
407 remote-endpoint = <&dsi_out>;
408 };
409 };
410 };
411 };
412
413 fimd@11c00000 {
414 status = "okay";
415 };
416
356 camera { 417 camera {
357 pinctrl-names = "default"; 418 pinctrl-names = "default";
358 pinctrl-0 = <>; 419 pinctrl-0 = <>;
diff --git a/arch/arm/boot/dts/exynos4210-universal_c210.dts b/arch/arm/boot/dts/exynos4210-universal_c210.dts
index 477208d98c6d..0a80a72368d3 100644
--- a/arch/arm/boot/dts/exynos4210-universal_c210.dts
+++ b/arch/arm/boot/dts/exynos4210-universal_c210.dts
@@ -225,7 +225,6 @@
225 regulator-name = "VLCD+VMIPI_1.8V"; 225 regulator-name = "VLCD+VMIPI_1.8V";
226 regulator-min-microvolt = <1800000>; 226 regulator-min-microvolt = <1800000>;
227 regulator-max-microvolt = <1800000>; 227 regulator-max-microvolt = <1800000>;
228 regulator-always-on;
229 }; 228 };
230 229
231 ldo8_reg: LDO8 { 230 ldo8_reg: LDO8 {
@@ -289,7 +288,6 @@
289 regulator-name = "VCC_3.0V_LCD"; 288 regulator-name = "VCC_3.0V_LCD";
290 regulator-min-microvolt = <3000000>; 289 regulator-min-microvolt = <3000000>;
291 regulator-max-microvolt = <3000000>; 290 regulator-max-microvolt = <3000000>;
292 regulator-always-on;
293 }; 291 };
294 292
295 buck1_reg: BUCK1 { 293 buck1_reg: BUCK1 {
@@ -347,27 +345,66 @@
347 }; 345 };
348 }; 346 };
349 347
348 spi-lcd {
349 compatible = "spi-gpio";
350 #address-cells = <1>;
351 #size-cells = <0>;
352
353 gpio-sck = <&gpy3 1 0>;
354 gpio-mosi = <&gpy3 3 0>;
355 num-chipselects = <1>;
356 cs-gpios = <&gpy4 3 0>;
357
358 lcd@0 {
359 compatible = "samsung,ld9040";
360 reg = <0>;
361 vdd3-supply = <&ldo7_reg>;
362 vci-supply = <&ldo17_reg>;
363 reset-gpios = <&gpy4 5 0>;
364 spi-max-frequency = <1200000>;
365 spi-cpol;
366 spi-cpha;
367 power-on-delay = <10>;
368 reset-delay = <10>;
369 panel-width-mm = <90>;
370 panel-height-mm = <154>;
371 display-timings {
372 timing {
373 clock-frequency = <23492370>;
374 hactive = <480>;
375 vactive = <800>;
376 hback-porch = <16>;
377 hfront-porch = <16>;
378 vback-porch = <2>;
379 vfront-porch = <28>;
380 hsync-len = <2>;
381 vsync-len = <1>;
382 hsync-active = <0>;
383 vsync-active = <0>;
384 de-active = <0>;
385 pixelclk-active = <0>;
386 };
387 };
388 port {
389 lcd_ep: endpoint {
390 remote-endpoint = <&fimd_dpi_ep>;
391 };
392 };
393 };
394 };
395
350 fimd: fimd@11c00000 { 396 fimd: fimd@11c00000 {
351 pinctrl-0 = <&lcd_clk>, <&lcd_data24>; 397 pinctrl-0 = <&lcd_clk>, <&lcd_data24>;
352 pinctrl-names = "default"; 398 pinctrl-names = "default";
353 status = "okay"; 399 status = "okay";
354 samsung,invert-vden; 400 samsung,invert-vden;
355 samsung,invert-vclk; 401 samsung,invert-vclk;
356 display-timings { 402 #address-cells = <1>;
357 timing { 403 #size-cells = <0>;
358 clock-frequency = <23492370>; 404 port@3 {
359 hactive = <480>; 405 reg = <3>;
360 vactive = <800>; 406 fimd_dpi_ep: endpoint {
361 hback-porch = <16>; 407 remote-endpoint = <&lcd_ep>;
362 hfront-porch = <16>;
363 vback-porch = <2>;
364 vfront-porch = <28>;
365 hsync-len = <2>;
366 vsync-len = <1>;
367 hsync-active = <0>;
368 vsync-active = <0>;
369 de-active = <0>;
370 pixelclk-active = <0>;
371 }; 408 };
372 }; 409 };
373 }; 410 };
diff --git a/arch/arm/boot/dts/exynos4412-trats2.dts b/arch/arm/boot/dts/exynos4412-trats2.dts
index 4f851ccf40eb..53c717b6eb69 100644
--- a/arch/arm/boot/dts/exynos4412-trats2.dts
+++ b/arch/arm/boot/dts/exynos4412-trats2.dts
@@ -71,6 +71,15 @@
71 enable-active-high; 71 enable-active-high;
72 }; 72 };
73 73
74 lcd_vdd3_reg: voltage-regulator-2 {
75 compatible = "regulator-fixed";
76 regulator-name = "LCD_VDD_2.2V";
77 regulator-min-microvolt = <2200000>;
78 regulator-max-microvolt = <2200000>;
79 gpio = <&gpc0 1 0>;
80 enable-active-high;
81 };
82
74 /* More to come */ 83 /* More to come */
75 }; 84 };
76 85
@@ -511,6 +520,67 @@
511 }; 520 };
512 }; 521 };
513 522
523 dsi_0: dsi@11C80000 {
524 vddcore-supply = <&ldo8_reg>;
525 vddio-supply = <&ldo10_reg>;
526 samsung,pll-clock-frequency = <24000000>;
527 status = "okay";
528
529 ports {
530 #address-cells = <1>;
531 #size-cells = <0>;
532
533 port@1 {
534 reg = <1>;
535
536 dsi_out: endpoint {
537 remote-endpoint = <&dsi_in>;
538 samsung,burst-clock-frequency = <500000000>;
539 samsung,esc-clock-frequency = <20000000>;
540 };
541 };
542 };
543
544 panel@0 {
545 compatible = "samsung,s6e8aa0";
546 reg = <0>;
547 vdd3-supply = <&lcd_vdd3_reg>;
548 vci-supply = <&ldo25_reg>;
549 reset-gpios = <&gpy4 5 0>;
550 power-on-delay= <50>;
551 reset-delay = <100>;
552 init-delay = <100>;
553 flip-horizontal;
554 flip-vertical;
555 panel-width-mm = <58>;
556 panel-height-mm = <103>;
557
558 display-timings {
559 timing-0 {
560 clock-frequency = <0>;
561 hactive = <720>;
562 vactive = <1280>;
563 hfront-porch = <5>;
564 hback-porch = <5>;
565 hsync-len = <5>;
566 vfront-porch = <13>;
567 vback-porch = <1>;
568 vsync-len = <2>;
569 };
570 };
571
572 port {
573 dsi_in: endpoint {
574 remote-endpoint = <&dsi_out>;
575 };
576 };
577 };
578 };
579
580 fimd@11c00000 {
581 status = "okay";
582 };
583
514 camera { 584 camera {
515 pinctrl-0 = <&cam_port_b_clk_active>; 585 pinctrl-0 = <&cam_port_b_clk_active>;
516 pinctrl-names = "default"; 586 pinctrl-names = "default";
diff --git a/drivers/gpu/drm/bridge/ptn3460.c b/drivers/gpu/drm/bridge/ptn3460.c
index a9e5c1a13666..b171901a3553 100644
--- a/drivers/gpu/drm/bridge/ptn3460.c
+++ b/drivers/gpu/drm/bridge/ptn3460.c
@@ -347,3 +347,4 @@ err:
347 gpio_free(ptn_bridge->gpio_rst_n); 347 gpio_free(ptn_bridge->gpio_rst_n);
348 return ret; 348 return ret;
349} 349}
350EXPORT_SYMBOL(ptn3460_init);
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c
index b155ee2ffa17..09821f46d768 100644
--- a/drivers/gpu/drm/drm_mipi_dsi.c
+++ b/drivers/gpu/drm/drm_mipi_dsi.c
@@ -142,8 +142,12 @@ int mipi_dsi_host_register(struct mipi_dsi_host *host)
142{ 142{
143 struct device_node *node; 143 struct device_node *node;
144 144
145 for_each_available_child_of_node(host->dev->of_node, node) 145 for_each_available_child_of_node(host->dev->of_node, node) {
146 /* skip nodes without reg property */
147 if (!of_find_property(node, "reg", NULL))
148 continue;
146 of_mipi_dsi_device_add(host, node); 149 of_mipi_dsi_device_add(host, node);
150 }
147 151
148 return 0; 152 return 0;
149} 153}
diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig
index 56f95811a5e5..5bf5bca94f56 100644
--- a/drivers/gpu/drm/exynos/Kconfig
+++ b/drivers/gpu/drm/exynos/Kconfig
@@ -39,6 +39,15 @@ config DRM_EXYNOS_DPI
39 help 39 help
40 This enables support for Exynos parallel output. 40 This enables support for Exynos parallel output.
41 41
42config DRM_EXYNOS_DSI
43 bool "EXYNOS DRM MIPI-DSI driver support"
44 depends on DRM_EXYNOS
45 select DRM_MIPI_DSI
46 select DRM_PANEL
47 default n
48 help
49 This enables support for Exynos MIPI-DSI device.
50
42config DRM_EXYNOS_DP 51config DRM_EXYNOS_DP
43 bool "EXYNOS DRM DP driver support" 52 bool "EXYNOS DRM DP driver support"
44 depends on DRM_EXYNOS && ARCH_EXYNOS 53 depends on DRM_EXYNOS && ARCH_EXYNOS
diff --git a/drivers/gpu/drm/exynos/Makefile b/drivers/gpu/drm/exynos/Makefile
index babcd52b65df..33ae3652b8da 100644
--- a/drivers/gpu/drm/exynos/Makefile
+++ b/drivers/gpu/drm/exynos/Makefile
@@ -12,6 +12,7 @@ exynosdrm-$(CONFIG_DRM_EXYNOS_IOMMU) += exynos_drm_iommu.o
12exynosdrm-$(CONFIG_DRM_EXYNOS_DMABUF) += exynos_drm_dmabuf.o 12exynosdrm-$(CONFIG_DRM_EXYNOS_DMABUF) += exynos_drm_dmabuf.o
13exynosdrm-$(CONFIG_DRM_EXYNOS_FIMD) += exynos_drm_fimd.o 13exynosdrm-$(CONFIG_DRM_EXYNOS_FIMD) += exynos_drm_fimd.o
14exynosdrm-$(CONFIG_DRM_EXYNOS_DPI) += exynos_drm_dpi.o 14exynosdrm-$(CONFIG_DRM_EXYNOS_DPI) += exynos_drm_dpi.o
15exynosdrm-$(CONFIG_DRM_EXYNOS_DSI) += exynos_drm_dsi.o
15exynosdrm-$(CONFIG_DRM_EXYNOS_DP) += exynos_dp_core.o exynos_dp_reg.o 16exynosdrm-$(CONFIG_DRM_EXYNOS_DP) += exynos_dp_core.o exynos_dp_reg.o
16exynosdrm-$(CONFIG_DRM_EXYNOS_HDMI) += exynos_hdmi.o exynos_mixer.o 17exynosdrm-$(CONFIG_DRM_EXYNOS_HDMI) += exynos_hdmi.o exynos_mixer.o
17exynosdrm-$(CONFIG_DRM_EXYNOS_VIDI) += exynos_drm_vidi.o 18exynosdrm-$(CONFIG_DRM_EXYNOS_VIDI) += exynos_drm_vidi.o
diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c
index a59bca9f16e1..aed533bbfd31 100644
--- a/drivers/gpu/drm/exynos/exynos_dp_core.c
+++ b/drivers/gpu/drm/exynos/exynos_dp_core.c
@@ -1339,7 +1339,6 @@ static const struct of_device_id exynos_dp_match[] = {
1339 { .compatible = "samsung,exynos5-dp" }, 1339 { .compatible = "samsung,exynos5-dp" },
1340 {}, 1340 {},
1341}; 1341};
1342MODULE_DEVICE_TABLE(of, exynos_dp_match);
1343 1342
1344struct platform_driver dp_driver = { 1343struct platform_driver dp_driver = {
1345 .probe = exynos_dp_probe, 1344 .probe = exynos_dp_probe,
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index 771c87e90a2f..2d27ba23a6a8 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -450,6 +450,12 @@ static int __init exynos_drm_init(void)
450 goto out_dp; 450 goto out_dp;
451#endif 451#endif
452 452
453#ifdef CONFIG_DRM_EXYNOS_DSI
454 ret = platform_driver_register(&dsi_driver);
455 if (ret < 0)
456 goto out_dsi;
457#endif
458
453#ifdef CONFIG_DRM_EXYNOS_FIMD 459#ifdef CONFIG_DRM_EXYNOS_FIMD
454 ret = platform_driver_register(&fimd_driver); 460 ret = platform_driver_register(&fimd_driver);
455 if (ret < 0) 461 if (ret < 0)
@@ -566,6 +572,11 @@ out_hdmi:
566out_fimd: 572out_fimd:
567#endif 573#endif
568 574
575#ifdef CONFIG_DRM_EXYNOS_DSI
576 platform_driver_unregister(&dsi_driver);
577out_dsi:
578#endif
579
569#ifdef CONFIG_DRM_EXYNOS_DP 580#ifdef CONFIG_DRM_EXYNOS_DP
570 platform_driver_unregister(&dp_driver); 581 platform_driver_unregister(&dp_driver);
571out_dp: 582out_dp:
@@ -613,6 +624,10 @@ static void __exit exynos_drm_exit(void)
613 platform_driver_unregister(&fimd_driver); 624 platform_driver_unregister(&fimd_driver);
614#endif 625#endif
615 626
627#ifdef CONFIG_DRM_EXYNOS_DSI
628 platform_driver_unregister(&dsi_driver);
629#endif
630
616#ifdef CONFIG_DRM_EXYNOS_DP 631#ifdef CONFIG_DRM_EXYNOS_DP
617 platform_driver_unregister(&dp_driver); 632 platform_driver_unregister(&dp_driver);
618#endif 633#endif
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index 2d892f32e831..4c5cf6843137 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -370,6 +370,7 @@ static inline int exynos_dpi_remove(struct device *dev) { return 0; }
370#endif 370#endif
371 371
372extern struct platform_driver dp_driver; 372extern struct platform_driver dp_driver;
373extern struct platform_driver dsi_driver;
373extern struct platform_driver fimd_driver; 374extern struct platform_driver fimd_driver;
374extern struct platform_driver hdmi_driver; 375extern struct platform_driver hdmi_driver;
375extern struct platform_driver mixer_driver; 376extern struct platform_driver mixer_driver;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
new file mode 100644
index 000000000000..eb73e3bf2a0c
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
@@ -0,0 +1,1524 @@
1/*
2 * Samsung SoC MIPI DSI Master driver.
3 *
4 * Copyright (c) 2014 Samsung Electronics Co., Ltd
5 *
6 * Contacts: Tomasz Figa <t.figa@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 <drm/drmP.h>
14#include <drm/drm_crtc_helper.h>
15#include <drm/drm_mipi_dsi.h>
16#include <drm/drm_panel.h>
17
18#include <linux/clk.h>
19#include <linux/irq.h>
20#include <linux/phy/phy.h>
21#include <linux/regulator/consumer.h>
22
23#include <video/mipi_display.h>
24#include <video/videomode.h>
25
26#include "exynos_drm_drv.h"
27
28/* returns true iff both arguments logically differs */
29#define NEQV(a, b) (!(a) ^ !(b))
30
31#define DSIM_STATUS_REG 0x0 /* Status register */
32#define DSIM_SWRST_REG 0x4 /* Software reset register */
33#define DSIM_CLKCTRL_REG 0x8 /* Clock control register */
34#define DSIM_TIMEOUT_REG 0xc /* Time out register */
35#define DSIM_CONFIG_REG 0x10 /* Configuration register */
36#define DSIM_ESCMODE_REG 0x14 /* Escape mode register */
37
38/* Main display image resolution register */
39#define DSIM_MDRESOL_REG 0x18
40#define DSIM_MVPORCH_REG 0x1c /* Main display Vporch register */
41#define DSIM_MHPORCH_REG 0x20 /* Main display Hporch register */
42#define DSIM_MSYNC_REG 0x24 /* Main display sync area register */
43
44/* Sub display image resolution register */
45#define DSIM_SDRESOL_REG 0x28
46#define DSIM_INTSRC_REG 0x2c /* Interrupt source register */
47#define DSIM_INTMSK_REG 0x30 /* Interrupt mask register */
48#define DSIM_PKTHDR_REG 0x34 /* Packet Header FIFO register */
49#define DSIM_PAYLOAD_REG 0x38 /* Payload FIFO register */
50#define DSIM_RXFIFO_REG 0x3c /* Read FIFO register */
51#define DSIM_FIFOTHLD_REG 0x40 /* FIFO threshold level register */
52#define DSIM_FIFOCTRL_REG 0x44 /* FIFO status and control register */
53
54/* FIFO memory AC characteristic register */
55#define DSIM_PLLCTRL_REG 0x4c /* PLL control register */
56#define DSIM_PLLTMR_REG 0x50 /* PLL timer register */
57#define DSIM_PHYACCHR_REG 0x54 /* D-PHY AC characteristic register */
58#define DSIM_PHYACCHR1_REG 0x58 /* D-PHY AC characteristic register1 */
59
60/* DSIM_STATUS */
61#define DSIM_STOP_STATE_DAT(x) (((x) & 0xf) << 0)
62#define DSIM_STOP_STATE_CLK (1 << 8)
63#define DSIM_TX_READY_HS_CLK (1 << 10)
64#define DSIM_PLL_STABLE (1 << 31)
65
66/* DSIM_SWRST */
67#define DSIM_FUNCRST (1 << 16)
68#define DSIM_SWRST (1 << 0)
69
70/* DSIM_TIMEOUT */
71#define DSIM_LPDR_TIMEOUT(x) ((x) << 0)
72#define DSIM_BTA_TIMEOUT(x) ((x) << 16)
73
74/* DSIM_CLKCTRL */
75#define DSIM_ESC_PRESCALER(x) (((x) & 0xffff) << 0)
76#define DSIM_ESC_PRESCALER_MASK (0xffff << 0)
77#define DSIM_LANE_ESC_CLK_EN_CLK (1 << 19)
78#define DSIM_LANE_ESC_CLK_EN_DATA(x) (((x) & 0xf) << 20)
79#define DSIM_LANE_ESC_CLK_EN_DATA_MASK (0xf << 20)
80#define DSIM_BYTE_CLKEN (1 << 24)
81#define DSIM_BYTE_CLK_SRC(x) (((x) & 0x3) << 25)
82#define DSIM_BYTE_CLK_SRC_MASK (0x3 << 25)
83#define DSIM_PLL_BYPASS (1 << 27)
84#define DSIM_ESC_CLKEN (1 << 28)
85#define DSIM_TX_REQUEST_HSCLK (1 << 31)
86
87/* DSIM_CONFIG */
88#define DSIM_LANE_EN_CLK (1 << 0)
89#define DSIM_LANE_EN(x) (((x) & 0xf) << 1)
90#define DSIM_NUM_OF_DATA_LANE(x) (((x) & 0x3) << 5)
91#define DSIM_SUB_PIX_FORMAT(x) (((x) & 0x7) << 8)
92#define DSIM_MAIN_PIX_FORMAT_MASK (0x7 << 12)
93#define DSIM_MAIN_PIX_FORMAT_RGB888 (0x7 << 12)
94#define DSIM_MAIN_PIX_FORMAT_RGB666 (0x6 << 12)
95#define DSIM_MAIN_PIX_FORMAT_RGB666_P (0x5 << 12)
96#define DSIM_MAIN_PIX_FORMAT_RGB565 (0x4 << 12)
97#define DSIM_SUB_VC (((x) & 0x3) << 16)
98#define DSIM_MAIN_VC (((x) & 0x3) << 18)
99#define DSIM_HSA_MODE (1 << 20)
100#define DSIM_HBP_MODE (1 << 21)
101#define DSIM_HFP_MODE (1 << 22)
102#define DSIM_HSE_MODE (1 << 23)
103#define DSIM_AUTO_MODE (1 << 24)
104#define DSIM_VIDEO_MODE (1 << 25)
105#define DSIM_BURST_MODE (1 << 26)
106#define DSIM_SYNC_INFORM (1 << 27)
107#define DSIM_EOT_DISABLE (1 << 28)
108#define DSIM_MFLUSH_VS (1 << 29)
109
110/* DSIM_ESCMODE */
111#define DSIM_TX_TRIGGER_RST (1 << 4)
112#define DSIM_TX_LPDT_LP (1 << 6)
113#define DSIM_CMD_LPDT_LP (1 << 7)
114#define DSIM_FORCE_BTA (1 << 16)
115#define DSIM_FORCE_STOP_STATE (1 << 20)
116#define DSIM_STOP_STATE_CNT(x) (((x) & 0x7ff) << 21)
117#define DSIM_STOP_STATE_CNT_MASK (0x7ff << 21)
118
119/* DSIM_MDRESOL */
120#define DSIM_MAIN_STAND_BY (1 << 31)
121#define DSIM_MAIN_VRESOL(x) (((x) & 0x7ff) << 16)
122#define DSIM_MAIN_HRESOL(x) (((x) & 0X7ff) << 0)
123
124/* DSIM_MVPORCH */
125#define DSIM_CMD_ALLOW(x) ((x) << 28)
126#define DSIM_STABLE_VFP(x) ((x) << 16)
127#define DSIM_MAIN_VBP(x) ((x) << 0)
128#define DSIM_CMD_ALLOW_MASK (0xf << 28)
129#define DSIM_STABLE_VFP_MASK (0x7ff << 16)
130#define DSIM_MAIN_VBP_MASK (0x7ff << 0)
131
132/* DSIM_MHPORCH */
133#define DSIM_MAIN_HFP(x) ((x) << 16)
134#define DSIM_MAIN_HBP(x) ((x) << 0)
135#define DSIM_MAIN_HFP_MASK ((0xffff) << 16)
136#define DSIM_MAIN_HBP_MASK ((0xffff) << 0)
137
138/* DSIM_MSYNC */
139#define DSIM_MAIN_VSA(x) ((x) << 22)
140#define DSIM_MAIN_HSA(x) ((x) << 0)
141#define DSIM_MAIN_VSA_MASK ((0x3ff) << 22)
142#define DSIM_MAIN_HSA_MASK ((0xffff) << 0)
143
144/* DSIM_SDRESOL */
145#define DSIM_SUB_STANDY(x) ((x) << 31)
146#define DSIM_SUB_VRESOL(x) ((x) << 16)
147#define DSIM_SUB_HRESOL(x) ((x) << 0)
148#define DSIM_SUB_STANDY_MASK ((0x1) << 31)
149#define DSIM_SUB_VRESOL_MASK ((0x7ff) << 16)
150#define DSIM_SUB_HRESOL_MASK ((0x7ff) << 0)
151
152/* DSIM_INTSRC */
153#define DSIM_INT_PLL_STABLE (1 << 31)
154#define DSIM_INT_SW_RST_RELEASE (1 << 30)
155#define DSIM_INT_SFR_FIFO_EMPTY (1 << 29)
156#define DSIM_INT_BTA (1 << 25)
157#define DSIM_INT_FRAME_DONE (1 << 24)
158#define DSIM_INT_RX_TIMEOUT (1 << 21)
159#define DSIM_INT_BTA_TIMEOUT (1 << 20)
160#define DSIM_INT_RX_DONE (1 << 18)
161#define DSIM_INT_RX_TE (1 << 17)
162#define DSIM_INT_RX_ACK (1 << 16)
163#define DSIM_INT_RX_ECC_ERR (1 << 15)
164#define DSIM_INT_RX_CRC_ERR (1 << 14)
165
166/* DSIM_FIFOCTRL */
167#define DSIM_RX_DATA_FULL (1 << 25)
168#define DSIM_RX_DATA_EMPTY (1 << 24)
169#define DSIM_SFR_HEADER_FULL (1 << 23)
170#define DSIM_SFR_HEADER_EMPTY (1 << 22)
171#define DSIM_SFR_PAYLOAD_FULL (1 << 21)
172#define DSIM_SFR_PAYLOAD_EMPTY (1 << 20)
173#define DSIM_I80_HEADER_FULL (1 << 19)
174#define DSIM_I80_HEADER_EMPTY (1 << 18)
175#define DSIM_I80_PAYLOAD_FULL (1 << 17)
176#define DSIM_I80_PAYLOAD_EMPTY (1 << 16)
177#define DSIM_SD_HEADER_FULL (1 << 15)
178#define DSIM_SD_HEADER_EMPTY (1 << 14)
179#define DSIM_SD_PAYLOAD_FULL (1 << 13)
180#define DSIM_SD_PAYLOAD_EMPTY (1 << 12)
181#define DSIM_MD_HEADER_FULL (1 << 11)
182#define DSIM_MD_HEADER_EMPTY (1 << 10)
183#define DSIM_MD_PAYLOAD_FULL (1 << 9)
184#define DSIM_MD_PAYLOAD_EMPTY (1 << 8)
185#define DSIM_RX_FIFO (1 << 4)
186#define DSIM_SFR_FIFO (1 << 3)
187#define DSIM_I80_FIFO (1 << 2)
188#define DSIM_SD_FIFO (1 << 1)
189#define DSIM_MD_FIFO (1 << 0)
190
191/* DSIM_PHYACCHR */
192#define DSIM_AFC_EN (1 << 14)
193#define DSIM_AFC_CTL(x) (((x) & 0x7) << 5)
194
195/* DSIM_PLLCTRL */
196#define DSIM_FREQ_BAND(x) ((x) << 24)
197#define DSIM_PLL_EN (1 << 23)
198#define DSIM_PLL_P(x) ((x) << 13)
199#define DSIM_PLL_M(x) ((x) << 4)
200#define DSIM_PLL_S(x) ((x) << 1)
201
202#define DSI_MAX_BUS_WIDTH 4
203#define DSI_NUM_VIRTUAL_CHANNELS 4
204#define DSI_TX_FIFO_SIZE 2048
205#define DSI_RX_FIFO_SIZE 256
206#define DSI_XFER_TIMEOUT_MS 100
207#define DSI_RX_FIFO_EMPTY 0x30800002
208
209enum exynos_dsi_transfer_type {
210 EXYNOS_DSI_TX,
211 EXYNOS_DSI_RX,
212};
213
214struct exynos_dsi_transfer {
215 struct list_head list;
216 struct completion completed;
217 int result;
218 u8 data_id;
219 u8 data[2];
220 u16 flags;
221
222 const u8 *tx_payload;
223 u16 tx_len;
224 u16 tx_done;
225
226 u8 *rx_payload;
227 u16 rx_len;
228 u16 rx_done;
229};
230
231#define DSIM_STATE_ENABLED BIT(0)
232#define DSIM_STATE_INITIALIZED BIT(1)
233#define DSIM_STATE_CMD_LPM BIT(2)
234
235struct exynos_dsi {
236 struct mipi_dsi_host dsi_host;
237 struct drm_connector connector;
238 struct drm_encoder *encoder;
239 struct device_node *panel_node;
240 struct drm_panel *panel;
241 struct device *dev;
242
243 void __iomem *reg_base;
244 struct phy *phy;
245 struct clk *pll_clk;
246 struct clk *bus_clk;
247 struct regulator_bulk_data supplies[2];
248 int irq;
249
250 u32 pll_clk_rate;
251 u32 burst_clk_rate;
252 u32 esc_clk_rate;
253 u32 lanes;
254 u32 mode_flags;
255 u32 format;
256 struct videomode vm;
257
258 int state;
259 struct drm_property *brightness;
260 struct completion completed;
261
262 spinlock_t transfer_lock; /* protects transfer_list */
263 struct list_head transfer_list;
264};
265
266#define host_to_dsi(host) container_of(host, struct exynos_dsi, dsi_host)
267#define connector_to_dsi(c) container_of(c, struct exynos_dsi, connector)
268
269static void exynos_dsi_wait_for_reset(struct exynos_dsi *dsi)
270{
271 if (wait_for_completion_timeout(&dsi->completed, msecs_to_jiffies(300)))
272 return;
273
274 dev_err(dsi->dev, "timeout waiting for reset\n");
275}
276
277static void exynos_dsi_reset(struct exynos_dsi *dsi)
278{
279 reinit_completion(&dsi->completed);
280 writel(DSIM_SWRST, dsi->reg_base + DSIM_SWRST_REG);
281}
282
283#ifndef MHZ
284#define MHZ (1000*1000)
285#endif
286
287static unsigned long exynos_dsi_pll_find_pms(struct exynos_dsi *dsi,
288 unsigned long fin, unsigned long fout, u8 *p, u16 *m, u8 *s)
289{
290 unsigned long best_freq = 0;
291 u32 min_delta = 0xffffffff;
292 u8 p_min, p_max;
293 u8 _p, uninitialized_var(best_p);
294 u16 _m, uninitialized_var(best_m);
295 u8 _s, uninitialized_var(best_s);
296
297 p_min = DIV_ROUND_UP(fin, (12 * MHZ));
298 p_max = fin / (6 * MHZ);
299
300 for (_p = p_min; _p <= p_max; ++_p) {
301 for (_s = 0; _s <= 5; ++_s) {
302 u64 tmp;
303 u32 delta;
304
305 tmp = (u64)fout * (_p << _s);
306 do_div(tmp, fin);
307 _m = tmp;
308 if (_m < 41 || _m > 125)
309 continue;
310
311 tmp = (u64)_m * fin;
312 do_div(tmp, _p);
313 if (tmp < 500 * MHZ || tmp > 1000 * MHZ)
314 continue;
315
316 tmp = (u64)_m * fin;
317 do_div(tmp, _p << _s);
318
319 delta = abs(fout - tmp);
320 if (delta < min_delta) {
321 best_p = _p;
322 best_m = _m;
323 best_s = _s;
324 min_delta = delta;
325 best_freq = tmp;
326 }
327 }
328 }
329
330 if (best_freq) {
331 *p = best_p;
332 *m = best_m;
333 *s = best_s;
334 }
335
336 return best_freq;
337}
338
339static unsigned long exynos_dsi_set_pll(struct exynos_dsi *dsi,
340 unsigned long freq)
341{
342 static const unsigned long freq_bands[] = {
343 100 * MHZ, 120 * MHZ, 160 * MHZ, 200 * MHZ,
344 270 * MHZ, 320 * MHZ, 390 * MHZ, 450 * MHZ,
345 510 * MHZ, 560 * MHZ, 640 * MHZ, 690 * MHZ,
346 770 * MHZ, 870 * MHZ, 950 * MHZ,
347 };
348 unsigned long fin, fout;
349 int timeout, band;
350 u8 p, s;
351 u16 m;
352 u32 reg;
353
354 clk_set_rate(dsi->pll_clk, dsi->pll_clk_rate);
355
356 fin = clk_get_rate(dsi->pll_clk);
357 if (!fin) {
358 dev_err(dsi->dev, "failed to get PLL clock frequency\n");
359 return 0;
360 }
361
362 dev_dbg(dsi->dev, "PLL input frequency: %lu\n", fin);
363
364 fout = exynos_dsi_pll_find_pms(dsi, fin, freq, &p, &m, &s);
365 if (!fout) {
366 dev_err(dsi->dev,
367 "failed to find PLL PMS for requested frequency\n");
368 return -EFAULT;
369 }
370
371 for (band = 0; band < ARRAY_SIZE(freq_bands); ++band)
372 if (fout < freq_bands[band])
373 break;
374
375 dev_dbg(dsi->dev, "PLL freq %lu, (p %d, m %d, s %d), band %d\n", fout,
376 p, m, s, band);
377
378 writel(500, dsi->reg_base + DSIM_PLLTMR_REG);
379
380 reg = DSIM_FREQ_BAND(band) | DSIM_PLL_EN
381 | DSIM_PLL_P(p) | DSIM_PLL_M(m) | DSIM_PLL_S(s);
382 writel(reg, dsi->reg_base + DSIM_PLLCTRL_REG);
383
384 timeout = 1000;
385 do {
386 if (timeout-- == 0) {
387 dev_err(dsi->dev, "PLL failed to stabilize\n");
388 return -EFAULT;
389 }
390 reg = readl(dsi->reg_base + DSIM_STATUS_REG);
391 } while ((reg & DSIM_PLL_STABLE) == 0);
392
393 return fout;
394}
395
396static int exynos_dsi_enable_clock(struct exynos_dsi *dsi)
397{
398 unsigned long hs_clk, byte_clk, esc_clk;
399 unsigned long esc_div;
400 u32 reg;
401
402 hs_clk = exynos_dsi_set_pll(dsi, dsi->burst_clk_rate);
403 if (!hs_clk) {
404 dev_err(dsi->dev, "failed to configure DSI PLL\n");
405 return -EFAULT;
406 }
407
408 byte_clk = hs_clk / 8;
409 esc_div = DIV_ROUND_UP(byte_clk, dsi->esc_clk_rate);
410 esc_clk = byte_clk / esc_div;
411
412 if (esc_clk > 20 * MHZ) {
413 ++esc_div;
414 esc_clk = byte_clk / esc_div;
415 }
416
417 dev_dbg(dsi->dev, "hs_clk = %lu, byte_clk = %lu, esc_clk = %lu\n",
418 hs_clk, byte_clk, esc_clk);
419
420 reg = readl(dsi->reg_base + DSIM_CLKCTRL_REG);
421 reg &= ~(DSIM_ESC_PRESCALER_MASK | DSIM_LANE_ESC_CLK_EN_CLK
422 | DSIM_LANE_ESC_CLK_EN_DATA_MASK | DSIM_PLL_BYPASS
423 | DSIM_BYTE_CLK_SRC_MASK);
424 reg |= DSIM_ESC_CLKEN | DSIM_BYTE_CLKEN
425 | DSIM_ESC_PRESCALER(esc_div)
426 | DSIM_LANE_ESC_CLK_EN_CLK
427 | DSIM_LANE_ESC_CLK_EN_DATA(BIT(dsi->lanes) - 1)
428 | DSIM_BYTE_CLK_SRC(0)
429 | DSIM_TX_REQUEST_HSCLK;
430 writel(reg, dsi->reg_base + DSIM_CLKCTRL_REG);
431
432 return 0;
433}
434
435static void exynos_dsi_disable_clock(struct exynos_dsi *dsi)
436{
437 u32 reg;
438
439 reg = readl(dsi->reg_base + DSIM_CLKCTRL_REG);
440 reg &= ~(DSIM_LANE_ESC_CLK_EN_CLK | DSIM_LANE_ESC_CLK_EN_DATA_MASK
441 | DSIM_ESC_CLKEN | DSIM_BYTE_CLKEN);
442 writel(reg, dsi->reg_base + DSIM_CLKCTRL_REG);
443
444 reg = readl(dsi->reg_base + DSIM_PLLCTRL_REG);
445 reg &= ~DSIM_PLL_EN;
446 writel(reg, dsi->reg_base + DSIM_PLLCTRL_REG);
447}
448
449static int exynos_dsi_init_link(struct exynos_dsi *dsi)
450{
451 int timeout;
452 u32 reg;
453 u32 lanes_mask;
454
455 /* Initialize FIFO pointers */
456 reg = readl(dsi->reg_base + DSIM_FIFOCTRL_REG);
457 reg &= ~0x1f;
458 writel(reg, dsi->reg_base + DSIM_FIFOCTRL_REG);
459
460 usleep_range(9000, 11000);
461
462 reg |= 0x1f;
463 writel(reg, dsi->reg_base + DSIM_FIFOCTRL_REG);
464
465 usleep_range(9000, 11000);
466
467 /* DSI configuration */
468 reg = 0;
469
470 if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) {
471 reg |= DSIM_VIDEO_MODE;
472
473 if (!(dsi->mode_flags & MIPI_DSI_MODE_VSYNC_FLUSH))
474 reg |= DSIM_MFLUSH_VS;
475 if (!(dsi->mode_flags & MIPI_DSI_MODE_EOT_PACKET))
476 reg |= DSIM_EOT_DISABLE;
477 if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)
478 reg |= DSIM_SYNC_INFORM;
479 if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST)
480 reg |= DSIM_BURST_MODE;
481 if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_AUTO_VERT)
482 reg |= DSIM_AUTO_MODE;
483 if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_HSE)
484 reg |= DSIM_HSE_MODE;
485 if (!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO_HFP))
486 reg |= DSIM_HFP_MODE;
487 if (!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO_HBP))
488 reg |= DSIM_HBP_MODE;
489 if (!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO_HSA))
490 reg |= DSIM_HSA_MODE;
491 }
492
493 switch (dsi->format) {
494 case MIPI_DSI_FMT_RGB888:
495 reg |= DSIM_MAIN_PIX_FORMAT_RGB888;
496 break;
497 case MIPI_DSI_FMT_RGB666:
498 reg |= DSIM_MAIN_PIX_FORMAT_RGB666;
499 break;
500 case MIPI_DSI_FMT_RGB666_PACKED:
501 reg |= DSIM_MAIN_PIX_FORMAT_RGB666_P;
502 break;
503 case MIPI_DSI_FMT_RGB565:
504 reg |= DSIM_MAIN_PIX_FORMAT_RGB565;
505 break;
506 default:
507 dev_err(dsi->dev, "invalid pixel format\n");
508 return -EINVAL;
509 }
510
511 reg |= DSIM_NUM_OF_DATA_LANE(dsi->lanes - 1);
512
513 writel(reg, dsi->reg_base + DSIM_CONFIG_REG);
514
515 reg |= DSIM_LANE_EN_CLK;
516 writel(reg, dsi->reg_base + DSIM_CONFIG_REG);
517
518 lanes_mask = BIT(dsi->lanes) - 1;
519 reg |= DSIM_LANE_EN(lanes_mask);
520 writel(reg, dsi->reg_base + DSIM_CONFIG_REG);
521
522 /* Check clock and data lane state are stop state */
523 timeout = 100;
524 do {
525 if (timeout-- == 0) {
526 dev_err(dsi->dev, "waiting for bus lanes timed out\n");
527 return -EFAULT;
528 }
529
530 reg = readl(dsi->reg_base + DSIM_STATUS_REG);
531 if ((reg & DSIM_STOP_STATE_DAT(lanes_mask))
532 != DSIM_STOP_STATE_DAT(lanes_mask))
533 continue;
534 } while (!(reg & (DSIM_STOP_STATE_CLK | DSIM_TX_READY_HS_CLK)));
535
536 reg = readl(dsi->reg_base + DSIM_ESCMODE_REG);
537 reg &= ~DSIM_STOP_STATE_CNT_MASK;
538 reg |= DSIM_STOP_STATE_CNT(0xf);
539 writel(reg, dsi->reg_base + DSIM_ESCMODE_REG);
540
541 reg = DSIM_BTA_TIMEOUT(0xff) | DSIM_LPDR_TIMEOUT(0xffff);
542 writel(reg, dsi->reg_base + DSIM_TIMEOUT_REG);
543
544 return 0;
545}
546
547static void exynos_dsi_set_display_mode(struct exynos_dsi *dsi)
548{
549 struct videomode *vm = &dsi->vm;
550 u32 reg;
551
552 if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) {
553 reg = DSIM_CMD_ALLOW(0xf)
554 | DSIM_STABLE_VFP(vm->vfront_porch)
555 | DSIM_MAIN_VBP(vm->vback_porch);
556 writel(reg, dsi->reg_base + DSIM_MVPORCH_REG);
557
558 reg = DSIM_MAIN_HFP(vm->hfront_porch)
559 | DSIM_MAIN_HBP(vm->hback_porch);
560 writel(reg, dsi->reg_base + DSIM_MHPORCH_REG);
561
562 reg = DSIM_MAIN_VSA(vm->vsync_len)
563 | DSIM_MAIN_HSA(vm->hsync_len);
564 writel(reg, dsi->reg_base + DSIM_MSYNC_REG);
565 }
566
567 reg = DSIM_MAIN_HRESOL(vm->hactive) | DSIM_MAIN_VRESOL(vm->vactive);
568 writel(reg, dsi->reg_base + DSIM_MDRESOL_REG);
569
570 dev_dbg(dsi->dev, "LCD size = %dx%d\n", vm->hactive, vm->vactive);
571}
572
573static void exynos_dsi_set_display_enable(struct exynos_dsi *dsi, bool enable)
574{
575 u32 reg;
576
577 reg = readl(dsi->reg_base + DSIM_MDRESOL_REG);
578 if (enable)
579 reg |= DSIM_MAIN_STAND_BY;
580 else
581 reg &= ~DSIM_MAIN_STAND_BY;
582 writel(reg, dsi->reg_base + DSIM_MDRESOL_REG);
583}
584
585static int exynos_dsi_wait_for_hdr_fifo(struct exynos_dsi *dsi)
586{
587 int timeout = 2000;
588
589 do {
590 u32 reg = readl(dsi->reg_base + DSIM_FIFOCTRL_REG);
591
592 if (!(reg & DSIM_SFR_HEADER_FULL))
593 return 0;
594
595 if (!cond_resched())
596 usleep_range(950, 1050);
597 } while (--timeout);
598
599 return -ETIMEDOUT;
600}
601
602static void exynos_dsi_set_cmd_lpm(struct exynos_dsi *dsi, bool lpm)
603{
604 u32 v = readl(dsi->reg_base + DSIM_ESCMODE_REG);
605
606 if (lpm)
607 v |= DSIM_CMD_LPDT_LP;
608 else
609 v &= ~DSIM_CMD_LPDT_LP;
610
611 writel(v, dsi->reg_base + DSIM_ESCMODE_REG);
612}
613
614static void exynos_dsi_force_bta(struct exynos_dsi *dsi)
615{
616 u32 v = readl(dsi->reg_base + DSIM_ESCMODE_REG);
617
618 v |= DSIM_FORCE_BTA;
619 writel(v, dsi->reg_base + DSIM_ESCMODE_REG);
620}
621
622static void exynos_dsi_send_to_fifo(struct exynos_dsi *dsi,
623 struct exynos_dsi_transfer *xfer)
624{
625 struct device *dev = dsi->dev;
626 const u8 *payload = xfer->tx_payload + xfer->tx_done;
627 u16 length = xfer->tx_len - xfer->tx_done;
628 bool first = !xfer->tx_done;
629 u32 reg;
630
631 dev_dbg(dev, "< xfer %p: tx len %u, done %u, rx len %u, done %u\n",
632 xfer, xfer->tx_len, xfer->tx_done, xfer->rx_len, xfer->rx_done);
633
634 if (length > DSI_TX_FIFO_SIZE)
635 length = DSI_TX_FIFO_SIZE;
636
637 xfer->tx_done += length;
638
639 /* Send payload */
640 while (length >= 4) {
641 reg = (payload[3] << 24) | (payload[2] << 16)
642 | (payload[1] << 8) | payload[0];
643 writel(reg, dsi->reg_base + DSIM_PAYLOAD_REG);
644 payload += 4;
645 length -= 4;
646 }
647
648 reg = 0;
649 switch (length) {
650 case 3:
651 reg |= payload[2] << 16;
652 /* Fall through */
653 case 2:
654 reg |= payload[1] << 8;
655 /* Fall through */
656 case 1:
657 reg |= payload[0];
658 writel(reg, dsi->reg_base + DSIM_PAYLOAD_REG);
659 break;
660 case 0:
661 /* Do nothing */
662 break;
663 }
664
665 /* Send packet header */
666 if (!first)
667 return;
668
669 reg = (xfer->data[1] << 16) | (xfer->data[0] << 8) | xfer->data_id;
670 if (exynos_dsi_wait_for_hdr_fifo(dsi)) {
671 dev_err(dev, "waiting for header FIFO timed out\n");
672 return;
673 }
674
675 if (NEQV(xfer->flags & MIPI_DSI_MSG_USE_LPM,
676 dsi->state & DSIM_STATE_CMD_LPM)) {
677 exynos_dsi_set_cmd_lpm(dsi, xfer->flags & MIPI_DSI_MSG_USE_LPM);
678 dsi->state ^= DSIM_STATE_CMD_LPM;
679 }
680
681 writel(reg, dsi->reg_base + DSIM_PKTHDR_REG);
682
683 if (xfer->flags & MIPI_DSI_MSG_REQ_ACK)
684 exynos_dsi_force_bta(dsi);
685}
686
687static void exynos_dsi_read_from_fifo(struct exynos_dsi *dsi,
688 struct exynos_dsi_transfer *xfer)
689{
690 u8 *payload = xfer->rx_payload + xfer->rx_done;
691 bool first = !xfer->rx_done;
692 struct device *dev = dsi->dev;
693 u16 length;
694 u32 reg;
695
696 if (first) {
697 reg = readl(dsi->reg_base + DSIM_RXFIFO_REG);
698
699 switch (reg & 0x3f) {
700 case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE:
701 case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE:
702 if (xfer->rx_len >= 2) {
703 payload[1] = reg >> 16;
704 ++xfer->rx_done;
705 }
706 /* Fall through */
707 case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE:
708 case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE:
709 payload[0] = reg >> 8;
710 ++xfer->rx_done;
711 xfer->rx_len = xfer->rx_done;
712 xfer->result = 0;
713 goto clear_fifo;
714 case MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT:
715 dev_err(dev, "DSI Error Report: 0x%04x\n",
716 (reg >> 8) & 0xffff);
717 xfer->result = 0;
718 goto clear_fifo;
719 }
720
721 length = (reg >> 8) & 0xffff;
722 if (length > xfer->rx_len) {
723 dev_err(dev,
724 "response too long (%u > %u bytes), stripping\n",
725 xfer->rx_len, length);
726 length = xfer->rx_len;
727 } else if (length < xfer->rx_len)
728 xfer->rx_len = length;
729 }
730
731 length = xfer->rx_len - xfer->rx_done;
732 xfer->rx_done += length;
733
734 /* Receive payload */
735 while (length >= 4) {
736 reg = readl(dsi->reg_base + DSIM_RXFIFO_REG);
737 payload[0] = (reg >> 0) & 0xff;
738 payload[1] = (reg >> 8) & 0xff;
739 payload[2] = (reg >> 16) & 0xff;
740 payload[3] = (reg >> 24) & 0xff;
741 payload += 4;
742 length -= 4;
743 }
744
745 if (length) {
746 reg = readl(dsi->reg_base + DSIM_RXFIFO_REG);
747 switch (length) {
748 case 3:
749 payload[2] = (reg >> 16) & 0xff;
750 /* Fall through */
751 case 2:
752 payload[1] = (reg >> 8) & 0xff;
753 /* Fall through */
754 case 1:
755 payload[0] = reg & 0xff;
756 }
757 }
758
759 if (xfer->rx_done == xfer->rx_len)
760 xfer->result = 0;
761
762clear_fifo:
763 length = DSI_RX_FIFO_SIZE / 4;
764 do {
765 reg = readl(dsi->reg_base + DSIM_RXFIFO_REG);
766 if (reg == DSI_RX_FIFO_EMPTY)
767 break;
768 } while (--length);
769}
770
771static void exynos_dsi_transfer_start(struct exynos_dsi *dsi)
772{
773 unsigned long flags;
774 struct exynos_dsi_transfer *xfer;
775 bool start = false;
776
777again:
778 spin_lock_irqsave(&dsi->transfer_lock, flags);
779
780 if (list_empty(&dsi->transfer_list)) {
781 spin_unlock_irqrestore(&dsi->transfer_lock, flags);
782 return;
783 }
784
785 xfer = list_first_entry(&dsi->transfer_list,
786 struct exynos_dsi_transfer, list);
787
788 spin_unlock_irqrestore(&dsi->transfer_lock, flags);
789
790 if (xfer->tx_len && xfer->tx_done == xfer->tx_len)
791 /* waiting for RX */
792 return;
793
794 exynos_dsi_send_to_fifo(dsi, xfer);
795
796 if (xfer->tx_len || xfer->rx_len)
797 return;
798
799 xfer->result = 0;
800 complete(&xfer->completed);
801
802 spin_lock_irqsave(&dsi->transfer_lock, flags);
803
804 list_del_init(&xfer->list);
805 start = !list_empty(&dsi->transfer_list);
806
807 spin_unlock_irqrestore(&dsi->transfer_lock, flags);
808
809 if (start)
810 goto again;
811}
812
813static bool exynos_dsi_transfer_finish(struct exynos_dsi *dsi)
814{
815 struct exynos_dsi_transfer *xfer;
816 unsigned long flags;
817 bool start = true;
818
819 spin_lock_irqsave(&dsi->transfer_lock, flags);
820
821 if (list_empty(&dsi->transfer_list)) {
822 spin_unlock_irqrestore(&dsi->transfer_lock, flags);
823 return false;
824 }
825
826 xfer = list_first_entry(&dsi->transfer_list,
827 struct exynos_dsi_transfer, list);
828
829 spin_unlock_irqrestore(&dsi->transfer_lock, flags);
830
831 dev_dbg(dsi->dev,
832 "> xfer %p, tx_len %u, tx_done %u, rx_len %u, rx_done %u\n",
833 xfer, xfer->tx_len, xfer->tx_done, xfer->rx_len, xfer->rx_done);
834
835 if (xfer->tx_done != xfer->tx_len)
836 return true;
837
838 if (xfer->rx_done != xfer->rx_len)
839 exynos_dsi_read_from_fifo(dsi, xfer);
840
841 if (xfer->rx_done != xfer->rx_len)
842 return true;
843
844 spin_lock_irqsave(&dsi->transfer_lock, flags);
845
846 list_del_init(&xfer->list);
847 start = !list_empty(&dsi->transfer_list);
848
849 spin_unlock_irqrestore(&dsi->transfer_lock, flags);
850
851 if (!xfer->rx_len)
852 xfer->result = 0;
853 complete(&xfer->completed);
854
855 return start;
856}
857
858static void exynos_dsi_remove_transfer(struct exynos_dsi *dsi,
859 struct exynos_dsi_transfer *xfer)
860{
861 unsigned long flags;
862 bool start;
863
864 spin_lock_irqsave(&dsi->transfer_lock, flags);
865
866 if (!list_empty(&dsi->transfer_list) &&
867 xfer == list_first_entry(&dsi->transfer_list,
868 struct exynos_dsi_transfer, list)) {
869 list_del_init(&xfer->list);
870 start = !list_empty(&dsi->transfer_list);
871 spin_unlock_irqrestore(&dsi->transfer_lock, flags);
872 if (start)
873 exynos_dsi_transfer_start(dsi);
874 return;
875 }
876
877 list_del_init(&xfer->list);
878
879 spin_unlock_irqrestore(&dsi->transfer_lock, flags);
880}
881
882static int exynos_dsi_transfer(struct exynos_dsi *dsi,
883 struct exynos_dsi_transfer *xfer)
884{
885 unsigned long flags;
886 bool stopped;
887
888 xfer->tx_done = 0;
889 xfer->rx_done = 0;
890 xfer->result = -ETIMEDOUT;
891 init_completion(&xfer->completed);
892
893 spin_lock_irqsave(&dsi->transfer_lock, flags);
894
895 stopped = list_empty(&dsi->transfer_list);
896 list_add_tail(&xfer->list, &dsi->transfer_list);
897
898 spin_unlock_irqrestore(&dsi->transfer_lock, flags);
899
900 if (stopped)
901 exynos_dsi_transfer_start(dsi);
902
903 wait_for_completion_timeout(&xfer->completed,
904 msecs_to_jiffies(DSI_XFER_TIMEOUT_MS));
905 if (xfer->result == -ETIMEDOUT) {
906 exynos_dsi_remove_transfer(dsi, xfer);
907 dev_err(dsi->dev, "xfer timed out: %*ph %*ph\n", 2, xfer->data,
908 xfer->tx_len, xfer->tx_payload);
909 return -ETIMEDOUT;
910 }
911
912 /* Also covers hardware timeout condition */
913 return xfer->result;
914}
915
916static irqreturn_t exynos_dsi_irq(int irq, void *dev_id)
917{
918 struct exynos_dsi *dsi = dev_id;
919 u32 status;
920
921 status = readl(dsi->reg_base + DSIM_INTSRC_REG);
922 if (!status) {
923 static unsigned long int j;
924 if (printk_timed_ratelimit(&j, 500))
925 dev_warn(dsi->dev, "spurious interrupt\n");
926 return IRQ_HANDLED;
927 }
928 writel(status, dsi->reg_base + DSIM_INTSRC_REG);
929
930 if (status & DSIM_INT_SW_RST_RELEASE) {
931 u32 mask = ~(DSIM_INT_RX_DONE | DSIM_INT_SFR_FIFO_EMPTY);
932 writel(mask, dsi->reg_base + DSIM_INTMSK_REG);
933 complete(&dsi->completed);
934 return IRQ_HANDLED;
935 }
936
937 if (!(status & (DSIM_INT_RX_DONE | DSIM_INT_SFR_FIFO_EMPTY)))
938 return IRQ_HANDLED;
939
940 if (exynos_dsi_transfer_finish(dsi))
941 exynos_dsi_transfer_start(dsi);
942
943 return IRQ_HANDLED;
944}
945
946static int exynos_dsi_init(struct exynos_dsi *dsi)
947{
948 exynos_dsi_enable_clock(dsi);
949 exynos_dsi_reset(dsi);
950 enable_irq(dsi->irq);
951 exynos_dsi_wait_for_reset(dsi);
952 exynos_dsi_init_link(dsi);
953
954 return 0;
955}
956
957static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
958 struct mipi_dsi_device *device)
959{
960 struct exynos_dsi *dsi = host_to_dsi(host);
961
962 dsi->lanes = device->lanes;
963 dsi->format = device->format;
964 dsi->mode_flags = device->mode_flags;
965 dsi->panel_node = device->dev.of_node;
966
967 if (dsi->connector.dev)
968 drm_helper_hpd_irq_event(dsi->connector.dev);
969
970 return 0;
971}
972
973static int exynos_dsi_host_detach(struct mipi_dsi_host *host,
974 struct mipi_dsi_device *device)
975{
976 struct exynos_dsi *dsi = host_to_dsi(host);
977
978 dsi->panel_node = NULL;
979
980 if (dsi->connector.dev)
981 drm_helper_hpd_irq_event(dsi->connector.dev);
982
983 return 0;
984}
985
986/* distinguish between short and long DSI packet types */
987static bool exynos_dsi_is_short_dsi_type(u8 type)
988{
989 return (type & 0x0f) <= 8;
990}
991
992static ssize_t exynos_dsi_host_transfer(struct mipi_dsi_host *host,
993 struct mipi_dsi_msg *msg)
994{
995 struct exynos_dsi *dsi = host_to_dsi(host);
996 struct exynos_dsi_transfer xfer;
997 int ret;
998
999 if (!(dsi->state & DSIM_STATE_INITIALIZED)) {
1000 ret = exynos_dsi_init(dsi);
1001 if (ret)
1002 return ret;
1003 dsi->state |= DSIM_STATE_INITIALIZED;
1004 }
1005
1006 if (msg->tx_len == 0)
1007 return -EINVAL;
1008
1009 xfer.data_id = msg->type | (msg->channel << 6);
1010
1011 if (exynos_dsi_is_short_dsi_type(msg->type)) {
1012 const char *tx_buf = msg->tx_buf;
1013
1014 if (msg->tx_len > 2)
1015 return -EINVAL;
1016 xfer.tx_len = 0;
1017 xfer.data[0] = tx_buf[0];
1018 xfer.data[1] = (msg->tx_len == 2) ? tx_buf[1] : 0;
1019 } else {
1020 xfer.tx_len = msg->tx_len;
1021 xfer.data[0] = msg->tx_len & 0xff;
1022 xfer.data[1] = msg->tx_len >> 8;
1023 xfer.tx_payload = msg->tx_buf;
1024 }
1025
1026 xfer.rx_len = msg->rx_len;
1027 xfer.rx_payload = msg->rx_buf;
1028 xfer.flags = msg->flags;
1029
1030 ret = exynos_dsi_transfer(dsi, &xfer);
1031 return (ret < 0) ? ret : xfer.rx_done;
1032}
1033
1034static const struct mipi_dsi_host_ops exynos_dsi_ops = {
1035 .attach = exynos_dsi_host_attach,
1036 .detach = exynos_dsi_host_detach,
1037 .transfer = exynos_dsi_host_transfer,
1038};
1039
1040static int exynos_dsi_poweron(struct exynos_dsi *dsi)
1041{
1042 int ret;
1043
1044 ret = regulator_bulk_enable(ARRAY_SIZE(dsi->supplies), dsi->supplies);
1045 if (ret < 0) {
1046 dev_err(dsi->dev, "cannot enable regulators %d\n", ret);
1047 return ret;
1048 }
1049
1050 ret = clk_prepare_enable(dsi->bus_clk);
1051 if (ret < 0) {
1052 dev_err(dsi->dev, "cannot enable bus clock %d\n", ret);
1053 goto err_bus_clk;
1054 }
1055
1056 ret = clk_prepare_enable(dsi->pll_clk);
1057 if (ret < 0) {
1058 dev_err(dsi->dev, "cannot enable pll clock %d\n", ret);
1059 goto err_pll_clk;
1060 }
1061
1062 ret = phy_power_on(dsi->phy);
1063 if (ret < 0) {
1064 dev_err(dsi->dev, "cannot enable phy %d\n", ret);
1065 goto err_phy;
1066 }
1067
1068 return 0;
1069
1070err_phy:
1071 clk_disable_unprepare(dsi->pll_clk);
1072err_pll_clk:
1073 clk_disable_unprepare(dsi->bus_clk);
1074err_bus_clk:
1075 regulator_bulk_disable(ARRAY_SIZE(dsi->supplies), dsi->supplies);
1076
1077 return ret;
1078}
1079
1080static void exynos_dsi_poweroff(struct exynos_dsi *dsi)
1081{
1082 int ret;
1083
1084 usleep_range(10000, 20000);
1085
1086 if (dsi->state & DSIM_STATE_INITIALIZED) {
1087 dsi->state &= ~DSIM_STATE_INITIALIZED;
1088
1089 exynos_dsi_disable_clock(dsi);
1090
1091 disable_irq(dsi->irq);
1092 }
1093
1094 dsi->state &= ~DSIM_STATE_CMD_LPM;
1095
1096 phy_power_off(dsi->phy);
1097
1098 clk_disable_unprepare(dsi->pll_clk);
1099 clk_disable_unprepare(dsi->bus_clk);
1100
1101 ret = regulator_bulk_disable(ARRAY_SIZE(dsi->supplies), dsi->supplies);
1102 if (ret < 0)
1103 dev_err(dsi->dev, "cannot disable regulators %d\n", ret);
1104}
1105
1106static int exynos_dsi_enable(struct exynos_dsi *dsi)
1107{
1108 int ret;
1109
1110 if (dsi->state & DSIM_STATE_ENABLED)
1111 return 0;
1112
1113 ret = exynos_dsi_poweron(dsi);
1114 if (ret < 0)
1115 return ret;
1116
1117 ret = drm_panel_enable(dsi->panel);
1118 if (ret < 0) {
1119 exynos_dsi_poweroff(dsi);
1120 return ret;
1121 }
1122
1123 exynos_dsi_set_display_mode(dsi);
1124 exynos_dsi_set_display_enable(dsi, true);
1125
1126 dsi->state |= DSIM_STATE_ENABLED;
1127
1128 return 0;
1129}
1130
1131static void exynos_dsi_disable(struct exynos_dsi *dsi)
1132{
1133 if (!(dsi->state & DSIM_STATE_ENABLED))
1134 return;
1135
1136 exynos_dsi_set_display_enable(dsi, false);
1137 drm_panel_disable(dsi->panel);
1138 exynos_dsi_poweroff(dsi);
1139
1140 dsi->state &= ~DSIM_STATE_ENABLED;
1141}
1142
1143static void exynos_dsi_dpms(struct exynos_drm_display *display, int mode)
1144{
1145 struct exynos_dsi *dsi = display->ctx;
1146
1147 if (dsi->panel) {
1148 switch (mode) {
1149 case DRM_MODE_DPMS_ON:
1150 exynos_dsi_enable(dsi);
1151 break;
1152 case DRM_MODE_DPMS_STANDBY:
1153 case DRM_MODE_DPMS_SUSPEND:
1154 case DRM_MODE_DPMS_OFF:
1155 exynos_dsi_disable(dsi);
1156 break;
1157 default:
1158 break;
1159 }
1160 }
1161}
1162
1163static enum drm_connector_status
1164exynos_dsi_detect(struct drm_connector *connector, bool force)
1165{
1166 struct exynos_dsi *dsi = connector_to_dsi(connector);
1167
1168 if (!dsi->panel) {
1169 dsi->panel = of_drm_find_panel(dsi->panel_node);
1170 if (dsi->panel)
1171 drm_panel_attach(dsi->panel, &dsi->connector);
1172 } else if (!dsi->panel_node) {
1173 struct exynos_drm_display *display;
1174
1175 display = platform_get_drvdata(to_platform_device(dsi->dev));
1176 exynos_dsi_dpms(display, DRM_MODE_DPMS_OFF);
1177 drm_panel_detach(dsi->panel);
1178 dsi->panel = NULL;
1179 }
1180
1181 if (dsi->panel)
1182 return connector_status_connected;
1183
1184 return connector_status_disconnected;
1185}
1186
1187static void exynos_dsi_connector_destroy(struct drm_connector *connector)
1188{
1189}
1190
1191static struct drm_connector_funcs exynos_dsi_connector_funcs = {
1192 .dpms = drm_helper_connector_dpms,
1193 .detect = exynos_dsi_detect,
1194 .fill_modes = drm_helper_probe_single_connector_modes,
1195 .destroy = exynos_dsi_connector_destroy,
1196};
1197
1198static int exynos_dsi_get_modes(struct drm_connector *connector)
1199{
1200 struct exynos_dsi *dsi = connector_to_dsi(connector);
1201
1202 if (dsi->panel)
1203 return dsi->panel->funcs->get_modes(dsi->panel);
1204
1205 return 0;
1206}
1207
1208static int exynos_dsi_mode_valid(struct drm_connector *connector,
1209 struct drm_display_mode *mode)
1210{
1211 return MODE_OK;
1212}
1213
1214static struct drm_encoder *
1215exynos_dsi_best_encoder(struct drm_connector *connector)
1216{
1217 struct exynos_dsi *dsi = connector_to_dsi(connector);
1218
1219 return dsi->encoder;
1220}
1221
1222static struct drm_connector_helper_funcs exynos_dsi_connector_helper_funcs = {
1223 .get_modes = exynos_dsi_get_modes,
1224 .mode_valid = exynos_dsi_mode_valid,
1225 .best_encoder = exynos_dsi_best_encoder,
1226};
1227
1228static int exynos_dsi_create_connector(struct exynos_drm_display *display,
1229 struct drm_encoder *encoder)
1230{
1231 struct exynos_dsi *dsi = display->ctx;
1232 struct drm_connector *connector = &dsi->connector;
1233 int ret;
1234
1235 dsi->encoder = encoder;
1236
1237 connector->polled = DRM_CONNECTOR_POLL_HPD;
1238
1239 ret = drm_connector_init(encoder->dev, connector,
1240 &exynos_dsi_connector_funcs,
1241 DRM_MODE_CONNECTOR_DSI);
1242 if (ret) {
1243 DRM_ERROR("Failed to initialize connector with drm\n");
1244 return ret;
1245 }
1246
1247 drm_connector_helper_add(connector, &exynos_dsi_connector_helper_funcs);
1248 drm_sysfs_connector_add(connector);
1249 drm_mode_connector_attach_encoder(connector, encoder);
1250
1251 return 0;
1252}
1253
1254static void exynos_dsi_mode_set(struct exynos_drm_display *display,
1255 struct drm_display_mode *mode)
1256{
1257 struct exynos_dsi *dsi = display->ctx;
1258 struct videomode *vm = &dsi->vm;
1259
1260 vm->hactive = mode->hdisplay;
1261 vm->vactive = mode->vdisplay;
1262 vm->vfront_porch = mode->vsync_start - mode->vdisplay;
1263 vm->vback_porch = mode->vtotal - mode->vsync_end;
1264 vm->vsync_len = mode->vsync_end - mode->vsync_start;
1265 vm->hfront_porch = mode->hsync_start - mode->hdisplay;
1266 vm->hback_porch = mode->htotal - mode->hsync_end;
1267 vm->hsync_len = mode->hsync_end - mode->hsync_start;
1268}
1269
1270static struct exynos_drm_display_ops exynos_dsi_display_ops = {
1271 .create_connector = exynos_dsi_create_connector,
1272 .mode_set = exynos_dsi_mode_set,
1273 .dpms = exynos_dsi_dpms
1274};
1275
1276static struct exynos_drm_display exynos_dsi_display = {
1277 .type = EXYNOS_DISPLAY_TYPE_LCD,
1278 .ops = &exynos_dsi_display_ops,
1279};
1280
1281/* of_* functions will be removed after merge of of_graph patches */
1282static struct device_node *
1283of_get_child_by_name_reg(struct device_node *parent, const char *name, u32 reg)
1284{
1285 struct device_node *np;
1286
1287 for_each_child_of_node(parent, np) {
1288 u32 r;
1289
1290 if (!np->name || of_node_cmp(np->name, name))
1291 continue;
1292
1293 if (of_property_read_u32(np, "reg", &r) < 0)
1294 r = 0;
1295
1296 if (reg == r)
1297 break;
1298 }
1299
1300 return np;
1301}
1302
1303static struct device_node *of_graph_get_port_by_reg(struct device_node *parent,
1304 u32 reg)
1305{
1306 struct device_node *ports, *port;
1307
1308 ports = of_get_child_by_name(parent, "ports");
1309 if (ports)
1310 parent = ports;
1311
1312 port = of_get_child_by_name_reg(parent, "port", reg);
1313
1314 of_node_put(ports);
1315
1316 return port;
1317}
1318
1319static struct device_node *
1320of_graph_get_endpoint_by_reg(struct device_node *port, u32 reg)
1321{
1322 return of_get_child_by_name_reg(port, "endpoint", reg);
1323}
1324
1325static int exynos_dsi_of_read_u32(const struct device_node *np,
1326 const char *propname, u32 *out_value)
1327{
1328 int ret = of_property_read_u32(np, propname, out_value);
1329
1330 if (ret < 0)
1331 pr_err("%s: failed to get '%s' property\n", np->full_name,
1332 propname);
1333
1334 return ret;
1335}
1336
1337enum {
1338 DSI_PORT_IN,
1339 DSI_PORT_OUT
1340};
1341
1342static int exynos_dsi_parse_dt(struct exynos_dsi *dsi)
1343{
1344 struct device *dev = dsi->dev;
1345 struct device_node *node = dev->of_node;
1346 struct device_node *port, *ep;
1347 int ret;
1348
1349 ret = exynos_dsi_of_read_u32(node, "samsung,pll-clock-frequency",
1350 &dsi->pll_clk_rate);
1351 if (ret < 0)
1352 return ret;
1353
1354 port = of_graph_get_port_by_reg(node, DSI_PORT_OUT);
1355 if (!port) {
1356 dev_err(dev, "no output port specified\n");
1357 return -EINVAL;
1358 }
1359
1360 ep = of_graph_get_endpoint_by_reg(port, 0);
1361 of_node_put(port);
1362 if (!ep) {
1363 dev_err(dev, "no endpoint specified in output port\n");
1364 return -EINVAL;
1365 }
1366
1367 ret = exynos_dsi_of_read_u32(ep, "samsung,burst-clock-frequency",
1368 &dsi->burst_clk_rate);
1369 if (ret < 0)
1370 goto end;
1371
1372 ret = exynos_dsi_of_read_u32(ep, "samsung,esc-clock-frequency",
1373 &dsi->esc_clk_rate);
1374
1375end:
1376 of_node_put(ep);
1377
1378 return ret;
1379}
1380
1381static int exynos_dsi_probe(struct platform_device *pdev)
1382{
1383 struct resource *res;
1384 struct exynos_dsi *dsi;
1385 int ret;
1386
1387 dsi = devm_kzalloc(&pdev->dev, sizeof(*dsi), GFP_KERNEL);
1388 if (!dsi) {
1389 dev_err(&pdev->dev, "failed to allocate dsi object.\n");
1390 return -ENOMEM;
1391 }
1392
1393 init_completion(&dsi->completed);
1394 spin_lock_init(&dsi->transfer_lock);
1395 INIT_LIST_HEAD(&dsi->transfer_list);
1396
1397 dsi->dsi_host.ops = &exynos_dsi_ops;
1398 dsi->dsi_host.dev = &pdev->dev;
1399
1400 dsi->dev = &pdev->dev;
1401
1402 ret = exynos_dsi_parse_dt(dsi);
1403 if (ret)
1404 return ret;
1405
1406 dsi->supplies[0].supply = "vddcore";
1407 dsi->supplies[1].supply = "vddio";
1408 ret = devm_regulator_bulk_get(&pdev->dev, ARRAY_SIZE(dsi->supplies),
1409 dsi->supplies);
1410 if (ret) {
1411 dev_info(&pdev->dev, "failed to get regulators: %d\n", ret);
1412 return -EPROBE_DEFER;
1413 }
1414
1415 dsi->pll_clk = devm_clk_get(&pdev->dev, "pll_clk");
1416 if (IS_ERR(dsi->pll_clk)) {
1417 dev_info(&pdev->dev, "failed to get dsi pll input clock\n");
1418 return -EPROBE_DEFER;
1419 }
1420
1421 dsi->bus_clk = devm_clk_get(&pdev->dev, "bus_clk");
1422 if (IS_ERR(dsi->bus_clk)) {
1423 dev_info(&pdev->dev, "failed to get dsi bus clock\n");
1424 return -EPROBE_DEFER;
1425 }
1426
1427 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1428 dsi->reg_base = devm_ioremap_resource(&pdev->dev, res);
1429 if (!dsi->reg_base) {
1430 dev_err(&pdev->dev, "failed to remap io region\n");
1431 return -EADDRNOTAVAIL;
1432 }
1433
1434 dsi->phy = devm_phy_get(&pdev->dev, "dsim");
1435 if (IS_ERR(dsi->phy)) {
1436 dev_info(&pdev->dev, "failed to get dsim phy\n");
1437 return -EPROBE_DEFER;
1438 }
1439
1440 dsi->irq = platform_get_irq(pdev, 0);
1441 if (dsi->irq < 0) {
1442 dev_err(&pdev->dev, "failed to request dsi irq resource\n");
1443 return dsi->irq;
1444 }
1445
1446 irq_set_status_flags(dsi->irq, IRQ_NOAUTOEN);
1447 ret = devm_request_threaded_irq(&pdev->dev, dsi->irq, NULL,
1448 exynos_dsi_irq, IRQF_ONESHOT,
1449 dev_name(&pdev->dev), dsi);
1450 if (ret) {
1451 dev_err(&pdev->dev, "failed to request dsi irq\n");
1452 return ret;
1453 }
1454
1455 exynos_dsi_display.ctx = dsi;
1456
1457 platform_set_drvdata(pdev, &exynos_dsi_display);
1458 exynos_drm_display_register(&exynos_dsi_display);
1459
1460 return mipi_dsi_host_register(&dsi->dsi_host);
1461}
1462
1463static int exynos_dsi_remove(struct platform_device *pdev)
1464{
1465 struct exynos_dsi *dsi = exynos_dsi_display.ctx;
1466
1467 exynos_dsi_dpms(&exynos_dsi_display, DRM_MODE_DPMS_OFF);
1468
1469 exynos_drm_display_unregister(&exynos_dsi_display);
1470 mipi_dsi_host_unregister(&dsi->dsi_host);
1471
1472 return 0;
1473}
1474
1475#if CONFIG_PM_SLEEP
1476static int exynos_dsi_resume(struct device *dev)
1477{
1478 struct exynos_dsi *dsi = exynos_dsi_display.ctx;
1479
1480 if (dsi->state & DSIM_STATE_ENABLED) {
1481 dsi->state &= ~DSIM_STATE_ENABLED;
1482 exynos_dsi_enable(dsi);
1483 }
1484
1485 return 0;
1486}
1487
1488static int exynos_dsi_suspend(struct device *dev)
1489{
1490 struct exynos_dsi *dsi = exynos_dsi_display.ctx;
1491
1492 if (dsi->state & DSIM_STATE_ENABLED) {
1493 exynos_dsi_disable(dsi);
1494 dsi->state |= DSIM_STATE_ENABLED;
1495 }
1496
1497 return 0;
1498}
1499#endif
1500
1501static const struct dev_pm_ops exynos_dsi_pm_ops = {
1502 SET_SYSTEM_SLEEP_PM_OPS(exynos_dsi_suspend, exynos_dsi_resume)
1503};
1504
1505static struct of_device_id exynos_dsi_of_match[] = {
1506 { .compatible = "samsung,exynos4210-mipi-dsi" },
1507 { }
1508};
1509
1510struct platform_driver dsi_driver = {
1511 .probe = exynos_dsi_probe,
1512 .remove = exynos_dsi_remove,
1513 .driver = {
1514 .name = "exynos-dsi",
1515 .owner = THIS_MODULE,
1516 .pm = &exynos_dsi_pm_ops,
1517 .of_match_table = exynos_dsi_of_match,
1518 },
1519};
1520
1521MODULE_AUTHOR("Tomasz Figa <t.figa@samsung.com>");
1522MODULE_AUTHOR("Andrzej Hajda <a.hajda@samsung.com>");
1523MODULE_DESCRIPTION("Samsung SoC MIPI DSI Master");
1524MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
index 5fa342e5f963..addbf7536da4 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
@@ -237,6 +237,24 @@ static struct drm_fb_helper_funcs exynos_drm_fb_helper_funcs = {
237 .fb_probe = exynos_drm_fbdev_create, 237 .fb_probe = exynos_drm_fbdev_create,
238}; 238};
239 239
240bool exynos_drm_fbdev_is_anything_connected(struct drm_device *dev)
241{
242 struct drm_connector *connector;
243 bool ret = false;
244
245 mutex_lock(&dev->mode_config.mutex);
246 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
247 if (connector->status != connector_status_connected)
248 continue;
249
250 ret = true;
251 break;
252 }
253 mutex_unlock(&dev->mode_config.mutex);
254
255 return ret;
256}
257
240int exynos_drm_fbdev_init(struct drm_device *dev) 258int exynos_drm_fbdev_init(struct drm_device *dev)
241{ 259{
242 struct exynos_drm_fbdev *fbdev; 260 struct exynos_drm_fbdev *fbdev;
@@ -248,6 +266,9 @@ int exynos_drm_fbdev_init(struct drm_device *dev)
248 if (!dev->mode_config.num_crtc || !dev->mode_config.num_connector) 266 if (!dev->mode_config.num_crtc || !dev->mode_config.num_connector)
249 return 0; 267 return 0;
250 268
269 if (!exynos_drm_fbdev_is_anything_connected(dev))
270 return 0;
271
251 fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL); 272 fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL);
252 if (!fbdev) 273 if (!fbdev)
253 return -ENOMEM; 274 return -ENOMEM;
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index 3e0f13d1bc84..4ec874da5668 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -16,4 +16,18 @@ config DRM_PANEL_SIMPLE
16 that it can be automatically turned off when the panel goes into a 16 that it can be automatically turned off when the panel goes into a
17 low power state. 17 low power state.
18 18
19config DRM_PANEL_LD9040
20 tristate "LD9040 RGB/SPI panel"
21 depends on DRM && DRM_PANEL
22 depends on OF
23 select SPI
24 select VIDEOMODE_HELPERS
25
26config DRM_PANEL_S6E8AA0
27 tristate "S6E8AA0 DSI video mode panel"
28 depends on DRM && DRM_PANEL
29 depends on OF
30 select DRM_MIPI_DSI
31 select VIDEOMODE_HELPERS
32
19endmenu 33endmenu
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
index af9dfa235b94..8b929212fad7 100644
--- a/drivers/gpu/drm/panel/Makefile
+++ b/drivers/gpu/drm/panel/Makefile
@@ -1 +1,3 @@
1obj-$(CONFIG_DRM_PANEL_SIMPLE) += panel-simple.o 1obj-$(CONFIG_DRM_PANEL_SIMPLE) += panel-simple.o
2obj-$(CONFIG_DRM_PANEL_LD9040) += panel-ld9040.o
3obj-$(CONFIG_DRM_PANEL_S6E8AA0) += panel-s6e8aa0.o
diff --git a/drivers/gpu/drm/panel/panel-ld9040.c b/drivers/gpu/drm/panel/panel-ld9040.c
new file mode 100644
index 000000000000..1f1f8371a199
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-ld9040.c
@@ -0,0 +1,376 @@
1/*
2 * ld9040 AMOLED LCD drm_panel driver.
3 *
4 * Copyright (c) 2014 Samsung Electronics Co., Ltd
5 * Derived from drivers/video/backlight/ld9040.c
6 *
7 * Andrzej Hajda <a.hajda@samsung.com>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12*/
13
14#include <drm/drmP.h>
15#include <drm/drm_panel.h>
16
17#include <linux/gpio/consumer.h>
18#include <linux/regulator/consumer.h>
19#include <linux/spi/spi.h>
20
21#include <video/mipi_display.h>
22#include <video/of_videomode.h>
23#include <video/videomode.h>
24
25/* Manufacturer Command Set */
26#define MCS_MANPWR 0xb0
27#define MCS_ELVSS_ON 0xb1
28#define MCS_USER_SETTING 0xf0
29#define MCS_DISPCTL 0xf2
30#define MCS_GTCON 0xf7
31#define MCS_PANEL_CONDITION 0xf8
32#define MCS_GAMMA_SET1 0xf9
33#define MCS_GAMMA_CTRL 0xfb
34
35/* array of gamma tables for gamma value 2.2 */
36static u8 const ld9040_gammas[25][22] = {
37 { 0xf9, 0x00, 0x13, 0xb2, 0xba, 0xd2, 0x00, 0x30, 0x00, 0xaf, 0xc0,
38 0xb8, 0xcd, 0x00, 0x3d, 0x00, 0xa8, 0xb8, 0xb7, 0xcd, 0x00, 0x44 },
39 { 0xf9, 0x00, 0x13, 0xb9, 0xb9, 0xd0, 0x00, 0x3c, 0x00, 0xaf, 0xbf,
40 0xb6, 0xcb, 0x00, 0x4b, 0x00, 0xa8, 0xb9, 0xb5, 0xcc, 0x00, 0x52 },
41 { 0xf9, 0x00, 0x13, 0xba, 0xb9, 0xcd, 0x00, 0x41, 0x00, 0xb0, 0xbe,
42 0xb5, 0xc9, 0x00, 0x51, 0x00, 0xa9, 0xb9, 0xb5, 0xca, 0x00, 0x57 },
43 { 0xf9, 0x00, 0x13, 0xb9, 0xb8, 0xcd, 0x00, 0x46, 0x00, 0xb1, 0xbc,
44 0xb5, 0xc8, 0x00, 0x56, 0x00, 0xaa, 0xb8, 0xb4, 0xc9, 0x00, 0x5d },
45 { 0xf9, 0x00, 0x13, 0xba, 0xb8, 0xcb, 0x00, 0x4b, 0x00, 0xb3, 0xbc,
46 0xb4, 0xc7, 0x00, 0x5c, 0x00, 0xac, 0xb8, 0xb4, 0xc8, 0x00, 0x62 },
47 { 0xf9, 0x00, 0x13, 0xbb, 0xb7, 0xca, 0x00, 0x4f, 0x00, 0xb4, 0xbb,
48 0xb3, 0xc7, 0x00, 0x60, 0x00, 0xad, 0xb8, 0xb4, 0xc7, 0x00, 0x67 },
49 { 0xf9, 0x00, 0x47, 0xba, 0xb6, 0xca, 0x00, 0x53, 0x00, 0xb5, 0xbb,
50 0xb3, 0xc6, 0x00, 0x65, 0x00, 0xae, 0xb8, 0xb3, 0xc7, 0x00, 0x6c },
51 { 0xf9, 0x00, 0x71, 0xbb, 0xb5, 0xc8, 0x00, 0x57, 0x00, 0xb5, 0xbb,
52 0xb0, 0xc5, 0x00, 0x6a, 0x00, 0xae, 0xb9, 0xb1, 0xc6, 0x00, 0x70 },
53 { 0xf9, 0x00, 0x7b, 0xbb, 0xb4, 0xc8, 0x00, 0x5b, 0x00, 0xb5, 0xba,
54 0xb1, 0xc4, 0x00, 0x6e, 0x00, 0xae, 0xb9, 0xb0, 0xc5, 0x00, 0x75 },
55 { 0xf9, 0x00, 0x82, 0xba, 0xb4, 0xc7, 0x00, 0x5f, 0x00, 0xb5, 0xba,
56 0xb0, 0xc3, 0x00, 0x72, 0x00, 0xae, 0xb8, 0xb0, 0xc3, 0x00, 0x7a },
57 { 0xf9, 0x00, 0x89, 0xba, 0xb3, 0xc8, 0x00, 0x62, 0x00, 0xb6, 0xba,
58 0xaf, 0xc3, 0x00, 0x76, 0x00, 0xaf, 0xb7, 0xae, 0xc4, 0x00, 0x7e },
59 { 0xf9, 0x00, 0x8b, 0xb9, 0xb3, 0xc7, 0x00, 0x65, 0x00, 0xb7, 0xb8,
60 0xaf, 0xc3, 0x00, 0x7a, 0x00, 0x80, 0xb6, 0xae, 0xc4, 0x00, 0x81 },
61 { 0xf9, 0x00, 0x93, 0xba, 0xb3, 0xc5, 0x00, 0x69, 0x00, 0xb8, 0xb9,
62 0xae, 0xc1, 0x00, 0x7f, 0x00, 0xb0, 0xb6, 0xae, 0xc3, 0x00, 0x85 },
63 { 0xf9, 0x00, 0x97, 0xba, 0xb2, 0xc5, 0x00, 0x6c, 0x00, 0xb8, 0xb8,
64 0xae, 0xc1, 0x00, 0x82, 0x00, 0xb0, 0xb6, 0xae, 0xc2, 0x00, 0x89 },
65 { 0xf9, 0x00, 0x9a, 0xba, 0xb1, 0xc4, 0x00, 0x6f, 0x00, 0xb8, 0xb8,
66 0xad, 0xc0, 0x00, 0x86, 0x00, 0xb0, 0xb7, 0xad, 0xc0, 0x00, 0x8d },
67 { 0xf9, 0x00, 0x9c, 0xb9, 0xb0, 0xc4, 0x00, 0x72, 0x00, 0xb8, 0xb8,
68 0xac, 0xbf, 0x00, 0x8a, 0x00, 0xb0, 0xb6, 0xac, 0xc0, 0x00, 0x91 },
69 { 0xf9, 0x00, 0x9e, 0xba, 0xb0, 0xc2, 0x00, 0x75, 0x00, 0xb9, 0xb8,
70 0xab, 0xbe, 0x00, 0x8e, 0x00, 0xb0, 0xb6, 0xac, 0xbf, 0x00, 0x94 },
71 { 0xf9, 0x00, 0xa0, 0xb9, 0xaf, 0xc3, 0x00, 0x77, 0x00, 0xb9, 0xb7,
72 0xab, 0xbe, 0x00, 0x90, 0x00, 0xb0, 0xb6, 0xab, 0xbf, 0x00, 0x97 },
73 { 0xf9, 0x00, 0xa2, 0xb9, 0xaf, 0xc2, 0x00, 0x7a, 0x00, 0xb9, 0xb7,
74 0xaa, 0xbd, 0x00, 0x94, 0x00, 0xb0, 0xb5, 0xab, 0xbf, 0x00, 0x9a },
75 { 0xf9, 0x00, 0xa4, 0xb9, 0xaf, 0xc1, 0x00, 0x7d, 0x00, 0xb9, 0xb6,
76 0xaa, 0xbb, 0x00, 0x97, 0x00, 0xb1, 0xb5, 0xaa, 0xbf, 0x00, 0x9d },
77 { 0xf9, 0x00, 0xa4, 0xb8, 0xb0, 0xbf, 0x00, 0x80, 0x00, 0xb8, 0xb6,
78 0xaa, 0xbc, 0x00, 0x9a, 0x00, 0xb0, 0xb5, 0xab, 0xbd, 0x00, 0xa0 },
79 { 0xf9, 0x00, 0xa8, 0xb8, 0xae, 0xbe, 0x00, 0x84, 0x00, 0xb9, 0xb7,
80 0xa8, 0xbc, 0x00, 0x9d, 0x00, 0xb2, 0xb5, 0xaa, 0xbc, 0x00, 0xa4 },
81 { 0xf9, 0x00, 0xa9, 0xb6, 0xad, 0xbf, 0x00, 0x86, 0x00, 0xb8, 0xb5,
82 0xa8, 0xbc, 0x00, 0xa0, 0x00, 0xb3, 0xb3, 0xa9, 0xbc, 0x00, 0xa7 },
83 { 0xf9, 0x00, 0xa9, 0xb7, 0xae, 0xbd, 0x00, 0x89, 0x00, 0xb7, 0xb6,
84 0xa8, 0xba, 0x00, 0xa4, 0x00, 0xb1, 0xb4, 0xaa, 0xbb, 0x00, 0xaa },
85 { 0xf9, 0x00, 0xa7, 0xb4, 0xae, 0xbf, 0x00, 0x91, 0x00, 0xb2, 0xb4,
86 0xaa, 0xbb, 0x00, 0xac, 0x00, 0xb3, 0xb1, 0xaa, 0xbc, 0x00, 0xb3 },
87};
88
89struct ld9040 {
90 struct device *dev;
91 struct drm_panel panel;
92
93 struct regulator_bulk_data supplies[2];
94 struct gpio_desc *reset_gpio;
95 u32 power_on_delay;
96 u32 reset_delay;
97 struct videomode vm;
98 u32 width_mm;
99 u32 height_mm;
100
101 int brightness;
102
103 /* This field is tested by functions directly accessing bus before
104 * transfer, transfer is skipped if it is set. In case of transfer
105 * failure or unexpected response the field is set to error value.
106 * Such construct allows to eliminate many checks in higher level
107 * functions.
108 */
109 int error;
110};
111
112#define panel_to_ld9040(p) container_of(p, struct ld9040, panel)
113
114static int ld9040_clear_error(struct ld9040 *ctx)
115{
116 int ret = ctx->error;
117
118 ctx->error = 0;
119 return ret;
120}
121
122static int ld9040_spi_write_word(struct ld9040 *ctx, u16 data)
123{
124 struct spi_device *spi = to_spi_device(ctx->dev);
125 struct spi_transfer xfer = {
126 .len = 2,
127 .tx_buf = &data,
128 };
129 struct spi_message msg;
130
131 spi_message_init(&msg);
132 spi_message_add_tail(&xfer, &msg);
133
134 return spi_sync(spi, &msg);
135}
136
137static void ld9040_dcs_write(struct ld9040 *ctx, const u8 *data, size_t len)
138{
139 int ret = 0;
140
141 if (ctx->error < 0 || len == 0)
142 return;
143
144 dev_dbg(ctx->dev, "writing dcs seq: %*ph\n", len, data);
145 ret = ld9040_spi_write_word(ctx, *data);
146
147 while (!ret && --len) {
148 ++data;
149 ret = ld9040_spi_write_word(ctx, *data | 0x100);
150 }
151
152 if (ret) {
153 dev_err(ctx->dev, "error %d writing dcs seq: %*ph\n", ret, len,
154 data);
155 ctx->error = ret;
156 }
157
158 usleep_range(300, 310);
159}
160
161#define ld9040_dcs_write_seq_static(ctx, seq...) \
162({\
163 static const u8 d[] = { seq };\
164 ld9040_dcs_write(ctx, d, ARRAY_SIZE(d));\
165})
166
167static void ld9040_brightness_set(struct ld9040 *ctx)
168{
169 ld9040_dcs_write(ctx, ld9040_gammas[ctx->brightness],
170 ARRAY_SIZE(ld9040_gammas[ctx->brightness]));
171
172 ld9040_dcs_write_seq_static(ctx, MCS_GAMMA_CTRL, 0x02, 0x5a);
173}
174
175static void ld9040_init(struct ld9040 *ctx)
176{
177 ld9040_dcs_write_seq_static(ctx, MCS_USER_SETTING, 0x5a, 0x5a);
178 ld9040_dcs_write_seq_static(ctx, MCS_PANEL_CONDITION,
179 0x05, 0x65, 0x96, 0x71, 0x7d, 0x19, 0x3b, 0x0d,
180 0x19, 0x7e, 0x0d, 0xe2, 0x00, 0x00, 0x7e, 0x7d,
181 0x07, 0x07, 0x20, 0x20, 0x20, 0x02, 0x02);
182 ld9040_dcs_write_seq_static(ctx, MCS_DISPCTL,
183 0x02, 0x08, 0x08, 0x10, 0x10);
184 ld9040_dcs_write_seq_static(ctx, MCS_MANPWR, 0x04);
185 ld9040_dcs_write_seq_static(ctx, MCS_ELVSS_ON, 0x0d, 0x00, 0x16);
186 ld9040_dcs_write_seq_static(ctx, MCS_GTCON, 0x09, 0x00, 0x00);
187 ld9040_brightness_set(ctx);
188 ld9040_dcs_write_seq_static(ctx, MIPI_DCS_EXIT_SLEEP_MODE);
189 ld9040_dcs_write_seq_static(ctx, MIPI_DCS_SET_DISPLAY_ON);
190}
191
192static int ld9040_power_on(struct ld9040 *ctx)
193{
194 int ret;
195
196 ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
197 if (ret < 0)
198 return ret;
199
200 msleep(ctx->power_on_delay);
201 gpiod_set_value(ctx->reset_gpio, 0);
202 msleep(ctx->reset_delay);
203 gpiod_set_value(ctx->reset_gpio, 1);
204 msleep(ctx->reset_delay);
205
206 return 0;
207}
208
209static int ld9040_power_off(struct ld9040 *ctx)
210{
211 return regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
212}
213
214static int ld9040_disable(struct drm_panel *panel)
215{
216 struct ld9040 *ctx = panel_to_ld9040(panel);
217
218 msleep(120);
219 ld9040_dcs_write_seq_static(ctx, MIPI_DCS_SET_DISPLAY_OFF);
220 ld9040_dcs_write_seq_static(ctx, MIPI_DCS_ENTER_SLEEP_MODE);
221 msleep(40);
222
223 ld9040_clear_error(ctx);
224
225 return ld9040_power_off(ctx);
226}
227
228static int ld9040_enable(struct drm_panel *panel)
229{
230 struct ld9040 *ctx = panel_to_ld9040(panel);
231 int ret;
232
233 ret = ld9040_power_on(ctx);
234 if (ret < 0)
235 return ret;
236
237 ld9040_init(ctx);
238
239 ret = ld9040_clear_error(ctx);
240
241 if (ret < 0)
242 ld9040_disable(panel);
243
244 return ret;
245}
246
247static int ld9040_get_modes(struct drm_panel *panel)
248{
249 struct drm_connector *connector = panel->connector;
250 struct ld9040 *ctx = panel_to_ld9040(panel);
251 struct drm_display_mode *mode;
252
253 mode = drm_mode_create(connector->dev);
254 if (!mode) {
255 DRM_ERROR("failed to create a new display mode\n");
256 return 0;
257 }
258
259 drm_display_mode_from_videomode(&ctx->vm, mode);
260 mode->width_mm = ctx->width_mm;
261 mode->height_mm = ctx->height_mm;
262 connector->display_info.width_mm = mode->width_mm;
263 connector->display_info.height_mm = mode->height_mm;
264
265 mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
266 drm_mode_probed_add(connector, mode);
267
268 return 1;
269}
270
271static const struct drm_panel_funcs ld9040_drm_funcs = {
272 .disable = ld9040_disable,
273 .enable = ld9040_enable,
274 .get_modes = ld9040_get_modes,
275};
276
277static int ld9040_parse_dt(struct ld9040 *ctx)
278{
279 struct device *dev = ctx->dev;
280 struct device_node *np = dev->of_node;
281 int ret;
282
283 ret = of_get_videomode(np, &ctx->vm, 0);
284 if (ret < 0)
285 return ret;
286
287 of_property_read_u32(np, "power-on-delay", &ctx->power_on_delay);
288 of_property_read_u32(np, "reset-delay", &ctx->reset_delay);
289 of_property_read_u32(np, "panel-width-mm", &ctx->width_mm);
290 of_property_read_u32(np, "panel-height-mm", &ctx->height_mm);
291
292 return 0;
293}
294
295static int ld9040_probe(struct spi_device *spi)
296{
297 struct device *dev = &spi->dev;
298 struct ld9040 *ctx;
299 int ret;
300
301 ctx = devm_kzalloc(dev, sizeof(struct ld9040), GFP_KERNEL);
302 if (!ctx)
303 return -ENOMEM;
304
305 spi_set_drvdata(spi, ctx);
306
307 ctx->dev = dev;
308 ctx->brightness = ARRAY_SIZE(ld9040_gammas) - 1;
309
310 ret = ld9040_parse_dt(ctx);
311 if (ret < 0)
312 return ret;
313
314 ctx->supplies[0].supply = "vdd3";
315 ctx->supplies[1].supply = "vci";
316 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies),
317 ctx->supplies);
318 if (ret < 0)
319 return ret;
320
321 ctx->reset_gpio = devm_gpiod_get(dev, "reset");
322 if (IS_ERR(ctx->reset_gpio)) {
323 dev_err(dev, "cannot get reset-gpios %ld\n",
324 PTR_ERR(ctx->reset_gpio));
325 return PTR_ERR(ctx->reset_gpio);
326 }
327 ret = gpiod_direction_output(ctx->reset_gpio, 1);
328 if (ret < 0) {
329 dev_err(dev, "cannot configure reset-gpios %d\n", ret);
330 return ret;
331 }
332
333 spi->bits_per_word = 9;
334 ret = spi_setup(spi);
335 if (ret < 0) {
336 dev_err(dev, "spi setup failed.\n");
337 return ret;
338 }
339
340 drm_panel_init(&ctx->panel);
341 ctx->panel.dev = dev;
342 ctx->panel.funcs = &ld9040_drm_funcs;
343
344 return drm_panel_add(&ctx->panel);
345}
346
347static int ld9040_remove(struct spi_device *spi)
348{
349 struct ld9040 *ctx = spi_get_drvdata(spi);
350
351 ld9040_power_off(ctx);
352 drm_panel_remove(&ctx->panel);
353
354 return 0;
355}
356
357static struct of_device_id ld9040_of_match[] = {
358 { .compatible = "samsung,ld9040" },
359 { }
360};
361MODULE_DEVICE_TABLE(of, ld9040_of_match);
362
363static struct spi_driver ld9040_driver = {
364 .probe = ld9040_probe,
365 .remove = ld9040_remove,
366 .driver = {
367 .name = "ld9040",
368 .owner = THIS_MODULE,
369 .of_match_table = ld9040_of_match,
370 },
371};
372module_spi_driver(ld9040_driver);
373
374MODULE_AUTHOR("Andrzej Hajda <a.hajda@samsung.com>");
375MODULE_DESCRIPTION("ld9040 LCD Driver");
376MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/panel/panel-s6e8aa0.c b/drivers/gpu/drm/panel/panel-s6e8aa0.c
new file mode 100644
index 000000000000..35941d2412b8
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-s6e8aa0.c
@@ -0,0 +1,1069 @@
1/*
2 * MIPI-DSI based s6e8aa0 AMOLED LCD 5.3 inch panel driver.
3 *
4 * Copyright (c) 2013 Samsung Electronics Co., Ltd
5 *
6 * Inki Dae, <inki.dae@samsung.com>
7 * Donghwa Lee, <dh09.lee@samsung.com>
8 * Joongmock Shin <jmock.shin@samsung.com>
9 * Eunchul Kim <chulspro.kim@samsung.com>
10 * Tomasz Figa <t.figa@samsung.com>
11 * Andrzej Hajda <a.hajda@samsung.com>
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License version 2 as
15 * published by the Free Software Foundation.
16*/
17
18#include <drm/drmP.h>
19#include <drm/drm_mipi_dsi.h>
20#include <drm/drm_panel.h>
21
22#include <linux/gpio/consumer.h>
23#include <linux/regulator/consumer.h>
24
25#include <video/mipi_display.h>
26#include <video/of_videomode.h>
27#include <video/videomode.h>
28
29#define LDI_MTP_LENGTH 24
30#define GAMMA_LEVEL_NUM 25
31#define GAMMA_TABLE_LEN 26
32
33#define PANELCTL_SS_MASK (1 << 5)
34#define PANELCTL_SS_1_800 (0 << 5)
35#define PANELCTL_SS_800_1 (1 << 5)
36#define PANELCTL_GTCON_MASK (7 << 2)
37#define PANELCTL_GTCON_110 (6 << 2)
38#define PANELCTL_GTCON_111 (7 << 2)
39
40#define PANELCTL_CLK1_CON_MASK (7 << 3)
41#define PANELCTL_CLK1_000 (0 << 3)
42#define PANELCTL_CLK1_001 (1 << 3)
43#define PANELCTL_CLK2_CON_MASK (7 << 0)
44#define PANELCTL_CLK2_000 (0 << 0)
45#define PANELCTL_CLK2_001 (1 << 0)
46
47#define PANELCTL_INT1_CON_MASK (7 << 3)
48#define PANELCTL_INT1_000 (0 << 3)
49#define PANELCTL_INT1_001 (1 << 3)
50#define PANELCTL_INT2_CON_MASK (7 << 0)
51#define PANELCTL_INT2_000 (0 << 0)
52#define PANELCTL_INT2_001 (1 << 0)
53
54#define PANELCTL_BICTL_CON_MASK (7 << 3)
55#define PANELCTL_BICTL_000 (0 << 3)
56#define PANELCTL_BICTL_001 (1 << 3)
57#define PANELCTL_BICTLB_CON_MASK (7 << 0)
58#define PANELCTL_BICTLB_000 (0 << 0)
59#define PANELCTL_BICTLB_001 (1 << 0)
60
61#define PANELCTL_EM_CLK1_CON_MASK (7 << 3)
62#define PANELCTL_EM_CLK1_110 (6 << 3)
63#define PANELCTL_EM_CLK1_111 (7 << 3)
64#define PANELCTL_EM_CLK1B_CON_MASK (7 << 0)
65#define PANELCTL_EM_CLK1B_110 (6 << 0)
66#define PANELCTL_EM_CLK1B_111 (7 << 0)
67
68#define PANELCTL_EM_CLK2_CON_MASK (7 << 3)
69#define PANELCTL_EM_CLK2_110 (6 << 3)
70#define PANELCTL_EM_CLK2_111 (7 << 3)
71#define PANELCTL_EM_CLK2B_CON_MASK (7 << 0)
72#define PANELCTL_EM_CLK2B_110 (6 << 0)
73#define PANELCTL_EM_CLK2B_111 (7 << 0)
74
75#define PANELCTL_EM_INT1_CON_MASK (7 << 3)
76#define PANELCTL_EM_INT1_000 (0 << 3)
77#define PANELCTL_EM_INT1_001 (1 << 3)
78#define PANELCTL_EM_INT2_CON_MASK (7 << 0)
79#define PANELCTL_EM_INT2_000 (0 << 0)
80#define PANELCTL_EM_INT2_001 (1 << 0)
81
82#define AID_DISABLE (0x4)
83#define AID_1 (0x5)
84#define AID_2 (0x6)
85#define AID_3 (0x7)
86
87typedef u8 s6e8aa0_gamma_table[GAMMA_TABLE_LEN];
88
89struct s6e8aa0_variant {
90 u8 version;
91 const s6e8aa0_gamma_table *gamma_tables;
92};
93
94struct s6e8aa0 {
95 struct device *dev;
96 struct drm_panel panel;
97
98 struct regulator_bulk_data supplies[2];
99 struct gpio_desc *reset_gpio;
100 u32 power_on_delay;
101 u32 reset_delay;
102 u32 init_delay;
103 bool flip_horizontal;
104 bool flip_vertical;
105 struct videomode vm;
106 u32 width_mm;
107 u32 height_mm;
108
109 u8 version;
110 u8 id;
111 const struct s6e8aa0_variant *variant;
112 int brightness;
113
114 /* This field is tested by functions directly accessing DSI bus before
115 * transfer, transfer is skipped if it is set. In case of transfer
116 * failure or unexpected response the field is set to error value.
117 * Such construct allows to eliminate many checks in higher level
118 * functions.
119 */
120 int error;
121};
122
123#define panel_to_s6e8aa0(p) container_of(p, struct s6e8aa0, panel)
124
125static int s6e8aa0_clear_error(struct s6e8aa0 *ctx)
126{
127 int ret = ctx->error;
128
129 ctx->error = 0;
130 return ret;
131}
132
133static void s6e8aa0_dcs_write(struct s6e8aa0 *ctx, const void *data, size_t len)
134{
135 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
136 int ret;
137
138 if (ctx->error < 0)
139 return;
140
141 ret = mipi_dsi_dcs_write(dsi, dsi->channel, data, len);
142 if (ret < 0) {
143 dev_err(ctx->dev, "error %d writing dcs seq: %*ph\n", ret, len,
144 data);
145 ctx->error = ret;
146 }
147}
148
149static int s6e8aa0_dcs_read(struct s6e8aa0 *ctx, u8 cmd, void *data, size_t len)
150{
151 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
152 int ret;
153
154 if (ctx->error < 0)
155 return ctx->error;
156
157 ret = mipi_dsi_dcs_read(dsi, dsi->channel, cmd, data, len);
158 if (ret < 0) {
159 dev_err(ctx->dev, "error %d reading dcs seq(%#x)\n", ret, cmd);
160 ctx->error = ret;
161 }
162
163 return ret;
164}
165
166#define s6e8aa0_dcs_write_seq(ctx, seq...) \
167({\
168 const u8 d[] = { seq };\
169 BUILD_BUG_ON_MSG(ARRAY_SIZE(d) > 64, "DCS sequence too big for stack");\
170 s6e8aa0_dcs_write(ctx, d, ARRAY_SIZE(d));\
171})
172
173#define s6e8aa0_dcs_write_seq_static(ctx, seq...) \
174({\
175 static const u8 d[] = { seq };\
176 s6e8aa0_dcs_write(ctx, d, ARRAY_SIZE(d));\
177})
178
179static void s6e8aa0_apply_level_1_key(struct s6e8aa0 *ctx)
180{
181 s6e8aa0_dcs_write_seq_static(ctx, 0xf0, 0x5a, 0x5a);
182}
183
184static void s6e8aa0_panel_cond_set_v142(struct s6e8aa0 *ctx)
185{
186 static const u8 aids[] = {
187 0x04, 0x04, 0x04, 0x04, 0x04, 0x60, 0x80, 0xA0
188 };
189 u8 aid = aids[ctx->id >> 5];
190 u8 cfg = 0x3d;
191 u8 clk_con = 0xc8;
192 u8 int_con = 0x08;
193 u8 bictl_con = 0x48;
194 u8 em_clk1_con = 0xff;
195 u8 em_clk2_con = 0xff;
196 u8 em_int_con = 0xc8;
197
198 if (ctx->flip_vertical) {
199 /* GTCON */
200 cfg &= ~(PANELCTL_GTCON_MASK);
201 cfg |= (PANELCTL_GTCON_110);
202 }
203
204 if (ctx->flip_horizontal) {
205 /* SS */
206 cfg &= ~(PANELCTL_SS_MASK);
207 cfg |= (PANELCTL_SS_1_800);
208 }
209
210 if (ctx->flip_horizontal || ctx->flip_vertical) {
211 /* CLK1,2_CON */
212 clk_con &= ~(PANELCTL_CLK1_CON_MASK |
213 PANELCTL_CLK2_CON_MASK);
214 clk_con |= (PANELCTL_CLK1_000 | PANELCTL_CLK2_001);
215
216 /* INT1,2_CON */
217 int_con &= ~(PANELCTL_INT1_CON_MASK |
218 PANELCTL_INT2_CON_MASK);
219 int_con |= (PANELCTL_INT1_000 | PANELCTL_INT2_001);
220
221 /* BICTL,B_CON */
222 bictl_con &= ~(PANELCTL_BICTL_CON_MASK |
223 PANELCTL_BICTLB_CON_MASK);
224 bictl_con |= (PANELCTL_BICTL_000 |
225 PANELCTL_BICTLB_001);
226
227 /* EM_CLK1,1B_CON */
228 em_clk1_con &= ~(PANELCTL_EM_CLK1_CON_MASK |
229 PANELCTL_EM_CLK1B_CON_MASK);
230 em_clk1_con |= (PANELCTL_EM_CLK1_110 |
231 PANELCTL_EM_CLK1B_110);
232
233 /* EM_CLK2,2B_CON */
234 em_clk2_con &= ~(PANELCTL_EM_CLK2_CON_MASK |
235 PANELCTL_EM_CLK2B_CON_MASK);
236 em_clk2_con |= (PANELCTL_EM_CLK2_110 |
237 PANELCTL_EM_CLK2B_110);
238
239 /* EM_INT1,2_CON */
240 em_int_con &= ~(PANELCTL_EM_INT1_CON_MASK |
241 PANELCTL_EM_INT2_CON_MASK);
242 em_int_con |= (PANELCTL_EM_INT1_000 |
243 PANELCTL_EM_INT2_001);
244 }
245
246 s6e8aa0_dcs_write_seq(ctx,
247 0xf8, cfg, 0x35, 0x00, 0x00, 0x00, 0x93, 0x00,
248 0x3c, 0x78, 0x08, 0x27, 0x7d, 0x3f, 0x00, 0x00,
249 0x00, 0x20, aid, 0x08, 0x6e, 0x00, 0x00, 0x00,
250 0x02, 0x07, 0x07, 0x23, 0x23, 0xc0, clk_con, int_con,
251 bictl_con, 0xc1, 0x00, 0xc1, em_clk1_con, em_clk2_con,
252 em_int_con);
253}
254
255static void s6e8aa0_panel_cond_set(struct s6e8aa0 *ctx)
256{
257 if (ctx->version < 142)
258 s6e8aa0_dcs_write_seq_static(ctx,
259 0xf8, 0x19, 0x35, 0x00, 0x00, 0x00, 0x94, 0x00,
260 0x3c, 0x78, 0x10, 0x27, 0x08, 0x6e, 0x00, 0x00,
261 0x00, 0x00, 0x04, 0x08, 0x6e, 0x00, 0x00, 0x00,
262 0x00, 0x07, 0x07, 0x23, 0x6e, 0xc0, 0xc1, 0x01,
263 0x81, 0xc1, 0x00, 0xc3, 0xf6, 0xf6, 0xc1
264 );
265 else
266 s6e8aa0_panel_cond_set_v142(ctx);
267}
268
269static void s6e8aa0_display_condition_set(struct s6e8aa0 *ctx)
270{
271 s6e8aa0_dcs_write_seq_static(ctx, 0xf2, 0x80, 0x03, 0x0d);
272}
273
274static void s6e8aa0_etc_source_control(struct s6e8aa0 *ctx)
275{
276 s6e8aa0_dcs_write_seq_static(ctx, 0xf6, 0x00, 0x02, 0x00);
277}
278
279static void s6e8aa0_etc_pentile_control(struct s6e8aa0 *ctx)
280{
281 static const u8 pent32[] = {
282 0xb6, 0x0c, 0x02, 0x03, 0x32, 0xc0, 0x44, 0x44, 0xc0, 0x00
283 };
284
285 static const u8 pent142[] = {
286 0xb6, 0x0c, 0x02, 0x03, 0x32, 0xff, 0x44, 0x44, 0xc0, 0x00
287 };
288
289 if (ctx->version < 142)
290 s6e8aa0_dcs_write(ctx, pent32, ARRAY_SIZE(pent32));
291 else
292 s6e8aa0_dcs_write(ctx, pent142, ARRAY_SIZE(pent142));
293}
294
295static void s6e8aa0_etc_power_control(struct s6e8aa0 *ctx)
296{
297 static const u8 pwr142[] = {
298 0xf4, 0xcf, 0x0a, 0x12, 0x10, 0x1e, 0x33, 0x02
299 };
300
301 static const u8 pwr32[] = {
302 0xf4, 0xcf, 0x0a, 0x15, 0x10, 0x19, 0x33, 0x02
303 };
304
305 if (ctx->version < 142)
306 s6e8aa0_dcs_write(ctx, pwr32, ARRAY_SIZE(pwr32));
307 else
308 s6e8aa0_dcs_write(ctx, pwr142, ARRAY_SIZE(pwr142));
309}
310
311static void s6e8aa0_etc_elvss_control(struct s6e8aa0 *ctx)
312{
313 u8 id = ctx->id ? 0 : 0x95;
314
315 s6e8aa0_dcs_write_seq(ctx, 0xb1, 0x04, id);
316}
317
318static void s6e8aa0_elvss_nvm_set_v142(struct s6e8aa0 *ctx)
319{
320 u8 br;
321
322 switch (ctx->brightness) {
323 case 0 ... 6: /* 30cd ~ 100cd */
324 br = 0xdf;
325 break;
326 case 7 ... 11: /* 120cd ~ 150cd */
327 br = 0xdd;
328 break;
329 case 12 ... 15: /* 180cd ~ 210cd */
330 default:
331 br = 0xd9;
332 break;
333 case 16 ... 24: /* 240cd ~ 300cd */
334 br = 0xd0;
335 break;
336 }
337
338 s6e8aa0_dcs_write_seq(ctx, 0xd9, 0x14, 0x40, 0x0c, 0xcb, 0xce, 0x6e,
339 0xc4, 0x0f, 0x40, 0x41, br, 0x00, 0x60, 0x19);
340}
341
342static void s6e8aa0_elvss_nvm_set(struct s6e8aa0 *ctx)
343{
344 if (ctx->version < 142)
345 s6e8aa0_dcs_write_seq_static(ctx,
346 0xd9, 0x14, 0x40, 0x0c, 0xcb, 0xce, 0x6e, 0xc4, 0x07,
347 0x40, 0x41, 0xc1, 0x00, 0x60, 0x19);
348 else
349 s6e8aa0_elvss_nvm_set_v142(ctx);
350};
351
352static void s6e8aa0_apply_level_2_key(struct s6e8aa0 *ctx)
353{
354 s6e8aa0_dcs_write_seq_static(ctx, 0xfc, 0x5a, 0x5a);
355}
356
357static const s6e8aa0_gamma_table s6e8aa0_gamma_tables_v142[GAMMA_LEVEL_NUM] = {
358 {
359 0xfa, 0x01, 0x71, 0x31, 0x7b, 0x62, 0x55, 0x55,
360 0xaf, 0xb1, 0xb1, 0xbd, 0xce, 0xb7, 0x9a, 0xb1,
361 0x90, 0xb2, 0xc4, 0xae, 0x00, 0x60, 0x00, 0x40,
362 0x00, 0x70,
363 }, {
364 0xfa, 0x01, 0x71, 0x31, 0x7b, 0x74, 0x68, 0x69,
365 0xb8, 0xc1, 0xb7, 0xbd, 0xcd, 0xb8, 0x93, 0xab,
366 0x88, 0xb4, 0xc4, 0xb1, 0x00, 0x6b, 0x00, 0x4d,
367 0x00, 0x7d,
368 }, {
369 0xfa, 0x01, 0x71, 0x31, 0x7b, 0x95, 0x8a, 0x89,
370 0xb4, 0xc6, 0xb2, 0xc5, 0xd2, 0xbf, 0x90, 0xa8,
371 0x85, 0xb5, 0xc4, 0xb3, 0x00, 0x7b, 0x00, 0x5d,
372 0x00, 0x8f,
373 }, {
374 0xfa, 0x01, 0x71, 0x31, 0x7b, 0x9f, 0x98, 0x92,
375 0xb3, 0xc4, 0xb0, 0xbc, 0xcc, 0xb4, 0x91, 0xa6,
376 0x87, 0xb5, 0xc5, 0xb4, 0x00, 0x87, 0x00, 0x6a,
377 0x00, 0x9e,
378 }, {
379 0xfa, 0x01, 0x71, 0x31, 0x7b, 0x99, 0x93, 0x8b,
380 0xb2, 0xc2, 0xb0, 0xbd, 0xce, 0xb4, 0x90, 0xa6,
381 0x87, 0xb3, 0xc3, 0xb2, 0x00, 0x8d, 0x00, 0x70,
382 0x00, 0xa4,
383 }, {
384 0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa7, 0xa5, 0x99,
385 0xb2, 0xc2, 0xb0, 0xbb, 0xcd, 0xb1, 0x93, 0xa7,
386 0x8a, 0xb2, 0xc1, 0xb0, 0x00, 0x92, 0x00, 0x75,
387 0x00, 0xaa,
388 }, {
389 0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa0, 0xa0, 0x93,
390 0xb6, 0xc4, 0xb4, 0xb5, 0xc8, 0xaa, 0x94, 0xa9,
391 0x8c, 0xb2, 0xc0, 0xb0, 0x00, 0x97, 0x00, 0x7a,
392 0x00, 0xaf,
393 }, {
394 0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa3, 0xa7, 0x96,
395 0xb3, 0xc2, 0xb0, 0xba, 0xcb, 0xb0, 0x94, 0xa8,
396 0x8c, 0xb0, 0xbf, 0xaf, 0x00, 0x9f, 0x00, 0x83,
397 0x00, 0xb9,
398 }, {
399 0xfa, 0x01, 0x71, 0x31, 0x7b, 0x9d, 0xa2, 0x90,
400 0xb6, 0xc5, 0xb3, 0xb8, 0xc9, 0xae, 0x94, 0xa8,
401 0x8d, 0xaf, 0xbd, 0xad, 0x00, 0xa4, 0x00, 0x88,
402 0x00, 0xbf,
403 }, {
404 0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa6, 0xac, 0x97,
405 0xb4, 0xc4, 0xb1, 0xbb, 0xcb, 0xb2, 0x93, 0xa7,
406 0x8d, 0xae, 0xbc, 0xad, 0x00, 0xa7, 0x00, 0x8c,
407 0x00, 0xc3,
408 }, {
409 0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa2, 0xa9, 0x93,
410 0xb6, 0xc5, 0xb2, 0xba, 0xc9, 0xb0, 0x93, 0xa7,
411 0x8d, 0xae, 0xbb, 0xac, 0x00, 0xab, 0x00, 0x90,
412 0x00, 0xc8,
413 }, {
414 0xfa, 0x01, 0x71, 0x31, 0x7b, 0x9e, 0xa6, 0x8f,
415 0xb7, 0xc6, 0xb3, 0xb8, 0xc8, 0xb0, 0x93, 0xa6,
416 0x8c, 0xae, 0xbb, 0xad, 0x00, 0xae, 0x00, 0x93,
417 0x00, 0xcc,
418 }, {
419 0xfa, 0x01, 0x71, 0x31, 0x7b, 0xab, 0xb4, 0x9c,
420 0xb3, 0xc3, 0xaf, 0xb7, 0xc7, 0xaf, 0x93, 0xa6,
421 0x8c, 0xaf, 0xbc, 0xad, 0x00, 0xb1, 0x00, 0x97,
422 0x00, 0xcf,
423 }, {
424 0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa6, 0xb1, 0x98,
425 0xb1, 0xc2, 0xab, 0xba, 0xc9, 0xb2, 0x93, 0xa6,
426 0x8d, 0xae, 0xba, 0xab, 0x00, 0xb5, 0x00, 0x9b,
427 0x00, 0xd4,
428 }, {
429 0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa3, 0xae, 0x94,
430 0xb2, 0xc3, 0xac, 0xbb, 0xca, 0xb4, 0x91, 0xa4,
431 0x8a, 0xae, 0xba, 0xac, 0x00, 0xb8, 0x00, 0x9e,
432 0x00, 0xd8,
433 }, {
434 0xfa, 0x01, 0x71, 0x31, 0x7b, 0xab, 0xb7, 0x9c,
435 0xae, 0xc0, 0xa9, 0xba, 0xc9, 0xb3, 0x92, 0xa5,
436 0x8b, 0xad, 0xb9, 0xab, 0x00, 0xbb, 0x00, 0xa1,
437 0x00, 0xdc,
438 }, {
439 0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa7, 0xb4, 0x97,
440 0xb0, 0xc1, 0xaa, 0xb9, 0xc8, 0xb2, 0x92, 0xa5,
441 0x8c, 0xae, 0xb9, 0xab, 0x00, 0xbe, 0x00, 0xa4,
442 0x00, 0xdf,
443 }, {
444 0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa3, 0xb0, 0x94,
445 0xb0, 0xc2, 0xab, 0xbb, 0xc9, 0xb3, 0x91, 0xa4,
446 0x8b, 0xad, 0xb8, 0xaa, 0x00, 0xc1, 0x00, 0xa8,
447 0x00, 0xe2,
448 }, {
449 0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa3, 0xb0, 0x94,
450 0xae, 0xbf, 0xa8, 0xb9, 0xc8, 0xb3, 0x92, 0xa4,
451 0x8b, 0xad, 0xb7, 0xa9, 0x00, 0xc4, 0x00, 0xab,
452 0x00, 0xe6,
453 }, {
454 0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa7, 0xb6, 0x98,
455 0xaf, 0xc0, 0xa8, 0xb8, 0xc7, 0xb2, 0x93, 0xa5,
456 0x8d, 0xad, 0xb7, 0xa9, 0x00, 0xc7, 0x00, 0xae,
457 0x00, 0xe9,
458 }, {
459 0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa4, 0xb3, 0x95,
460 0xaf, 0xc1, 0xa9, 0xb9, 0xc8, 0xb3, 0x92, 0xa4,
461 0x8b, 0xad, 0xb7, 0xaa, 0x00, 0xc9, 0x00, 0xb0,
462 0x00, 0xec,
463 }, {
464 0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa4, 0xb3, 0x95,
465 0xac, 0xbe, 0xa6, 0xbb, 0xc9, 0xb4, 0x90, 0xa3,
466 0x8a, 0xad, 0xb7, 0xa9, 0x00, 0xcc, 0x00, 0xb4,
467 0x00, 0xf0,
468 }, {
469 0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa0, 0xb0, 0x91,
470 0xae, 0xc0, 0xa6, 0xba, 0xc8, 0xb4, 0x91, 0xa4,
471 0x8b, 0xad, 0xb7, 0xa9, 0x00, 0xcf, 0x00, 0xb7,
472 0x00, 0xf3,
473 }, {
474 0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa7, 0xb8, 0x98,
475 0xab, 0xbd, 0xa4, 0xbb, 0xc9, 0xb5, 0x91, 0xa3,
476 0x8b, 0xac, 0xb6, 0xa8, 0x00, 0xd1, 0x00, 0xb9,
477 0x00, 0xf6,
478 }, {
479 0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa4, 0xb5, 0x95,
480 0xa9, 0xbc, 0xa1, 0xbb, 0xc9, 0xb5, 0x91, 0xa3,
481 0x8a, 0xad, 0xb6, 0xa8, 0x00, 0xd6, 0x00, 0xbf,
482 0x00, 0xfc,
483 },
484};
485
486static const s6e8aa0_gamma_table s6e8aa0_gamma_tables_v96[GAMMA_LEVEL_NUM] = {
487 {
488 0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xff, 0x00, 0xff,
489 0xdf, 0x1f, 0xd7, 0xdc, 0xb7, 0xe1, 0xc0, 0xaf,
490 0xc4, 0xd2, 0xd0, 0xcf, 0x00, 0x4d, 0x00, 0x40,
491 0x00, 0x5f,
492 }, {
493 0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xff, 0x00, 0xff,
494 0xd5, 0x35, 0xcf, 0xdc, 0xc1, 0xe1, 0xbf, 0xb3,
495 0xc1, 0xd2, 0xd1, 0xce, 0x00, 0x53, 0x00, 0x46,
496 0x00, 0x67,
497 }, {
498 0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xff, 0x00, 0xff,
499 0xd2, 0x64, 0xcf, 0xdb, 0xc6, 0xe1, 0xbd, 0xb3,
500 0xbd, 0xd2, 0xd2, 0xce, 0x00, 0x59, 0x00, 0x4b,
501 0x00, 0x6e,
502 }, {
503 0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xff, 0x00, 0xff,
504 0xd0, 0x7c, 0xcf, 0xdb, 0xc9, 0xe0, 0xbc, 0xb4,
505 0xbb, 0xcf, 0xd1, 0xcc, 0x00, 0x5f, 0x00, 0x50,
506 0x00, 0x75,
507 }, {
508 0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xff, 0x00, 0xff,
509 0xd0, 0x8e, 0xd1, 0xdb, 0xcc, 0xdf, 0xbb, 0xb6,
510 0xb9, 0xd0, 0xd1, 0xcd, 0x00, 0x63, 0x00, 0x54,
511 0x00, 0x7a,
512 }, {
513 0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xff, 0x00, 0xff,
514 0xd1, 0x9e, 0xd5, 0xda, 0xcd, 0xdd, 0xbb, 0xb7,
515 0xb9, 0xce, 0xce, 0xc9, 0x00, 0x68, 0x00, 0x59,
516 0x00, 0x81,
517 }, {
518 0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xff, 0x00, 0xff,
519 0xd0, 0xa5, 0xd6, 0xda, 0xcf, 0xdd, 0xbb, 0xb7,
520 0xb8, 0xcc, 0xcd, 0xc7, 0x00, 0x6c, 0x00, 0x5c,
521 0x00, 0x86,
522 }, {
523 0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xff, 0x1f, 0xfe,
524 0xd0, 0xae, 0xd7, 0xd9, 0xd0, 0xdb, 0xb9, 0xb6,
525 0xb5, 0xca, 0xcc, 0xc5, 0x00, 0x74, 0x00, 0x63,
526 0x00, 0x90,
527 }, {
528 0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xff, 0x1f, 0xf9,
529 0xcf, 0xb0, 0xd6, 0xd9, 0xd1, 0xdb, 0xb9, 0xb6,
530 0xb4, 0xca, 0xcb, 0xc5, 0x00, 0x77, 0x00, 0x66,
531 0x00, 0x94,
532 }, {
533 0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xff, 0x1f, 0xf7,
534 0xcf, 0xb3, 0xd7, 0xd8, 0xd1, 0xd9, 0xb7, 0xb6,
535 0xb3, 0xc9, 0xca, 0xc3, 0x00, 0x7b, 0x00, 0x69,
536 0x00, 0x99,
537
538 }, {
539 0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xfd, 0x2f, 0xf7,
540 0xdf, 0xb5, 0xd6, 0xd8, 0xd1, 0xd8, 0xb6, 0xb5,
541 0xb2, 0xca, 0xcb, 0xc4, 0x00, 0x7e, 0x00, 0x6c,
542 0x00, 0x9d,
543 }, {
544 0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xfa, 0x2f, 0xf5,
545 0xce, 0xb6, 0xd5, 0xd7, 0xd2, 0xd8, 0xb6, 0xb4,
546 0xb0, 0xc7, 0xc9, 0xc1, 0x00, 0x84, 0x00, 0x71,
547 0x00, 0xa5,
548 }, {
549 0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xf7, 0x2f, 0xf2,
550 0xce, 0xb9, 0xd5, 0xd8, 0xd2, 0xd8, 0xb4, 0xb4,
551 0xaf, 0xc7, 0xc9, 0xc1, 0x00, 0x87, 0x00, 0x73,
552 0x00, 0xa8,
553 }, {
554 0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xf5, 0x2f, 0xf0,
555 0xdf, 0xba, 0xd5, 0xd7, 0xd2, 0xd7, 0xb4, 0xb4,
556 0xaf, 0xc5, 0xc7, 0xbf, 0x00, 0x8a, 0x00, 0x76,
557 0x00, 0xac,
558 }, {
559 0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xf2, 0x2f, 0xed,
560 0xcE, 0xbb, 0xd4, 0xd6, 0xd2, 0xd6, 0xb5, 0xb4,
561 0xaF, 0xc5, 0xc7, 0xbf, 0x00, 0x8c, 0x00, 0x78,
562 0x00, 0xaf,
563 }, {
564 0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xef, 0x2f, 0xeb,
565 0xcd, 0xbb, 0xd2, 0xd7, 0xd3, 0xd6, 0xb3, 0xb4,
566 0xae, 0xc5, 0xc6, 0xbe, 0x00, 0x91, 0x00, 0x7d,
567 0x00, 0xb6,
568 }, {
569 0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xee, 0x2f, 0xea,
570 0xce, 0xbd, 0xd4, 0xd6, 0xd2, 0xd5, 0xb2, 0xb3,
571 0xad, 0xc3, 0xc4, 0xbb, 0x00, 0x94, 0x00, 0x7f,
572 0x00, 0xba,
573 }, {
574 0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xec, 0x2f, 0xe8,
575 0xce, 0xbe, 0xd3, 0xd6, 0xd3, 0xd5, 0xb2, 0xb2,
576 0xac, 0xc3, 0xc5, 0xbc, 0x00, 0x96, 0x00, 0x81,
577 0x00, 0xbd,
578 }, {
579 0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xeb, 0x2f, 0xe7,
580 0xce, 0xbf, 0xd3, 0xd6, 0xd2, 0xd5, 0xb1, 0xb2,
581 0xab, 0xc2, 0xc4, 0xbb, 0x00, 0x99, 0x00, 0x83,
582 0x00, 0xc0,
583 }, {
584 0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xef, 0x5f, 0xe9,
585 0xca, 0xbf, 0xd3, 0xd5, 0xd2, 0xd4, 0xb2, 0xb2,
586 0xab, 0xc1, 0xc4, 0xba, 0x00, 0x9b, 0x00, 0x85,
587 0x00, 0xc3,
588 }, {
589 0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xea, 0x5f, 0xe8,
590 0xee, 0xbf, 0xd2, 0xd5, 0xd2, 0xd4, 0xb1, 0xb2,
591 0xab, 0xc1, 0xc2, 0xb9, 0x00, 0x9D, 0x00, 0x87,
592 0x00, 0xc6,
593 }, {
594 0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xe9, 0x5f, 0xe7,
595 0xcd, 0xbf, 0xd2, 0xd6, 0xd2, 0xd4, 0xb1, 0xb2,
596 0xab, 0xbe, 0xc0, 0xb7, 0x00, 0xa1, 0x00, 0x8a,
597 0x00, 0xca,
598 }, {
599 0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xe8, 0x61, 0xe6,
600 0xcd, 0xbf, 0xd1, 0xd6, 0xd3, 0xd4, 0xaf, 0xb0,
601 0xa9, 0xbe, 0xc1, 0xb7, 0x00, 0xa3, 0x00, 0x8b,
602 0x00, 0xce,
603 }, {
604 0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xe8, 0x62, 0xe5,
605 0xcc, 0xc0, 0xd0, 0xd6, 0xd2, 0xd4, 0xaf, 0xb1,
606 0xa9, 0xbd, 0xc0, 0xb6, 0x00, 0xa5, 0x00, 0x8d,
607 0x00, 0xd0,
608 }, {
609 0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xe7, 0x7f, 0xe3,
610 0xcc, 0xc1, 0xd0, 0xd5, 0xd3, 0xd3, 0xae, 0xaf,
611 0xa8, 0xbe, 0xc0, 0xb7, 0x00, 0xa8, 0x00, 0x90,
612 0x00, 0xd3,
613 }
614};
615
616static const s6e8aa0_gamma_table s6e8aa0_gamma_tables_v32[GAMMA_LEVEL_NUM] = {
617 {
618 0xfa, 0x01, 0x43, 0x14, 0x45, 0x72, 0x5e, 0x6b,
619 0xa1, 0xa7, 0x9a, 0xb4, 0xcb, 0xb8, 0x92, 0xac,
620 0x97, 0xb4, 0xc3, 0xb5, 0x00, 0x4e, 0x00, 0x37,
621 0x00, 0x58,
622 }, {
623 0xfa, 0x01, 0x43, 0x14, 0x45, 0x85, 0x71, 0x7d,
624 0xa6, 0xb6, 0xa1, 0xb5, 0xca, 0xba, 0x93, 0xac,
625 0x98, 0xb2, 0xc0, 0xaf, 0x00, 0x59, 0x00, 0x43,
626 0x00, 0x64,
627 }, {
628 0xfa, 0x01, 0x43, 0x14, 0x45, 0xa4, 0x94, 0x9e,
629 0xa0, 0xbb, 0x9c, 0xc3, 0xd2, 0xc6, 0x93, 0xaa,
630 0x95, 0xb7, 0xc2, 0xb4, 0x00, 0x65, 0x00, 0x50,
631 0x00, 0x74,
632 }, {
633 0xfa, 0x01, 0x43, 0x14, 0x45, 0xad, 0xa1, 0xa6,
634 0xa0, 0xb9, 0x9b, 0xc3, 0xd1, 0xc8, 0x90, 0xa6,
635 0x90, 0xbb, 0xc3, 0xb7, 0x00, 0x6f, 0x00, 0x5b,
636 0x00, 0x80,
637 }, {
638 0xfa, 0x01, 0x43, 0x14, 0x45, 0xa6, 0x9d, 0x9f,
639 0x9f, 0xb8, 0x9a, 0xc7, 0xd5, 0xcc, 0x90, 0xa5,
640 0x8f, 0xb8, 0xc1, 0xb6, 0x00, 0x74, 0x00, 0x60,
641 0x00, 0x85,
642 }, {
643 0xfa, 0x01, 0x43, 0x14, 0x45, 0xb3, 0xae, 0xae,
644 0x9e, 0xb7, 0x9a, 0xc8, 0xd6, 0xce, 0x91, 0xa6,
645 0x90, 0xb6, 0xc0, 0xb3, 0x00, 0x78, 0x00, 0x65,
646 0x00, 0x8a,
647 }, {
648 0xfa, 0x01, 0x43, 0x14, 0x45, 0xad, 0xa9, 0xa8,
649 0xa3, 0xb9, 0x9e, 0xc4, 0xd3, 0xcb, 0x94, 0xa6,
650 0x90, 0xb6, 0xbf, 0xb3, 0x00, 0x7c, 0x00, 0x69,
651 0x00, 0x8e,
652 }, {
653 0xfa, 0x01, 0x43, 0x14, 0x45, 0xaf, 0xaf, 0xa9,
654 0xa5, 0xbc, 0xa2, 0xc7, 0xd5, 0xcd, 0x93, 0xa5,
655 0x8f, 0xb4, 0xbd, 0xb1, 0x00, 0x83, 0x00, 0x70,
656 0x00, 0x96,
657 }, {
658 0xfa, 0x01, 0x43, 0x14, 0x45, 0xa9, 0xab, 0xa3,
659 0xaa, 0xbf, 0xa7, 0xc5, 0xd3, 0xcb, 0x93, 0xa5,
660 0x8f, 0xb2, 0xbb, 0xb0, 0x00, 0x86, 0x00, 0x74,
661 0x00, 0x9b,
662 }, {
663 0xfa, 0x01, 0x43, 0x14, 0x45, 0xb1, 0xb5, 0xab,
664 0xab, 0xc0, 0xa9, 0xc7, 0xd4, 0xcc, 0x94, 0xa4,
665 0x8f, 0xb1, 0xbb, 0xaf, 0x00, 0x8a, 0x00, 0x77,
666 0x00, 0x9e,
667 }, {
668 0xfa, 0x01, 0x43, 0x14, 0x45, 0xad, 0xb2, 0xa7,
669 0xae, 0xc2, 0xab, 0xc5, 0xd3, 0xca, 0x93, 0xa4,
670 0x8f, 0xb1, 0xba, 0xae, 0x00, 0x8d, 0x00, 0x7b,
671 0x00, 0xa2,
672 }, {
673 0xfa, 0x01, 0x43, 0x14, 0x45, 0xa9, 0xaf, 0xa3,
674 0xb0, 0xc3, 0xae, 0xc4, 0xd1, 0xc8, 0x93, 0xa4,
675 0x8f, 0xb1, 0xba, 0xaf, 0x00, 0x8f, 0x00, 0x7d,
676 0x00, 0xa5,
677 }, {
678 0xfa, 0x01, 0x43, 0x14, 0x45, 0xb4, 0xbd, 0xaf,
679 0xae, 0xc1, 0xab, 0xc2, 0xd0, 0xc6, 0x94, 0xa4,
680 0x8f, 0xb1, 0xba, 0xaf, 0x00, 0x92, 0x00, 0x80,
681 0x00, 0xa8,
682 }, {
683 0xfa, 0x01, 0x43, 0x14, 0x45, 0xb0, 0xb9, 0xac,
684 0xad, 0xc1, 0xab, 0xc4, 0xd1, 0xc7, 0x95, 0xa4,
685 0x90, 0xb0, 0xb9, 0xad, 0x00, 0x95, 0x00, 0x84,
686 0x00, 0xac,
687 }, {
688 0xfa, 0x01, 0x43, 0x14, 0x45, 0xad, 0xb6, 0xa7,
689 0xaf, 0xc2, 0xae, 0xc5, 0xd1, 0xc7, 0x93, 0xa3,
690 0x8e, 0xb0, 0xb9, 0xad, 0x00, 0x98, 0x00, 0x86,
691 0x00, 0xaf,
692 }, {
693 0xfa, 0x01, 0x43, 0x14, 0x45, 0xb4, 0xbf, 0xaf,
694 0xad, 0xc1, 0xab, 0xc3, 0xd0, 0xc6, 0x94, 0xa3,
695 0x8f, 0xaf, 0xb8, 0xac, 0x00, 0x9a, 0x00, 0x89,
696 0x00, 0xb2,
697 }, {
698 0xfa, 0x01, 0x43, 0x14, 0x45, 0xb0, 0xbc, 0xac,
699 0xaf, 0xc2, 0xad, 0xc2, 0xcf, 0xc4, 0x94, 0xa3,
700 0x90, 0xaf, 0xb8, 0xad, 0x00, 0x9c, 0x00, 0x8b,
701 0x00, 0xb5,
702 }, {
703 0xfa, 0x01, 0x43, 0x14, 0x45, 0xad, 0xb9, 0xa7,
704 0xb1, 0xc4, 0xaf, 0xc3, 0xcf, 0xc5, 0x94, 0xa3,
705 0x8f, 0xae, 0xb7, 0xac, 0x00, 0x9f, 0x00, 0x8e,
706 0x00, 0xb8,
707 }, {
708 0xfa, 0x01, 0x43, 0x14, 0x45, 0xad, 0xb9, 0xa7,
709 0xaf, 0xc2, 0xad, 0xc1, 0xce, 0xc3, 0x95, 0xa3,
710 0x90, 0xad, 0xb6, 0xab, 0x00, 0xa2, 0x00, 0x91,
711 0x00, 0xbb,
712 }, {
713 0xfa, 0x01, 0x43, 0x14, 0x45, 0xb1, 0xbe, 0xac,
714 0xb1, 0xc4, 0xaf, 0xc1, 0xcd, 0xc1, 0x95, 0xa4,
715 0x91, 0xad, 0xb6, 0xab, 0x00, 0xa4, 0x00, 0x93,
716 0x00, 0xbd,
717 }, {
718 0xfa, 0x01, 0x43, 0x14, 0x45, 0xad, 0xbb, 0xa8,
719 0xb3, 0xc5, 0xb2, 0xc1, 0xcd, 0xc2, 0x95, 0xa3,
720 0x90, 0xad, 0xb6, 0xab, 0x00, 0xa6, 0x00, 0x95,
721 0x00, 0xc0,
722 }, {
723 0xfa, 0x01, 0x43, 0x14, 0x45, 0xad, 0xbb, 0xa8,
724 0xb0, 0xc3, 0xaf, 0xc2, 0xce, 0xc2, 0x94, 0xa2,
725 0x90, 0xac, 0xb6, 0xab, 0x00, 0xa8, 0x00, 0x98,
726 0x00, 0xc3,
727 }, {
728 0xfa, 0x01, 0x43, 0x14, 0x45, 0xa9, 0xb8, 0xa5,
729 0xb3, 0xc5, 0xb2, 0xc1, 0xcc, 0xc0, 0x95, 0xa2,
730 0x90, 0xad, 0xb6, 0xab, 0x00, 0xaa, 0x00, 0x9a,
731 0x00, 0xc5,
732 }, {
733 0xfa, 0x01, 0x43, 0x14, 0x45, 0xb0, 0xc0, 0xac,
734 0xb0, 0xc3, 0xaf, 0xc1, 0xcd, 0xc1, 0x95, 0xa2,
735 0x90, 0xac, 0xb5, 0xa9, 0x00, 0xac, 0x00, 0x9c,
736 0x00, 0xc8,
737 }, {
738 0xfa, 0x01, 0x43, 0x14, 0x45, 0xad, 0xbd, 0xa8,
739 0xaf, 0xc2, 0xaf, 0xc1, 0xcc, 0xc0, 0x95, 0xa2,
740 0x90, 0xac, 0xb5, 0xaa, 0x00, 0xb1, 0x00, 0xa1,
741 0x00, 0xcc,
742 },
743};
744
745static const struct s6e8aa0_variant s6e8aa0_variants[] = {
746 {
747 .version = 32,
748 .gamma_tables = s6e8aa0_gamma_tables_v32,
749 }, {
750 .version = 96,
751 .gamma_tables = s6e8aa0_gamma_tables_v96,
752 }, {
753 .version = 142,
754 .gamma_tables = s6e8aa0_gamma_tables_v142,
755 }, {
756 .version = 210,
757 .gamma_tables = s6e8aa0_gamma_tables_v142,
758 }
759};
760
761static void s6e8aa0_brightness_set(struct s6e8aa0 *ctx)
762{
763 const u8 *gamma;
764
765 if (ctx->error)
766 return;
767
768 gamma = ctx->variant->gamma_tables[ctx->brightness];
769
770 if (ctx->version >= 142)
771 s6e8aa0_elvss_nvm_set(ctx);
772
773 s6e8aa0_dcs_write(ctx, gamma, GAMMA_TABLE_LEN);
774
775 /* update gamma table. */
776 s6e8aa0_dcs_write_seq_static(ctx, 0xf7, 0x03);
777}
778
779static void s6e8aa0_panel_init(struct s6e8aa0 *ctx)
780{
781 s6e8aa0_apply_level_1_key(ctx);
782 s6e8aa0_apply_level_2_key(ctx);
783 msleep(20);
784
785 s6e8aa0_dcs_write_seq_static(ctx, MIPI_DCS_EXIT_SLEEP_MODE);
786 msleep(40);
787
788 s6e8aa0_panel_cond_set(ctx);
789 s6e8aa0_display_condition_set(ctx);
790 s6e8aa0_brightness_set(ctx);
791 s6e8aa0_etc_source_control(ctx);
792 s6e8aa0_etc_pentile_control(ctx);
793 s6e8aa0_elvss_nvm_set(ctx);
794 s6e8aa0_etc_power_control(ctx);
795 s6e8aa0_etc_elvss_control(ctx);
796 msleep(ctx->init_delay);
797}
798
799static void s6e8aa0_set_maximum_return_packet_size(struct s6e8aa0 *ctx,
800 int size)
801{
802 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
803 const struct mipi_dsi_host_ops *ops = dsi->host->ops;
804 u8 buf[] = {size, 0};
805 struct mipi_dsi_msg msg = {
806 .channel = dsi->channel,
807 .type = MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE,
808 .tx_len = sizeof(buf),
809 .tx_buf = buf
810 };
811 int ret;
812
813 if (ctx->error < 0)
814 return;
815
816 if (!ops || !ops->transfer)
817 ret = -EIO;
818 else
819 ret = ops->transfer(dsi->host, &msg);
820
821 if (ret < 0) {
822 dev_err(ctx->dev,
823 "error %d setting maximum return packet size to %d\n",
824 ret, size);
825 ctx->error = ret;
826 }
827}
828
829static void s6e8aa0_read_mtp_id(struct s6e8aa0 *ctx)
830{
831 u8 id[3];
832 int ret, i;
833
834 ret = s6e8aa0_dcs_read(ctx, 0xd1, id, ARRAY_SIZE(id));
835 if (ret < ARRAY_SIZE(id) || id[0] == 0x00) {
836 dev_err(ctx->dev, "read id failed\n");
837 ctx->error = -EIO;
838 return;
839 }
840
841 dev_info(ctx->dev, "ID: 0x%2x, 0x%2x, 0x%2x\n", id[0], id[1], id[2]);
842
843 for (i = 0; i < ARRAY_SIZE(s6e8aa0_variants); ++i) {
844 if (id[1] == s6e8aa0_variants[i].version)
845 break;
846 }
847 if (i >= ARRAY_SIZE(s6e8aa0_variants)) {
848 dev_err(ctx->dev, "unsupported display version %d\n", id[1]);
849 ctx->error = -EINVAL;
850 }
851
852 ctx->variant = &s6e8aa0_variants[i];
853 ctx->version = id[1];
854 ctx->id = id[2];
855}
856
857static void s6e8aa0_set_sequence(struct s6e8aa0 *ctx)
858{
859 s6e8aa0_set_maximum_return_packet_size(ctx, 3);
860 s6e8aa0_read_mtp_id(ctx);
861 s6e8aa0_panel_init(ctx);
862 s6e8aa0_dcs_write_seq_static(ctx, MIPI_DCS_SET_DISPLAY_ON);
863}
864
865static int s6e8aa0_power_on(struct s6e8aa0 *ctx)
866{
867 int ret;
868
869 ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
870 if (ret < 0)
871 return ret;
872
873 msleep(ctx->power_on_delay);
874
875 gpiod_set_value(ctx->reset_gpio, 0);
876 usleep_range(10000, 11000);
877 gpiod_set_value(ctx->reset_gpio, 1);
878
879 msleep(ctx->reset_delay);
880
881 return 0;
882}
883
884static int s6e8aa0_power_off(struct s6e8aa0 *ctx)
885{
886 return regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
887}
888
889static int s6e8aa0_disable(struct drm_panel *panel)
890{
891 struct s6e8aa0 *ctx = panel_to_s6e8aa0(panel);
892
893 s6e8aa0_dcs_write_seq_static(ctx, MIPI_DCS_ENTER_SLEEP_MODE);
894 s6e8aa0_dcs_write_seq_static(ctx, MIPI_DCS_SET_DISPLAY_OFF);
895 msleep(40);
896
897 s6e8aa0_clear_error(ctx);
898
899 return s6e8aa0_power_off(ctx);
900}
901
902static int s6e8aa0_enable(struct drm_panel *panel)
903{
904 struct s6e8aa0 *ctx = panel_to_s6e8aa0(panel);
905 int ret;
906
907 ret = s6e8aa0_power_on(ctx);
908 if (ret < 0)
909 return ret;
910
911 s6e8aa0_set_sequence(ctx);
912 ret = ctx->error;
913
914 if (ret < 0)
915 s6e8aa0_disable(panel);
916
917 return ret;
918}
919
920static int s6e8aa0_get_modes(struct drm_panel *panel)
921{
922 struct drm_connector *connector = panel->connector;
923 struct s6e8aa0 *ctx = panel_to_s6e8aa0(panel);
924 struct drm_display_mode *mode;
925
926 mode = drm_mode_create(connector->dev);
927 if (!mode) {
928 DRM_ERROR("failed to create a new display mode\n");
929 return 0;
930 }
931
932 drm_display_mode_from_videomode(&ctx->vm, mode);
933 mode->width_mm = ctx->width_mm;
934 mode->height_mm = ctx->height_mm;
935 connector->display_info.width_mm = mode->width_mm;
936 connector->display_info.height_mm = mode->height_mm;
937
938 mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
939 drm_mode_probed_add(connector, mode);
940
941 return 1;
942}
943
944static const struct drm_panel_funcs s6e8aa0_drm_funcs = {
945 .disable = s6e8aa0_disable,
946 .enable = s6e8aa0_enable,
947 .get_modes = s6e8aa0_get_modes,
948};
949
950static int s6e8aa0_parse_dt(struct s6e8aa0 *ctx)
951{
952 struct device *dev = ctx->dev;
953 struct device_node *np = dev->of_node;
954 int ret;
955
956 ret = of_get_videomode(np, &ctx->vm, 0);
957 if (ret < 0)
958 return ret;
959
960 of_property_read_u32(np, "power-on-delay", &ctx->power_on_delay);
961 of_property_read_u32(np, "reset-delay", &ctx->reset_delay);
962 of_property_read_u32(np, "init-delay", &ctx->init_delay);
963 of_property_read_u32(np, "panel-width-mm", &ctx->width_mm);
964 of_property_read_u32(np, "panel-height-mm", &ctx->height_mm);
965
966 ctx->flip_horizontal = of_property_read_bool(np, "flip-horizontal");
967 ctx->flip_vertical = of_property_read_bool(np, "flip-vertical");
968
969 return 0;
970}
971
972static int s6e8aa0_probe(struct mipi_dsi_device *dsi)
973{
974 struct device *dev = &dsi->dev;
975 struct s6e8aa0 *ctx;
976 int ret;
977
978 ctx = devm_kzalloc(dev, sizeof(struct s6e8aa0), GFP_KERNEL);
979 if (!ctx)
980 return -ENOMEM;
981
982 mipi_dsi_set_drvdata(dsi, ctx);
983
984 ctx->dev = dev;
985
986 dsi->lanes = 4;
987 dsi->format = MIPI_DSI_FMT_RGB888;
988 dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST
989 | MIPI_DSI_MODE_VIDEO_HFP | MIPI_DSI_MODE_VIDEO_HBP
990 | MIPI_DSI_MODE_VIDEO_HSA | MIPI_DSI_MODE_EOT_PACKET
991 | MIPI_DSI_MODE_VSYNC_FLUSH | MIPI_DSI_MODE_VIDEO_AUTO_VERT;
992
993 ret = s6e8aa0_parse_dt(ctx);
994 if (ret < 0)
995 return ret;
996
997 ctx->supplies[0].supply = "vdd3";
998 ctx->supplies[1].supply = "vci";
999 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies),
1000 ctx->supplies);
1001 if (ret < 0) {
1002 dev_err(dev, "failed to get regulators: %d\n", ret);
1003 return ret;
1004 }
1005
1006 ctx->reset_gpio = devm_gpiod_get(dev, "reset");
1007 if (IS_ERR(ctx->reset_gpio)) {
1008 dev_err(dev, "cannot get reset-gpios %ld\n",
1009 PTR_ERR(ctx->reset_gpio));
1010 return PTR_ERR(ctx->reset_gpio);
1011 }
1012 ret = gpiod_direction_output(ctx->reset_gpio, 1);
1013 if (ret < 0) {
1014 dev_err(dev, "cannot configure reset-gpios %d\n", ret);
1015 return ret;
1016 }
1017
1018 ctx->brightness = GAMMA_LEVEL_NUM - 1;
1019
1020 drm_panel_init(&ctx->panel);
1021 ctx->panel.dev = dev;
1022 ctx->panel.funcs = &s6e8aa0_drm_funcs;
1023
1024 ret = drm_panel_add(&ctx->panel);
1025 if (ret < 0)
1026 return ret;
1027
1028 ret = mipi_dsi_attach(dsi);
1029 if (ret < 0)
1030 drm_panel_remove(&ctx->panel);
1031
1032 return ret;
1033}
1034
1035static int s6e8aa0_remove(struct mipi_dsi_device *dsi)
1036{
1037 struct s6e8aa0 *ctx = mipi_dsi_get_drvdata(dsi);
1038
1039 mipi_dsi_detach(dsi);
1040 drm_panel_remove(&ctx->panel);
1041
1042 return 0;
1043}
1044
1045static struct of_device_id s6e8aa0_of_match[] = {
1046 { .compatible = "samsung,s6e8aa0" },
1047 { }
1048};
1049MODULE_DEVICE_TABLE(of, s6e8aa0_of_match);
1050
1051static struct mipi_dsi_driver s6e8aa0_driver = {
1052 .probe = s6e8aa0_probe,
1053 .remove = s6e8aa0_remove,
1054 .driver = {
1055 .name = "panel_s6e8aa0",
1056 .owner = THIS_MODULE,
1057 .of_match_table = s6e8aa0_of_match,
1058 },
1059};
1060module_mipi_dsi_driver(s6e8aa0_driver);
1061
1062MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>");
1063MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
1064MODULE_AUTHOR("Joongmock Shin <jmock.shin@samsung.com>");
1065MODULE_AUTHOR("Eunchul Kim <chulspro.kim@samsung.com>");
1066MODULE_AUTHOR("Tomasz Figa <t.figa@samsung.com>");
1067MODULE_AUTHOR("Andrzej Hajda <a.hajda@samsung.com>");
1068MODULE_DESCRIPTION("MIPI-DSI based s6e8aa0 AMOLED LCD Panel Driver");
1069MODULE_LICENSE("GPL v2");
diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h
index d32628acdd90..7209df15a3cd 100644
--- a/include/drm/drm_mipi_dsi.h
+++ b/include/drm/drm_mipi_dsi.h
@@ -17,6 +17,11 @@
17struct mipi_dsi_host; 17struct mipi_dsi_host;
18struct mipi_dsi_device; 18struct mipi_dsi_device;
19 19
20/* request ACK from peripheral */
21#define MIPI_DSI_MSG_REQ_ACK BIT(0)
22/* use Low Power Mode to transmit message */
23#define MIPI_DSI_MSG_USE_LPM BIT(1)
24
20/** 25/**
21 * struct mipi_dsi_msg - read/write DSI buffer 26 * struct mipi_dsi_msg - read/write DSI buffer
22 * @channel: virtual channel id 27 * @channel: virtual channel id
@@ -29,6 +34,7 @@ struct mipi_dsi_device;
29struct mipi_dsi_msg { 34struct mipi_dsi_msg {
30 u8 channel; 35 u8 channel;
31 u8 type; 36 u8 type;
37 u16 flags;
32 38
33 size_t tx_len; 39 size_t tx_len;
34 const void *tx_buf; 40 const void *tx_buf;