mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Thierry Reding <thierry.reding@gmail.com>
To: dri-devel@lists.freedesktop.org
Cc: linux-tegra@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH 27/36] drm/tegra: dsi: Implement ->atomic_check()
Date: Tue, 20 Jan 2015 11:48:46 +0100	[thread overview]
Message-ID: <1421750935-4023-28-git-send-email-thierry.reding@gmail.com> (raw)
In-Reply-To: <1421750935-4023-1-git-send-email-thierry.reding@gmail.com>

From: Thierry Reding <treding@nvidia.com>

The implementation of the ->atomic_check() callback precomputes all
parameters to check if the given configuration can be applied. If so the
precomputed values are stored in the atomic state object for the encoder
and applied during modeset. In that way the modeset no longer needs to
perform any checking but simply program values into registers.

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 drivers/gpu/drm/tegra/dsi.c | 269 ++++++++++++++++++++++++++++++++------------
 1 file changed, 196 insertions(+), 73 deletions(-)

diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c
index 9799f3edc3f8..55a6a95bda84 100644
--- a/drivers/gpu/drm/tegra/dsi.c
+++ b/drivers/gpu/drm/tegra/dsi.c
@@ -28,6 +28,28 @@
 #include "dsi.h"
 #include "mipi-phy.h"
 
+struct tegra_dsi_state {
+	struct drm_connector_state base;
+
+	struct mipi_dphy_timing timing;
+	unsigned long period;
+
+	unsigned int vrefresh;
+	unsigned int lanes;
+	unsigned long pclk;
+	unsigned long bclk;
+
+	enum tegra_dsi_format format;
+	unsigned int mul;
+	unsigned int div;
+};
+
+static inline struct tegra_dsi_state *
+to_dsi_state(struct drm_connector_state *state)
+{
+	return container_of(state, struct tegra_dsi_state, base);
+}
+
 struct tegra_dsi {
 	struct host1x_client client;
 	struct tegra_output output;
@@ -77,6 +99,11 @@ static inline struct tegra_dsi *to_dsi(struct tegra_output *output)
 	return container_of(output, struct tegra_dsi, output);
 }
 
+static struct tegra_dsi_state *tegra_dsi_get_state(struct tegra_dsi *dsi)
+{
+	return to_dsi_state(dsi->output.connector.state);
+}
+
 static inline u32 tegra_dsi_readl(struct tegra_dsi *dsi, unsigned long reg)
 {
 	return readl(dsi->regs + (reg << 2));
@@ -335,62 +362,36 @@ static const u32 pkt_seq_command_mode[NUM_PKT_SEQ] = {
 	[11] = 0,
 };
 
-static int tegra_dsi_set_phy_timing(struct tegra_dsi *dsi)
+static void tegra_dsi_set_phy_timing(struct tegra_dsi *dsi,
+				     unsigned long period,
+				     const struct mipi_dphy_timing *timing)
 {
-	struct mipi_dphy_timing timing;
-	unsigned long period;
 	u32 value;
-	long rate;
-	int err;
-
-	rate = clk_get_rate(dsi->clk);
-	if (rate < 0)
-		return rate;
-
-	period = DIV_ROUND_CLOSEST(NSEC_PER_SEC, rate * 2);
 
-	err = mipi_dphy_timing_get_default(&timing, period);
-	if (err < 0)
-		return err;
-
-	err = mipi_dphy_timing_validate(&timing, period);
-	if (err < 0) {
-		dev_err(dsi->dev, "failed to validate D-PHY timing: %d\n", err);
-		return err;
-	}
-
-	/*
-	 * The D-PHY timing fields below are expressed in byte-clock cycles,
-	 * so multiply the period by 8.
-	 */
-	period *= 8;
-
-	value = DSI_TIMING_FIELD(timing.hsexit, period, 1) << 24 |
-		DSI_TIMING_FIELD(timing.hstrail, period, 0) << 16 |
-		DSI_TIMING_FIELD(timing.hszero, period, 3) << 8 |
-		DSI_TIMING_FIELD(timing.hsprepare, period, 1);
+	value = DSI_TIMING_FIELD(timing->hsexit, period, 1) << 24 |
+		DSI_TIMING_FIELD(timing->hstrail, period, 0) << 16 |
+		DSI_TIMING_FIELD(timing->hszero, period, 3) << 8 |
+		DSI_TIMING_FIELD(timing->hsprepare, period, 1);
 	tegra_dsi_writel(dsi, value, DSI_PHY_TIMING_0);
 
-	value = DSI_TIMING_FIELD(timing.clktrail, period, 1) << 24 |
-		DSI_TIMING_FIELD(timing.clkpost, period, 1) << 16 |
-		DSI_TIMING_FIELD(timing.clkzero, period, 1) << 8 |
-		DSI_TIMING_FIELD(timing.lpx, period, 1);
+	value = DSI_TIMING_FIELD(timing->clktrail, period, 1) << 24 |
+		DSI_TIMING_FIELD(timing->clkpost, period, 1) << 16 |
+		DSI_TIMING_FIELD(timing->clkzero, period, 1) << 8 |
+		DSI_TIMING_FIELD(timing->lpx, period, 1);
 	tegra_dsi_writel(dsi, value, DSI_PHY_TIMING_1);
 
-	value = DSI_TIMING_FIELD(timing.clkprepare, period, 1) << 16 |
-		DSI_TIMING_FIELD(timing.clkpre, period, 1) << 8 |
+	value = DSI_TIMING_FIELD(timing->clkprepare, period, 1) << 16 |
+		DSI_TIMING_FIELD(timing->clkpre, period, 1) << 8 |
 		DSI_TIMING_FIELD(0xff * period, period, 0) << 0;
 	tegra_dsi_writel(dsi, value, DSI_PHY_TIMING_2);
 
-	value = DSI_TIMING_FIELD(timing.taget, period, 1) << 16 |
-		DSI_TIMING_FIELD(timing.tasure, period, 1) << 8 |
-		DSI_TIMING_FIELD(timing.tago, period, 1);
+	value = DSI_TIMING_FIELD(timing->taget, period, 1) << 16 |
+		DSI_TIMING_FIELD(timing->tasure, period, 1) << 8 |
+		DSI_TIMING_FIELD(timing->tago, period, 1);
 	tegra_dsi_writel(dsi, value, DSI_BTA_TIMING);
 
 	if (dsi->slave)
-		return tegra_dsi_set_phy_timing(dsi->slave);
-
-	return 0;
+		tegra_dsi_set_phy_timing(dsi->slave, period, timing);
 }
 
 static int tegra_dsi_get_muldiv(enum mipi_dsi_pixel_format format,
@@ -482,14 +483,22 @@ static unsigned int tegra_dsi_get_lanes(struct tegra_dsi *dsi)
 	return dsi->lanes;
 }
 
-static int tegra_dsi_configure(struct tegra_dsi *dsi, unsigned int pipe,
-			       const struct drm_display_mode *mode)
+static void tegra_dsi_configure(struct tegra_dsi *dsi, unsigned int pipe,
+				const struct drm_display_mode *mode)
 {
 	unsigned int hact, hsw, hbp, hfp, i, mul, div;
-	enum tegra_dsi_format format;
+	struct tegra_dsi_state *state;
 	const u32 *pkt_seq;
 	u32 value;
-	int err;
+
+	/* XXX: pass in state into this function? */
+	if (dsi->master)
+		state = tegra_dsi_get_state(dsi->master);
+	else
+		state = tegra_dsi_get_state(dsi);
+
+	mul = state->mul;
+	div = state->div;
 
 	if (dsi->flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) {
 		DRM_DEBUG_KMS("Non-burst video mode with sync pulses\n");
@@ -502,15 +511,8 @@ static int tegra_dsi_configure(struct tegra_dsi *dsi, unsigned int pipe,
 		pkt_seq = pkt_seq_command_mode;
 	}
 
-	err = tegra_dsi_get_muldiv(dsi->format, &mul, &div);
-	if (err < 0)
-		return err;
-
-	err = tegra_dsi_get_format(dsi->format, &format);
-	if (err < 0)
-		return err;
-
-	value = DSI_CONTROL_CHANNEL(0) | DSI_CONTROL_FORMAT(format) |
+	value = DSI_CONTROL_CHANNEL(0) |
+		DSI_CONTROL_FORMAT(state->format) |
 		DSI_CONTROL_LANES(dsi->lanes - 1) |
 		DSI_CONTROL_SOURCE(pipe);
 	tegra_dsi_writel(dsi, value, DSI_CONTROL);
@@ -589,8 +591,8 @@ static int tegra_dsi_configure(struct tegra_dsi *dsi, unsigned int pipe,
 
 		/* set SOL delay */
 		if (dsi->master || dsi->slave) {
-			unsigned int lanes = tegra_dsi_get_lanes(dsi);
 			unsigned long delay, bclk, bclk_ganged;
+			unsigned int lanes = state->lanes;
 
 			/* SOL to valid, valid to FIFO and FIFO write delay */
 			delay = 4 + 4 + 2;
@@ -610,9 +612,7 @@ static int tegra_dsi_configure(struct tegra_dsi *dsi, unsigned int pipe,
 	}
 
 	if (dsi->slave) {
-		err = tegra_dsi_configure(dsi->slave, pipe, mode);
-		if (err < 0)
-			return err;
+		tegra_dsi_configure(dsi->slave, pipe, mode);
 
 		/*
 		 * TODO: Support modes other than symmetrical left-right
@@ -622,8 +622,6 @@ static int tegra_dsi_configure(struct tegra_dsi *dsi, unsigned int pipe,
 		tegra_dsi_ganged_enable(dsi->slave, mode->hdisplay / 2,
 					mode->hdisplay / 2);
 	}
-
-	return 0;
 }
 
 static int tegra_dsi_wait_idle(struct tegra_dsi *dsi, unsigned long timeout)
@@ -732,13 +730,38 @@ static void tegra_dsi_connector_dpms(struct drm_connector *connector, int mode)
 {
 }
 
+static void tegra_dsi_connector_reset(struct drm_connector *connector)
+{
+	struct tegra_dsi_state *state;
+
+	kfree(connector->state);
+	connector->state = NULL;
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (state)
+		connector->state = &state->base;
+}
+
+static struct drm_connector_state *
+tegra_dsi_connector_duplicate_state(struct drm_connector *connector)
+{
+	struct tegra_dsi_state *state = to_dsi_state(connector->state);
+	struct tegra_dsi_state *copy;
+
+	copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
+	if (!copy)
+		return NULL;
+
+	return &copy->base;
+}
+
 static const struct drm_connector_funcs tegra_dsi_connector_funcs = {
 	.dpms = tegra_dsi_connector_dpms,
-	.reset = drm_atomic_helper_connector_reset,
+	.reset = tegra_dsi_connector_reset,
 	.detect = tegra_output_connector_detect,
 	.fill_modes = drm_helper_probe_single_connector_modes,
 	.destroy = tegra_output_connector_destroy,
-	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_duplicate_state = tegra_dsi_connector_duplicate_state,
 	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 };
 
@@ -771,7 +794,9 @@ static bool tegra_dsi_encoder_mode_fixup(struct drm_encoder *encoder,
 	struct tegra_dc *dc = to_tegra_dc(encoder->crtc);
 	unsigned int mul, div, scdiv, vrefresh, lanes;
 	struct tegra_dsi *dsi = to_dsi(output);
+	struct mipi_dphy_timing timing;
 	unsigned long pclk, bclk, plld;
+	unsigned long period;
 	int err;
 
 	lanes = tegra_dsi_get_lanes(dsi);
@@ -792,6 +817,7 @@ static bool tegra_dsi_encoder_mode_fixup(struct drm_encoder *encoder,
 	 * Compute bit clock and round up to the next MHz.
 	 */
 	plld = DIV_ROUND_UP(bclk * 8, USEC_PER_SEC) * USEC_PER_SEC;
+	period = DIV_ROUND_CLOSEST(NSEC_PER_SEC, plld);
 
 	/*
 	 * We divide the frequency by two here, but we make up for that by
@@ -827,12 +853,22 @@ static bool tegra_dsi_encoder_mode_fixup(struct drm_encoder *encoder,
 
 	tegra_dsi_set_timeout(dsi, bclk, vrefresh);
 
-	err = tegra_dsi_set_phy_timing(dsi);
+	err = mipi_dphy_timing_get_default(&timing, period);
+	if (err < 0)
+		return err;
+
+	err = mipi_dphy_timing_validate(&timing, period);
 	if (err < 0) {
-		dev_err(dsi->dev, "failed to setup D-PHY timing: %d\n", err);
-		return false;
+		dev_err(dsi->dev, "failed to validate D-PHY timing: %d\n", err);
+		return err;
 	}
 
+	/*
+	 * The D-PHY timing fields are expressed in byte-clock cycles, so
+	 * multiply the period by 8.
+	 */
+	tegra_dsi_set_phy_timing(dsi, period * 8, &timing);
+
 	return true;
 }
 
@@ -851,19 +887,24 @@ static void tegra_dsi_encoder_mode_set(struct drm_encoder *encoder,
 	struct tegra_output *output = encoder_to_output(encoder);
 	struct tegra_dc *dc = to_tegra_dc(encoder->crtc);
 	struct tegra_dsi *dsi = to_dsi(output);
+	struct tegra_dsi_state *state;
 	u32 value;
-	int err;
 
+	state = tegra_dsi_get_state(dsi);
 
-	err = tegra_dsi_configure(dsi, dc->pipe, mode);
-	if (err < 0) {
-		dev_err(dsi->dev, "failed to configure DSI: %d\n", err);
-		return;
-	}
+	tegra_dsi_set_timeout(dsi, state->bclk, state->vrefresh);
+
+	/*
+	 * The D-PHY timing fields are expressed in byte-clock cycles, so
+	 * multiply the period by 8.
+	 */
+	tegra_dsi_set_phy_timing(dsi, state->period * 8, &state->timing);
 
 	if (output->panel)
 		drm_panel_prepare(output->panel);
 
+	tegra_dsi_configure(dsi, dc->pipe, mode);
+
 	/* enable display controller */
 	value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
 	value |= DSI_ENABLE;
@@ -929,6 +970,87 @@ static void tegra_dsi_encoder_disable(struct drm_encoder *encoder)
 	return;
 }
 
+static int
+tegra_dsi_encoder_atomic_check(struct drm_encoder *encoder,
+			       struct drm_crtc_state *crtc_state,
+			       struct drm_connector_state *conn_state)
+{
+	struct tegra_output *output = encoder_to_output(encoder);
+	struct tegra_dsi_state *state = to_dsi_state(conn_state);
+	struct tegra_dc *dc = to_tegra_dc(conn_state->crtc);
+	struct tegra_dsi *dsi = to_dsi(output);
+	unsigned int scdiv;
+	unsigned long plld;
+	int err;
+
+	state->pclk = crtc_state->mode.clock * 1000;
+
+	err = tegra_dsi_get_muldiv(dsi->format, &state->mul, &state->div);
+	if (err < 0)
+		return err;
+
+	state->lanes = tegra_dsi_get_lanes(dsi);
+
+	err = tegra_dsi_get_format(dsi->format, &state->format);
+	if (err < 0)
+		return err;
+
+	state->vrefresh = drm_mode_vrefresh(&crtc_state->mode);
+
+	/* compute byte clock */
+	state->bclk = (state->pclk * state->mul) / (state->div * state->lanes);
+
+	DRM_DEBUG_KMS("mul: %u, div: %u, lanes: %u\n", state->mul, state->div,
+		      state->lanes);
+	DRM_DEBUG_KMS("format: %u, vrefresh: %u\n", state->format,
+		      state->vrefresh);
+	DRM_DEBUG_KMS("bclk: %lu\n", state->bclk);
+
+	/*
+	 * Compute bit clock and round up to the next MHz.
+	 */
+	plld = DIV_ROUND_UP(state->bclk * 8, USEC_PER_SEC) * USEC_PER_SEC;
+	state->period = DIV_ROUND_CLOSEST(NSEC_PER_SEC, plld);
+
+	err = mipi_dphy_timing_get_default(&state->timing, state->period);
+	if (err < 0)
+		return err;
+
+	err = mipi_dphy_timing_validate(&state->timing, state->period);
+	if (err < 0) {
+		dev_err(dsi->dev, "failed to validate D-PHY timing: %d\n", err);
+		return err;
+	}
+
+	/*
+	 * We divide the frequency by two here, but we make up for that by
+	 * setting the shift clock divider (further below) to half of the
+	 * correct value.
+	 */
+	plld /= 2;
+
+	/*
+	 * Derive pixel clock from bit clock using the shift clock divider.
+	 * Note that this is only half of what we would expect, but we need
+	 * that to make up for the fact that we divided the bit clock by a
+	 * factor of two above.
+	 *
+	 * It's not clear exactly why this is necessary, but the display is
+	 * not working properly otherwise. Perhaps the PLLs cannot generate
+	 * frequencies sufficiently high.
+	 */
+	scdiv = ((8 * state->mul) / (state->div * state->lanes)) - 2;
+
+	err = tegra_dc_state_setup_clock(dc, crtc_state, dsi->clk_parent,
+					 plld, scdiv);
+	if (err < 0) {
+		dev_err(output->dev, "failed to setup CRTC state: %d\n", err);
+		return err;
+	}
+
+	return err;
+}
+
 static const struct drm_encoder_helper_funcs tegra_dsi_encoder_helper_funcs = {
 	.dpms = tegra_dsi_encoder_dpms,
 	.mode_fixup = tegra_dsi_encoder_mode_fixup,
@@ -936,6 +1058,7 @@ static const struct drm_encoder_helper_funcs tegra_dsi_encoder_helper_funcs = {
 	.commit = tegra_dsi_encoder_commit,
 	.mode_set = tegra_dsi_encoder_mode_set,
 	.disable = tegra_dsi_encoder_disable,
+	.atomic_check = tegra_dsi_encoder_atomic_check,
 };
 
 static int tegra_dsi_pad_enable(struct tegra_dsi *dsi)
-- 
2.1.3


  parent reply	other threads:[~2015-01-20 10:49 UTC|newest]

Thread overview: 61+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-01-20 10:48 [PATCH 00/36] drm/tegra: Atomic mode-setting conversion Thierry Reding
2015-01-20 10:48 ` [PATCH 01/36] clk: Introduce clk_try_parent() Thierry Reding
2015-01-20 18:02   ` Mike Turquette
2015-01-20 18:16     ` Rob Clark
2015-01-21 15:12       ` Thierry Reding
2015-01-20 19:21   ` Stephen Boyd
2015-01-21 15:05     ` Thierry Reding
2015-01-21 16:13   ` [PATCH v2] clk: Introduce clk_has_parent() Thierry Reding
2015-01-22  0:16     ` Stephen Boyd
2015-01-22  7:37       ` Thierry Reding
2015-01-22 20:25         ` Stephen Boyd
2015-01-23  9:34           ` Thierry Reding
2015-01-25  1:02             ` Mike Turquette
2015-01-20 10:48 ` [PATCH 02/36] drm/plane: Make ->atomic_update() mandatory Thierry Reding
2015-01-20 11:10   ` Daniel Vetter
2015-01-20 13:51   ` Rob Clark
2015-01-23  9:18     ` Thierry Reding
2015-01-23  9:26   ` [PATCH v2] " Thierry Reding
2015-01-20 10:48 ` [PATCH 03/36] drm/plane: Add optional ->atomic_disable() callback Thierry Reding
2015-01-20 11:13   ` Daniel Vetter
2015-01-22 18:57   ` Gustavo Padovan
2015-01-23  9:28   ` [PATCH v4] " Thierry Reding
2015-01-20 10:48 ` [PATCH 04/36] drm/atomic: Add ->atomic_check() to encoder helpers Thierry Reding
2015-01-20 11:07   ` Daniel Vetter
2015-01-20 10:48 ` [PATCH 05/36] drm/atomic: Add drm_atomic_plane_get_crtc_state() Thierry Reding
2015-01-20 11:10   ` Daniel Vetter
2015-01-23  9:32     ` Thierry Reding
2015-01-20 10:48 ` [PATCH 06/36] drm/tegra: Use tegra_commit_dc() in output drivers Thierry Reding
2015-01-20 10:48 ` [PATCH 07/36] drm/tegra: Stop CRTC at CRTC disable time Thierry Reding
2015-01-20 10:48 ` [PATCH 08/36] drm/tegra: dc: Wait for idle when disabled Thierry Reding
2015-01-20 10:48 ` [PATCH 09/36] drm/tegra: Move tegra_drm_mode_funcs to the core Thierry Reding
2015-01-20 10:48 ` [PATCH 10/36] drm/tegra: dc: No longer disable planes at CRTC disable Thierry Reding
2015-01-20 10:48 ` [PATCH 11/36] drm/tegra: Convert output midlayer to helpers Thierry Reding
2015-01-20 10:48 ` [PATCH 12/36] drm/tegra: output: Make ->setup_clock() optional Thierry Reding
2015-01-20 10:48 ` [PATCH 13/36] drm/tegra: Add tegra_dc_setup_clock() helper Thierry Reding
2015-01-20 10:48 ` [PATCH 14/36] drm/tegra: rgb: Demidlayer Thierry Reding
2015-01-20 10:48 ` [PATCH 15/36] drm/tegra: hdmi: Demidlayer Thierry Reding
2015-01-20 10:48 ` [PATCH 16/36] drm/tegra: dsi: Demidlayer Thierry Reding
2015-01-20 10:48 ` [PATCH 17/36] drm/tegra: sor: Demidlayer Thierry Reding
2015-01-20 10:48 ` [PATCH 18/36] drm/tegra: debugfs cleanup cannot fail Thierry Reding
2015-01-20 10:48 ` [PATCH 19/36] drm/tegra: Remove remnants of the output midlayer Thierry Reding
2015-01-20 10:48 ` [PATCH 20/36] drm/tegra: Output cleanup functions cannot fail Thierry Reding
2015-01-20 10:48 ` [PATCH 21/36] drm/tegra: dc: Do not needlessly deassert reset Thierry Reding
2015-01-20 10:48 ` [PATCH 22/36] drm/tegra: Atomic conversion, phase 1 Thierry Reding
2015-01-20 10:48 ` [PATCH 23/36] drm/tegra: Atomic conversion, phase 2 Thierry Reding
2015-01-20 10:48 ` [PATCH 24/36] drm/tegra: Atomic conversion, phase 3, step 1 Thierry Reding
2015-01-20 10:48 ` [PATCH 25/36] drm/tegra: dc: Store clock setup in atomic state Thierry Reding
2015-01-20 10:48 ` [PATCH 26/36] drm/tegra: rgb: Implement ->atomic_check() Thierry Reding
2015-01-20 10:48 ` Thierry Reding [this message]
2015-01-20 10:48 ` [PATCH 28/36] drm/tegra: hdmi: " Thierry Reding
2015-01-20 10:48 ` [PATCH 29/36] drm/tegra: sor: " Thierry Reding
2015-01-20 10:48 ` [PATCH 30/36] drm/tegra: dc: Use atomic clock state in modeset Thierry Reding
2015-01-20 10:48 ` [PATCH 31/36] drm/tegra: Atomic conversion, phase 3, step 2 Thierry Reding
2015-01-20 10:48 ` [PATCH 32/36] drm/tegra: Atomic conversion, phase 3, step 3 Thierry Reding
2015-01-20 10:48 ` [PATCH 33/36] drm/tegra: Remove unused ->mode_fixup() callbacks Thierry Reding
2015-01-20 10:48 ` [PATCH 34/36] drm/tegra: Track active planes in CRTC state Thierry Reding
2015-01-20 11:18   ` Daniel Vetter
2015-01-20 11:43     ` Thierry Reding
2015-01-23  9:31   ` [PATCH v2] " Thierry Reding
2015-01-20 10:48 ` [PATCH 35/36] drm/tegra: Track tiling and format in plane state Thierry Reding
2015-01-20 10:48 ` [PATCH 36/36] drm/tegra: dc: Unify enabling the display controller Thierry Reding

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1421750935-4023-28-git-send-email-thierry.reding@gmail.com \
    --to=thierry.reding@gmail.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-tegra@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

Powered by JetHome