aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThierry Reding <treding@nvidia.com>2014-10-07 10:10:24 -0400
committerThierry Reding <treding@nvidia.com>2014-11-13 10:12:28 -0500
commite94236cde4d519cdecd45e2435defba33abdc99f (patch)
tree637cd405102afcefa55f7a3bf195a3935709ac7c
parent3f6b406f7d716310c7a63648bbe6b2a4a30c3077 (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.txt2
-rw-r--r--drivers/gpu/drm/tegra/dsi.c221
-rw-r--r--drivers/gpu/drm/tegra/dsi.h1
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
59static inline struct tegra_dsi * 64static 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
449static 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
444static void tegra_dsi_enable(struct tegra_dsi *dsi) 461static 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
473static 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
453static int tegra_dsi_configure(struct tegra_dsi *dsi, unsigned int pipe, 484static 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
702static 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
628static void tegra_dsi_disable(struct tegra_dsi *dsi) 709static 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
704static int tegra_output_dsi_setup_clock(struct tegra_output *output, 796static 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
996static 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
895static int tegra_dsi_host_attach(struct mipi_dsi_host *host, 1013static 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
1074static 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
935static int tegra_dsi_probe(struct platform_device *pdev) 1094static 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