[PATCH v2 04/17] drm/tegra: dsi: Add ganged mode support

2014-11-04 Thread Thierry Reding
On Mon, Nov 03, 2014 at 01:30:38PM -0500, Sean Paul wrote:
> On Mon, Nov 3, 2014 at 4:27 AM, Thierry Reding  
> wrote:
> > From: Thierry Reding 
> >
> > 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.
> >
> 
> There's a lot in here that is not specifically ganging-support, such
> as adding the transfer callback and command mode, as well as pulling
> out functionality into helper functions. It might make things a little
> clearer to split this up into a few patches. I'll leave that up to
> you.

I think I tried to do that a while back, but things got really
complicated so I abandonned that effort. I'll give it another shot and
see what I can come up with.

> > diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c
[...]
> > -static int tegra_output_dsi_enable(struct tegra_output *output)
> > +static void tegra_dsi_ganged_enable(struct tegra_dsi *dsi, unsigned int 
> > start,
> > +   unsigned int size)
> > +{
> > +   u32 value;
> > +
> > +   tegra_dsi_writel(dsi, start, DSI_GANGED_MODE_START);
> > +   tegra_dsi_writel(dsi, size << 16 | size, DSI_GANGED_MODE_SIZE);
> 
> You might want to add "size = size & 0x;" before performing this write.

Actually according to register documentation the mask even needs to be
0x1fff, so that's a good idea. Alternatively I guess we could check the
size earlier to make sure that we can actually support it.

Thierry
-- next part --
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: 



[PATCH v2 04/17] drm/tegra: dsi: Add ganged mode support

2014-11-03 Thread Sean Paul
On Mon, Nov 3, 2014 at 4:27 AM, Thierry Reding  
wrote:
> From: Thierry Reding 
>
> 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.
>

There's a lot in here that is not specifically ganging-support, such
as adding the transfer callback and command mode, as well as pulling
out functionality into helper functions. It might make things a little
clearer to split this up into a few patches. I'll leave that up to
you.

At any rate, aside from the tiny nit I picked below (which you can
feel free to ignore),

Reviewed-by: Sean Paul 



> Signed-off-by: Thierry Reding 
> ---
> Changes in v2:
> - keep track of the number of bytes transferred to/from peripheral
> - use newly introduced mipi_dsi_create_packet()
> - extract FIFO write into separate function
>
>  .../bindings/gpu/nvidia,tegra20-host1x.txt |   2 +
>  drivers/gpu/drm/tegra/dsi.c| 792 
> ++---
>  drivers/gpu/drm/tegra/dsi.h|  14 +-
>  3 files changed, 691 insertions(+), 117 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:
>- nvidia,hpd-gpio: specifies a GPIO used for hotplug detection
>- nvidia,edid: supplies a binary EDID blob
>- nvidia,panel: phandle of a display panel
> +  - nvidia,ganged-mode: contains a phandle to a second DSI controller to gang
> +up with in order to support up to 8 data lanes
>
>  - sor: serial output resource
>
> diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c
> index 584b771d8b2f..8940360ccc9c 100644
> --- a/drivers/gpu/drm/tegra/dsi.c
> +++ b/drivers/gpu/drm/tegra/dsi.c
> @@ -11,6 +11,7 @@
>  #include 
>  #include 
>  #include 
> +#include 
>  #include 
>  #include 
>
> @@ -54,6 +55,10 @@ struct tegra_dsi {
>
> unsigned int video_fifo_depth;
> unsigned int host_fifo_depth;
> +
> +   /* for ganged-mode support */
> +   struct tegra_dsi *master;
> +   struct tegra_dsi *slave;
>  };
>
>  static inline struct tegra_dsi *
> @@ -318,6 +323,21 @@ static const u32 
> pkt_seq_video_non_burst_sync_events[NUM_PKT_SEQ] = {
> [11] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(4),
>  };
>
> +static const u32 pkt_seq_command_mode[NUM_PKT_SEQ] = {
> +   [ 0] = 0,
> +   [ 1] = 0,
> +   [ 2] = 0,
> +   [ 3] = 0,
> +   [ 4] = 0,
> +   [ 5] = 0,
> +   [ 6] = PKT_ID0(MIPI_DSI_DCS_LONG_WRITE) | PKT_LEN0(3) | PKT_LP,
> +   [ 7] = 0,
> +   [ 8] = 0,
> +   [ 9] = 0,
> +   [10] = PKT_ID0(MIPI_DSI_DCS_LONG_WRITE) | PKT_LEN0(5) | PKT_LP,
> +   [11] = 0,
> +};
> +
>  static int tegra_dsi_set_phy_timing(struct tegra_dsi *dsi)
>  {
> struct mipi_dphy_timing timing;
> @@ -329,7 +349,7 @@ static int tegra_dsi_set_phy_timing(struct tegra_dsi *dsi)
> if (rate < 0)
> return rate;
>
> -   period = DIV_ROUND_CLOSEST(10UL, rate * 2);
> +   period = DIV_ROUND_CLOSEST(NSEC_PER_SEC, rate * 2);
>
> err = mipi_dphy_timing_get_default(, period);
> if (err < 0)
> @@ -426,26 +446,59 @@ static int tegra_dsi_get_format(enum 
> mipi_dsi_pixel_format format,
> return 0;
>  }
>
> -static int tegra_output_dsi_enable(struct tegra_output *output)
> +static void tegra_dsi_ganged_enable(struct tegra_dsi *dsi, unsigned int 
> start,
> +   unsigned int size)
> +{
> +   u32 value;
> +
> +   tegra_dsi_writel(dsi, start, DSI_GANGED_MODE_START);
> +   tegra_dsi_writel(dsi, size << 16 | size, DSI_GANGED_MODE_SIZE);

You might want to add "size = size & 0x;" before performing this write.

> +
> +   value = DSI_GANGED_MODE_CONTROL_ENABLE;
> +   tegra_dsi_writel(dsi, value, DSI_GANGED_MODE_CONTROL);
> +}
> +
> +static void tegra_dsi_enable(struct tegra_dsi *dsi)
> +{
> +   u32 value;
> +
> +   value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL);
> +   value |= DSI_POWER_CONTROL_ENABLE;
> +   tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL);
> +
> +   if (dsi->slave)
> +   tegra_dsi_enable(dsi->slave);
> +}
> +
> +static unsigned int tegra_dsi_get_lanes(struct tegra_dsi *dsi)
> +{
> +   if (dsi->master)
> +   return dsi->master->lanes + dsi->lanes;
> +
> +   if (dsi->slave)
> +   return dsi->lanes + dsi->slave->lanes;
> +
> +   return dsi->lanes;
> +}
> +
> +static int tegra_dsi_configure(struct tegra_dsi *dsi, unsigned int pipe,
> +  const 

[PATCH v2 04/17] drm/tegra: dsi: Add ganged mode support

2014-11-03 Thread Thierry Reding
From: Thierry Reding 

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 
---
Changes in v2:
- keep track of the number of bytes transferred to/from peripheral
- use newly introduced mipi_dsi_create_packet()
- extract FIFO write into separate function

 .../bindings/gpu/nvidia,tegra20-host1x.txt |   2 +
 drivers/gpu/drm/tegra/dsi.c| 792 ++---
 drivers/gpu/drm/tegra/dsi.h|  14 +-
 3 files changed, 691 insertions(+), 117 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:
   - nvidia,hpd-gpio: specifies a GPIO used for hotplug detection
   - nvidia,edid: supplies a binary EDID blob
   - nvidia,panel: phandle of a display panel
+  - nvidia,ganged-mode: contains a phandle to a second DSI controller to gang
+up with in order to support up to 8 data lanes

 - sor: serial output resource

diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c
index 584b771d8b2f..8940360ccc9c 100644
--- a/drivers/gpu/drm/tegra/dsi.c
+++ b/drivers/gpu/drm/tegra/dsi.c
@@ -11,6 +11,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 

@@ -54,6 +55,10 @@ struct tegra_dsi {

unsigned int video_fifo_depth;
unsigned int host_fifo_depth;
+
+   /* for ganged-mode support */
+   struct tegra_dsi *master;
+   struct tegra_dsi *slave;
 };

 static inline struct tegra_dsi *
@@ -318,6 +323,21 @@ static const u32 
pkt_seq_video_non_burst_sync_events[NUM_PKT_SEQ] = {
[11] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(4),
 };

+static const u32 pkt_seq_command_mode[NUM_PKT_SEQ] = {
+   [ 0] = 0,
+   [ 1] = 0,
+   [ 2] = 0,
+   [ 3] = 0,
+   [ 4] = 0,
+   [ 5] = 0,
+   [ 6] = PKT_ID0(MIPI_DSI_DCS_LONG_WRITE) | PKT_LEN0(3) | PKT_LP,
+   [ 7] = 0,
+   [ 8] = 0,
+   [ 9] = 0,
+   [10] = PKT_ID0(MIPI_DSI_DCS_LONG_WRITE) | PKT_LEN0(5) | PKT_LP,
+   [11] = 0,
+};
+
 static int tegra_dsi_set_phy_timing(struct tegra_dsi *dsi)
 {
struct mipi_dphy_timing timing;
@@ -329,7 +349,7 @@ static int tegra_dsi_set_phy_timing(struct tegra_dsi *dsi)
if (rate < 0)
return rate;

-   period = DIV_ROUND_CLOSEST(10UL, rate * 2);
+   period = DIV_ROUND_CLOSEST(NSEC_PER_SEC, rate * 2);

err = mipi_dphy_timing_get_default(, period);
if (err < 0)
@@ -426,26 +446,59 @@ static int tegra_dsi_get_format(enum 
mipi_dsi_pixel_format format,
return 0;
 }

-static int tegra_output_dsi_enable(struct tegra_output *output)
+static void tegra_dsi_ganged_enable(struct tegra_dsi *dsi, unsigned int start,
+   unsigned int size)
+{
+   u32 value;
+
+   tegra_dsi_writel(dsi, start, DSI_GANGED_MODE_START);
+   tegra_dsi_writel(dsi, size << 16 | size, DSI_GANGED_MODE_SIZE);
+
+   value = DSI_GANGED_MODE_CONTROL_ENABLE;
+   tegra_dsi_writel(dsi, value, DSI_GANGED_MODE_CONTROL);
+}
+
+static void tegra_dsi_enable(struct tegra_dsi *dsi)
+{
+   u32 value;
+
+   value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL);
+   value |= DSI_POWER_CONTROL_ENABLE;
+   tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL);
+
+   if (dsi->slave)
+   tegra_dsi_enable(dsi->slave);
+}
+
+static unsigned int tegra_dsi_get_lanes(struct tegra_dsi *dsi)
+{
+   if (dsi->master)
+   return dsi->master->lanes + dsi->lanes;
+
+   if (dsi->slave)
+   return dsi->lanes + dsi->slave->lanes;
+
+   return dsi->lanes;
+}
+
+static int tegra_dsi_configure(struct tegra_dsi *dsi, unsigned int pipe,
+  const struct drm_display_mode *mode)
 {
-   struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc);
-   struct drm_display_mode *mode = >base.mode;
unsigned int hact, hsw, hbp, hfp, i, mul, div;
-   struct tegra_dsi *dsi = to_dsi(output);
enum tegra_dsi_format format;
-   unsigned long value;
const u32 *pkt_seq;
+   u32 value;
int err;

-   if (dsi->enabled)
-   return 0;
-
if (dsi->flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) {
DRM_DEBUG_KMS("Non-burst video mode with sync pulses\n");
pkt_seq = pkt_seq_video_non_burst_sync_pulses;
-   } else {
+   } else if (dsi->flags & MIPI_DSI_MODE_VIDEO) {
DRM_DEBUG_KMS("Non-burst video mode with sync