diff options
author | Thierry Reding <treding@nvidia.com> | 2014-10-07 10:10:24 -0400 |
---|---|---|
committer | Thierry Reding <treding@nvidia.com> | 2014-11-13 10:12:28 -0500 |
commit | e94236cde4d519cdecd45e2435defba33abdc99f (patch) | |
tree | 637cd405102afcefa55f7a3bf195a3935709ac7c | |
parent | 3f6b406f7d716310c7a63648bbe6b2a4a30c3077 (diff) |
drm/tegra: dsi: Add ganged mode support
Implement ganged mode support for the Tegra DSI driver. The DSI host
controller to gang up with is specified via a phandle in the device tree
and the resolved DSI host controller used for the programming of the
ganged-mode registers.
Signed-off-by: Thierry Reding <treding@nvidia.com>
-rw-r--r-- | Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/dsi.c | 221 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/dsi.h | 1 |
3 files changed, 195 insertions, 29 deletions
diff --git a/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt b/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt index b48f4ef31d93..4c32ef0b7db8 100644 --- a/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt +++ b/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt | |||
@@ -191,6 +191,8 @@ of the following host1x client modules: | |||
191 | - nvidia,hpd-gpio: specifies a GPIO used for hotplug detection | 191 | - nvidia,hpd-gpio: specifies a GPIO used for hotplug detection |
192 | - nvidia,edid: supplies a binary EDID blob | 192 | - nvidia,edid: supplies a binary EDID blob |
193 | - nvidia,panel: phandle of a display panel | 193 | - nvidia,panel: phandle of a display panel |
194 | - nvidia,ganged-mode: contains a phandle to a second DSI controller to gang | ||
195 | up with in order to support up to 8 data lanes | ||
194 | 196 | ||
195 | - sor: serial output resource | 197 | - sor: serial output resource |
196 | 198 | ||
diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c index 46fcf62658cf..66816104ba72 100644 --- a/drivers/gpu/drm/tegra/dsi.c +++ b/drivers/gpu/drm/tegra/dsi.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/host1x.h> | 11 | #include <linux/host1x.h> |
12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
13 | #include <linux/of.h> | 13 | #include <linux/of.h> |
14 | #include <linux/of_platform.h> | ||
14 | #include <linux/platform_device.h> | 15 | #include <linux/platform_device.h> |
15 | #include <linux/reset.h> | 16 | #include <linux/reset.h> |
16 | 17 | ||
@@ -54,6 +55,10 @@ struct tegra_dsi { | |||
54 | 55 | ||
55 | unsigned int video_fifo_depth; | 56 | unsigned int video_fifo_depth; |
56 | unsigned int host_fifo_depth; | 57 | unsigned int host_fifo_depth; |
58 | |||
59 | /* for ganged-mode support */ | ||
60 | struct tegra_dsi *master; | ||
61 | struct tegra_dsi *slave; | ||
57 | }; | 62 | }; |
58 | 63 | ||
59 | static inline struct tegra_dsi * | 64 | static inline struct tegra_dsi * |
@@ -441,6 +446,18 @@ static int tegra_dsi_get_format(enum mipi_dsi_pixel_format format, | |||
441 | return 0; | 446 | return 0; |
442 | } | 447 | } |
443 | 448 | ||
449 | static void tegra_dsi_ganged_enable(struct tegra_dsi *dsi, unsigned int start, | ||
450 | unsigned int size) | ||
451 | { | ||
452 | u32 value; | ||
453 | |||
454 | tegra_dsi_writel(dsi, start, DSI_GANGED_MODE_START); | ||
455 | tegra_dsi_writel(dsi, size << 16 | size, DSI_GANGED_MODE_SIZE); | ||
456 | |||
457 | value = DSI_GANGED_MODE_CONTROL_ENABLE; | ||
458 | tegra_dsi_writel(dsi, value, DSI_GANGED_MODE_CONTROL); | ||
459 | } | ||
460 | |||
444 | static void tegra_dsi_enable(struct tegra_dsi *dsi) | 461 | static void tegra_dsi_enable(struct tegra_dsi *dsi) |
445 | { | 462 | { |
446 | u32 value; | 463 | u32 value; |
@@ -448,6 +465,20 @@ static void tegra_dsi_enable(struct tegra_dsi *dsi) | |||
448 | value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL); | 465 | value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL); |
449 | value |= DSI_POWER_CONTROL_ENABLE; | 466 | value |= DSI_POWER_CONTROL_ENABLE; |
450 | tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL); | 467 | tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL); |
468 | |||
469 | if (dsi->slave) | ||
470 | tegra_dsi_enable(dsi->slave); | ||
471 | } | ||
472 | |||
473 | static unsigned int tegra_dsi_get_lanes(struct tegra_dsi *dsi) | ||
474 | { | ||
475 | if (dsi->master) | ||
476 | return dsi->master->lanes + dsi->lanes; | ||
477 | |||
478 | if (dsi->slave) | ||
479 | return dsi->lanes + dsi->slave->lanes; | ||
480 | |||
481 | return dsi->lanes; | ||
451 | } | 482 | } |
452 | 483 | ||
453 | static int tegra_dsi_configure(struct tegra_dsi *dsi, unsigned int pipe, | 484 | static int tegra_dsi_configure(struct tegra_dsi *dsi, unsigned int pipe, |
@@ -535,11 +566,20 @@ static int tegra_dsi_configure(struct tegra_dsi *dsi, unsigned int pipe, | |||
535 | 566 | ||
536 | /* set SOL delay (for non-burst mode only) */ | 567 | /* set SOL delay (for non-burst mode only) */ |
537 | tegra_dsi_writel(dsi, 8 * mul / div, DSI_SOL_DELAY); | 568 | tegra_dsi_writel(dsi, 8 * mul / div, DSI_SOL_DELAY); |
569 | |||
570 | /* TODO: implement ganged mode */ | ||
538 | } else { | 571 | } else { |
539 | u16 bytes; | 572 | u16 bytes; |
540 | 573 | ||
541 | /* 1 byte (DCS command) + pixel data */ | 574 | if (dsi->master || dsi->slave) { |
542 | bytes = 1 + mode->hdisplay * mul / div; | 575 | /* |
576 | * For ganged mode, assume symmetric left-right mode. | ||
577 | */ | ||
578 | bytes = 1 + (mode->hdisplay / 2) * mul / div; | ||
579 | } else { | ||
580 | /* 1 byte (DCS command) + pixel data */ | ||
581 | bytes = 1 + mode->hdisplay * mul / div; | ||
582 | } | ||
543 | 583 | ||
544 | tegra_dsi_writel(dsi, 0, DSI_PKT_LEN_0_1); | 584 | tegra_dsi_writel(dsi, 0, DSI_PKT_LEN_0_1); |
545 | tegra_dsi_writel(dsi, bytes << 16, DSI_PKT_LEN_2_3); | 585 | tegra_dsi_writel(dsi, bytes << 16, DSI_PKT_LEN_2_3); |
@@ -550,11 +590,42 @@ static int tegra_dsi_configure(struct tegra_dsi *dsi, unsigned int pipe, | |||
550 | MIPI_DCS_WRITE_MEMORY_CONTINUE; | 590 | MIPI_DCS_WRITE_MEMORY_CONTINUE; |
551 | tegra_dsi_writel(dsi, value, DSI_DCS_CMDS); | 591 | tegra_dsi_writel(dsi, value, DSI_DCS_CMDS); |
552 | 592 | ||
553 | value = 8 * mul / div; | 593 | /* set SOL delay */ |
594 | if (dsi->master || dsi->slave) { | ||
595 | unsigned int lanes = tegra_dsi_get_lanes(dsi); | ||
596 | unsigned long delay, bclk, bclk_ganged; | ||
597 | |||
598 | /* SOL to valid, valid to FIFO and FIFO write delay */ | ||
599 | delay = 4 + 4 + 2; | ||
600 | delay = DIV_ROUND_UP(delay * mul, div * lanes); | ||
601 | /* FIFO read delay */ | ||
602 | delay = delay + 6; | ||
603 | |||
604 | bclk = DIV_ROUND_UP(mode->htotal * mul, div * lanes); | ||
605 | bclk_ganged = DIV_ROUND_UP(bclk * lanes / 2, lanes); | ||
606 | value = bclk - bclk_ganged + delay + 20; | ||
607 | } else { | ||
608 | /* TODO: revisit for non-ganged mode */ | ||
609 | value = 8 * mul / div; | ||
610 | } | ||
554 | 611 | ||
555 | tegra_dsi_writel(dsi, value, DSI_SOL_DELAY); | 612 | tegra_dsi_writel(dsi, value, DSI_SOL_DELAY); |
556 | } | 613 | } |
557 | 614 | ||
615 | if (dsi->slave) { | ||
616 | err = tegra_dsi_configure(dsi->slave, pipe, mode); | ||
617 | if (err < 0) | ||
618 | return err; | ||
619 | |||
620 | /* | ||
621 | * TODO: Support modes other than symmetrical left-right | ||
622 | * split. | ||
623 | */ | ||
624 | tegra_dsi_ganged_enable(dsi, 0, mode->hdisplay / 2); | ||
625 | tegra_dsi_ganged_enable(dsi->slave, mode->hdisplay / 2, | ||
626 | mode->hdisplay / 2); | ||
627 | } | ||
628 | |||
558 | return 0; | 629 | return 0; |
559 | } | 630 | } |
560 | 631 | ||
@@ -623,16 +694,34 @@ static void tegra_dsi_video_disable(struct tegra_dsi *dsi) | |||
623 | value = tegra_dsi_readl(dsi, DSI_CONTROL); | 694 | value = tegra_dsi_readl(dsi, DSI_CONTROL); |
624 | value &= ~DSI_CONTROL_VIDEO_ENABLE; | 695 | value &= ~DSI_CONTROL_VIDEO_ENABLE; |
625 | tegra_dsi_writel(dsi, value, DSI_CONTROL); | 696 | tegra_dsi_writel(dsi, value, DSI_CONTROL); |
697 | |||
698 | if (dsi->slave) | ||
699 | tegra_dsi_video_disable(dsi->slave); | ||
700 | } | ||
701 | |||
702 | static void tegra_dsi_ganged_disable(struct tegra_dsi *dsi) | ||
703 | { | ||
704 | tegra_dsi_writel(dsi, 0, DSI_GANGED_MODE_START); | ||
705 | tegra_dsi_writel(dsi, 0, DSI_GANGED_MODE_SIZE); | ||
706 | tegra_dsi_writel(dsi, 0, DSI_GANGED_MODE_CONTROL); | ||
626 | } | 707 | } |
627 | 708 | ||
628 | static void tegra_dsi_disable(struct tegra_dsi *dsi) | 709 | static void tegra_dsi_disable(struct tegra_dsi *dsi) |
629 | { | 710 | { |
630 | u32 value; | 711 | u32 value; |
631 | 712 | ||
713 | if (dsi->slave) { | ||
714 | tegra_dsi_ganged_disable(dsi->slave); | ||
715 | tegra_dsi_ganged_disable(dsi); | ||
716 | } | ||
717 | |||
632 | value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL); | 718 | value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL); |
633 | value &= ~DSI_POWER_CONTROL_ENABLE; | 719 | value &= ~DSI_POWER_CONTROL_ENABLE; |
634 | tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL); | 720 | tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL); |
635 | 721 | ||
722 | if (dsi->slave) | ||
723 | tegra_dsi_disable(dsi->slave); | ||
724 | |||
636 | usleep_range(5000, 10000); | 725 | usleep_range(5000, 10000); |
637 | } | 726 | } |
638 | 727 | ||
@@ -699,6 +788,9 @@ static void tegra_dsi_set_timeout(struct tegra_dsi *dsi, unsigned long bclk, | |||
699 | 788 | ||
700 | value = DSI_TALLY_TA(0) | DSI_TALLY_LRX(0) | DSI_TALLY_HTX(0); | 789 | value = DSI_TALLY_TA(0) | DSI_TALLY_LRX(0) | DSI_TALLY_HTX(0); |
701 | tegra_dsi_writel(dsi, value, DSI_TO_TALLY); | 790 | tegra_dsi_writel(dsi, value, DSI_TO_TALLY); |
791 | |||
792 | if (dsi->slave) | ||
793 | tegra_dsi_set_timeout(dsi->slave, bclk, vrefresh); | ||
702 | } | 794 | } |
703 | 795 | ||
704 | static int tegra_output_dsi_setup_clock(struct tegra_output *output, | 796 | static int tegra_output_dsi_setup_clock(struct tegra_output *output, |
@@ -708,20 +800,22 @@ static int tegra_output_dsi_setup_clock(struct tegra_output *output, | |||
708 | struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc); | 800 | struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc); |
709 | struct drm_display_mode *mode = &dc->base.mode; | 801 | struct drm_display_mode *mode = &dc->base.mode; |
710 | struct tegra_dsi *dsi = to_dsi(output); | 802 | struct tegra_dsi *dsi = to_dsi(output); |
711 | unsigned int mul, div, vrefresh; | 803 | unsigned int mul, div, vrefresh, lanes; |
712 | unsigned long bclk, plld; | 804 | unsigned long bclk, plld; |
713 | int err; | 805 | int err; |
714 | 806 | ||
807 | lanes = tegra_dsi_get_lanes(dsi); | ||
808 | |||
715 | err = tegra_dsi_get_muldiv(dsi->format, &mul, &div); | 809 | err = tegra_dsi_get_muldiv(dsi->format, &mul, &div); |
716 | if (err < 0) | 810 | if (err < 0) |
717 | return err; | 811 | return err; |
718 | 812 | ||
719 | DRM_DEBUG_KMS("mul: %u, div: %u, lanes: %u\n", mul, div, dsi->lanes); | 813 | DRM_DEBUG_KMS("mul: %u, div: %u, lanes: %u\n", mul, div, lanes); |
720 | vrefresh = drm_mode_vrefresh(mode); | 814 | vrefresh = drm_mode_vrefresh(mode); |
721 | DRM_DEBUG_KMS("vrefresh: %u\n", vrefresh); | 815 | DRM_DEBUG_KMS("vrefresh: %u\n", vrefresh); |
722 | 816 | ||
723 | /* compute byte clock */ | 817 | /* compute byte clock */ |
724 | bclk = (pclk * mul) / (div * dsi->lanes); | 818 | bclk = (pclk * mul) / (div * lanes); |
725 | 819 | ||
726 | /* | 820 | /* |
727 | * Compute bit clock and round up to the next MHz. | 821 | * Compute bit clock and round up to the next MHz. |
@@ -758,7 +852,7 @@ static int tegra_output_dsi_setup_clock(struct tegra_output *output, | |||
758 | * not working properly otherwise. Perhaps the PLLs cannot generate | 852 | * not working properly otherwise. Perhaps the PLLs cannot generate |
759 | * frequencies sufficiently high. | 853 | * frequencies sufficiently high. |
760 | */ | 854 | */ |
761 | *divp = ((8 * mul) / (div * dsi->lanes)) - 2; | 855 | *divp = ((8 * mul) / (div * lanes)) - 2; |
762 | 856 | ||
763 | /* | 857 | /* |
764 | * XXX: Move the below somewhere else so that we don't need to have | 858 | * XXX: Move the below somewhere else so that we don't need to have |
@@ -826,14 +920,17 @@ static int tegra_dsi_init(struct host1x_client *client) | |||
826 | struct tegra_dsi *dsi = host1x_client_to_dsi(client); | 920 | struct tegra_dsi *dsi = host1x_client_to_dsi(client); |
827 | int err; | 921 | int err; |
828 | 922 | ||
829 | dsi->output.type = TEGRA_OUTPUT_DSI; | 923 | /* Gangsters must not register their own outputs. */ |
830 | dsi->output.dev = client->dev; | 924 | if (!dsi->master) { |
831 | dsi->output.ops = &dsi_ops; | 925 | dsi->output.type = TEGRA_OUTPUT_DSI; |
832 | 926 | dsi->output.dev = client->dev; | |
833 | err = tegra_output_init(drm, &dsi->output); | 927 | dsi->output.ops = &dsi_ops; |
834 | if (err < 0) { | 928 | |
835 | dev_err(client->dev, "output setup failed: %d\n", err); | 929 | err = tegra_output_init(drm, &dsi->output); |
836 | return err; | 930 | if (err < 0) { |
931 | dev_err(client->dev, "output setup failed: %d\n", err); | ||
932 | return err; | ||
933 | } | ||
837 | } | 934 | } |
838 | 935 | ||
839 | if (IS_ENABLED(CONFIG_DEBUG_FS)) { | 936 | if (IS_ENABLED(CONFIG_DEBUG_FS)) { |
@@ -856,16 +953,20 @@ static int tegra_dsi_exit(struct host1x_client *client) | |||
856 | dev_err(dsi->dev, "debugfs cleanup failed: %d\n", err); | 953 | dev_err(dsi->dev, "debugfs cleanup failed: %d\n", err); |
857 | } | 954 | } |
858 | 955 | ||
859 | err = tegra_output_disable(&dsi->output); | 956 | if (!dsi->master) { |
860 | if (err < 0) { | 957 | err = tegra_output_disable(&dsi->output); |
861 | dev_err(client->dev, "output failed to disable: %d\n", err); | 958 | if (err < 0) { |
862 | return err; | 959 | dev_err(client->dev, "output failed to disable: %d\n", |
863 | } | 960 | err); |
864 | 961 | return err; | |
865 | err = tegra_output_exit(&dsi->output); | 962 | } |
866 | if (err < 0) { | 963 | |
867 | dev_err(client->dev, "output cleanup failed: %d\n", err); | 964 | err = tegra_output_exit(&dsi->output); |
868 | return err; | 965 | if (err < 0) { |
966 | dev_err(client->dev, "output cleanup failed: %d\n", | ||
967 | err); | ||
968 | return err; | ||
969 | } | ||
869 | } | 970 | } |
870 | 971 | ||
871 | return 0; | 972 | return 0; |
@@ -892,20 +993,58 @@ static int tegra_dsi_setup_clocks(struct tegra_dsi *dsi) | |||
892 | return 0; | 993 | return 0; |
893 | } | 994 | } |
894 | 995 | ||
996 | static int tegra_dsi_ganged_setup(struct tegra_dsi *dsi) | ||
997 | { | ||
998 | struct clk *parent; | ||
999 | int err; | ||
1000 | |||
1001 | /* make sure both DSI controllers share the same PLL */ | ||
1002 | parent = clk_get_parent(dsi->slave->clk); | ||
1003 | if (!parent) | ||
1004 | return -EINVAL; | ||
1005 | |||
1006 | err = clk_set_parent(parent, dsi->clk_parent); | ||
1007 | if (err < 0) | ||
1008 | return err; | ||
1009 | |||
1010 | return 0; | ||
1011 | } | ||
1012 | |||
895 | static int tegra_dsi_host_attach(struct mipi_dsi_host *host, | 1013 | static int tegra_dsi_host_attach(struct mipi_dsi_host *host, |
896 | struct mipi_dsi_device *device) | 1014 | struct mipi_dsi_device *device) |
897 | { | 1015 | { |
898 | struct tegra_dsi *dsi = host_to_tegra(host); | 1016 | struct tegra_dsi *dsi = host_to_tegra(host); |
899 | struct tegra_output *output = &dsi->output; | ||
900 | 1017 | ||
901 | dsi->flags = device->mode_flags; | 1018 | dsi->flags = device->mode_flags; |
902 | dsi->format = device->format; | 1019 | dsi->format = device->format; |
903 | dsi->lanes = device->lanes; | 1020 | dsi->lanes = device->lanes; |
904 | 1021 | ||
905 | output->panel = of_drm_find_panel(device->dev.of_node); | 1022 | if (dsi->slave) { |
906 | if (output->panel) { | 1023 | int err; |
907 | if (output->connector.dev) | 1024 | |
1025 | dev_dbg(dsi->dev, "attaching dual-channel device %s\n", | ||
1026 | dev_name(&device->dev)); | ||
1027 | |||
1028 | err = tegra_dsi_ganged_setup(dsi); | ||
1029 | if (err < 0) { | ||
1030 | dev_err(dsi->dev, "failed to set up ganged mode: %d\n", | ||
1031 | err); | ||
1032 | return err; | ||
1033 | } | ||
1034 | } | ||
1035 | |||
1036 | /* | ||
1037 | * Slaves don't have a panel associated with them, so they provide | ||
1038 | * merely the second channel. | ||
1039 | */ | ||
1040 | if (!dsi->master) { | ||
1041 | struct tegra_output *output = &dsi->output; | ||
1042 | |||
1043 | output->panel = of_drm_find_panel(device->dev.of_node); | ||
1044 | if (output->panel && output->connector.dev) { | ||
1045 | drm_panel_attach(output->panel, &output->connector); | ||
908 | drm_helper_hpd_irq_event(output->connector.dev); | 1046 | drm_helper_hpd_irq_event(output->connector.dev); |
1047 | } | ||
909 | } | 1048 | } |
910 | 1049 | ||
911 | return 0; | 1050 | return 0; |
@@ -932,6 +1071,26 @@ static const struct mipi_dsi_host_ops tegra_dsi_host_ops = { | |||
932 | .detach = tegra_dsi_host_detach, | 1071 | .detach = tegra_dsi_host_detach, |
933 | }; | 1072 | }; |
934 | 1073 | ||
1074 | static int tegra_dsi_ganged_probe(struct tegra_dsi *dsi) | ||
1075 | { | ||
1076 | struct device_node *np; | ||
1077 | |||
1078 | np = of_parse_phandle(dsi->dev->of_node, "nvidia,ganged-mode", 0); | ||
1079 | if (np) { | ||
1080 | struct platform_device *gangster = of_find_device_by_node(np); | ||
1081 | |||
1082 | dsi->slave = platform_get_drvdata(gangster); | ||
1083 | of_node_put(np); | ||
1084 | |||
1085 | if (!dsi->slave) | ||
1086 | return -EPROBE_DEFER; | ||
1087 | |||
1088 | dsi->slave->master = dsi; | ||
1089 | } | ||
1090 | |||
1091 | return 0; | ||
1092 | } | ||
1093 | |||
935 | static int tegra_dsi_probe(struct platform_device *pdev) | 1094 | static int tegra_dsi_probe(struct platform_device *pdev) |
936 | { | 1095 | { |
937 | struct tegra_dsi *dsi; | 1096 | struct tegra_dsi *dsi; |
@@ -946,6 +1105,10 @@ static int tegra_dsi_probe(struct platform_device *pdev) | |||
946 | dsi->video_fifo_depth = 1920; | 1105 | dsi->video_fifo_depth = 1920; |
947 | dsi->host_fifo_depth = 64; | 1106 | dsi->host_fifo_depth = 64; |
948 | 1107 | ||
1108 | err = tegra_dsi_ganged_probe(dsi); | ||
1109 | if (err < 0) | ||
1110 | return err; | ||
1111 | |||
949 | err = tegra_output_probe(&dsi->output); | 1112 | err = tegra_output_probe(&dsi->output); |
950 | if (err < 0) | 1113 | if (err < 0) |
951 | return err; | 1114 | return err; |
diff --git a/drivers/gpu/drm/tegra/dsi.h b/drivers/gpu/drm/tegra/dsi.h index 5ce610d08d77..1f6ca68108d8 100644 --- a/drivers/gpu/drm/tegra/dsi.h +++ b/drivers/gpu/drm/tegra/dsi.h | |||
@@ -104,6 +104,7 @@ | |||
104 | #define DSI_PAD_CONTROL_3 0x51 | 104 | #define DSI_PAD_CONTROL_3 0x51 |
105 | #define DSI_PAD_CONTROL_4 0x52 | 105 | #define DSI_PAD_CONTROL_4 0x52 |
106 | #define DSI_GANGED_MODE_CONTROL 0x53 | 106 | #define DSI_GANGED_MODE_CONTROL 0x53 |
107 | #define DSI_GANGED_MODE_CONTROL_ENABLE (1 << 0) | ||
107 | #define DSI_GANGED_MODE_START 0x54 | 108 | #define DSI_GANGED_MODE_START 0x54 |
108 | #define DSI_GANGED_MODE_SIZE 0x55 | 109 | #define DSI_GANGED_MODE_SIZE 0x55 |
109 | #define DSI_RAW_DATA_BYTE_COUNT 0x56 | 110 | #define DSI_RAW_DATA_BYTE_COUNT 0x56 |