diff mbox

[2/2] drm/sti: support interlaced top / bottom field first

Message ID 1455269165-1564-3-git-send-email-vincent.abriou@st.com (mailing list archive)
State New, archived
Headers show

Commit Message

Vincent Abriou Feb. 12, 2016, 9:26 a.m. UTC
From: Fabien Dessenne <fabien.dessenne@st.com>

Support top field first and bottom field first interlaced buffers

Signed-off-by: Fabien Dessenne <fabien.dessenne@st.com>
---
 drivers/gpu/drm/sti/sti_hqvdp.c | 72 +++++++++++++++++++++++++----------------
 1 file changed, 44 insertions(+), 28 deletions(-)
diff mbox

Patch

diff --git a/drivers/gpu/drm/sti/sti_hqvdp.c b/drivers/gpu/drm/sti/sti_hqvdp.c
index e9c33fb..e024c13 100644
--- a/drivers/gpu/drm/sti/sti_hqvdp.c
+++ b/drivers/gpu/drm/sti/sti_hqvdp.c
@@ -325,7 +325,7 @@  struct sti_hqvdp_cmd {
  * @clk_pix_main:      pix main clock
  * @reset:             reset control
  * @vtg_nb:            notifier to handle VTG Vsync
- * @btm_field_pending: is there any bottom field (interlaced frame) to display
+ * @nxt_field_pending: is there any other field (interlaced frame) to display
  * @hqvdp_cmd:         buffer of commands
  * @hqvdp_cmd_paddr:   physical address of hqvdp_cmd
  * @vtg:               vtg for main data path
@@ -340,7 +340,7 @@  struct sti_hqvdp {
 	struct clk *clk_pix_main;
 	struct reset_control *reset;
 	struct notifier_block vtg_nb;
-	bool btm_field_pending;
+	bool nxt_field_pending;
 	void *hqvdp_cmd;
 	dma_addr_t hqvdp_cmd_paddr;
 	struct sti_vtg *vtg;
@@ -784,7 +784,7 @@  static void sti_hqvdp_disable(struct sti_hqvdp *hqvdp)
  * @evt: event message
  * @data: private data
  *
- * Handle VTG Vsync event, display pending bottom field
+ * Handle VTG Vsync event, display next field
  *
  * RETURNS:
  * 0 on success.
@@ -792,8 +792,8 @@  static void sti_hqvdp_disable(struct sti_hqvdp *hqvdp)
 int sti_hqvdp_vtg_cb(struct notifier_block *nb, unsigned long evt, void *data)
 {
 	struct sti_hqvdp *hqvdp = container_of(nb, struct sti_hqvdp, vtg_nb);
-	int btm_cmd_offset, top_cmd_offest;
-	struct sti_hqvdp_cmd *btm_cmd, *top_cmd;
+	int next_cmd_offset, curr_cmd_offest;
+	struct sti_hqvdp_cmd *next_cmd, *curr_cmd;
 
 	if ((evt != VTG_TOP_FIELD_EVENT) && (evt != VTG_BOTTOM_FIELD_EVENT)) {
 		DRM_DEBUG_DRIVER("Unknown event\n");
@@ -808,31 +808,41 @@  int sti_hqvdp_vtg_cb(struct notifier_block *nb, unsigned long evt, void *data)
 		sti_hqvdp_disable(hqvdp);
 	}
 
-	if (hqvdp->btm_field_pending) {
-		/* Create the btm field command from the current one */
-		btm_cmd_offset = sti_hqvdp_get_free_cmd(hqvdp);
-		top_cmd_offest = sti_hqvdp_get_curr_cmd(hqvdp);
-		if ((btm_cmd_offset == -1) || (top_cmd_offest == -1)) {
+	if (hqvdp->nxt_field_pending) {
+		/* Create the next field command from the current one */
+		next_cmd_offset = sti_hqvdp_get_free_cmd(hqvdp);
+		curr_cmd_offest = sti_hqvdp_get_curr_cmd(hqvdp);
+		if ((next_cmd_offset == -1) || (curr_cmd_offest == -1)) {
 			DRM_DEBUG_DRIVER("Warning: no cmd, will skip field\n");
 			return -EBUSY;
 		}
 
-		btm_cmd = hqvdp->hqvdp_cmd + btm_cmd_offset;
-		top_cmd = hqvdp->hqvdp_cmd + top_cmd_offest;
-
-		memcpy(btm_cmd, top_cmd, sizeof(*btm_cmd));
-
-		btm_cmd->top.config = TOP_CONFIG_INTER_BTM;
-		btm_cmd->top.current_luma +=
-				btm_cmd->top.luma_src_pitch / 2;
-		btm_cmd->top.current_chroma +=
-				btm_cmd->top.chroma_src_pitch / 2;
+		next_cmd = hqvdp->hqvdp_cmd + next_cmd_offset;
+		curr_cmd = hqvdp->hqvdp_cmd + curr_cmd_offest;
+
+		memcpy(next_cmd, curr_cmd, sizeof(*next_cmd));
+
+		if (curr_cmd->top.config == TOP_CONFIG_INTER_TOP) {
+			/* Display the bottom field now */
+			next_cmd->top.config = TOP_CONFIG_INTER_BTM;
+			next_cmd->top.current_luma +=
+					next_cmd->top.luma_src_pitch / 2;
+			next_cmd->top.current_chroma +=
+					next_cmd->top.chroma_src_pitch / 2;
+		} else {
+			/* Display the top field now */
+			next_cmd->top.config = TOP_CONFIG_INTER_TOP;
+			next_cmd->top.current_luma -=
+					next_cmd->top.luma_src_pitch / 2;
+			next_cmd->top.current_chroma -=
+					next_cmd->top.chroma_src_pitch / 2;
+		}
 
 		/* Post the command to mailbox */
-		writel(hqvdp->hqvdp_cmd_paddr + btm_cmd_offset,
-				hqvdp->regs + HQVDP_MBX_NEXT_CMD);
+		writel(hqvdp->hqvdp_cmd_paddr + next_cmd_offset,
+		       hqvdp->regs + HQVDP_MBX_NEXT_CMD);
 
-		hqvdp->btm_field_pending = false;
+		hqvdp->nxt_field_pending = false;
 
 		dev_dbg(hqvdp->dev, "%s Posted command:0x%x\n",
 				__func__, hqvdp->hqvdp_cmd_paddr);
@@ -1077,7 +1087,7 @@  static int sti_hqvdp_atomic_check(struct drm_plane *drm_plane,
 			return -EINVAL;
 		}
 
-		/* Register VTG Vsync callback to handle bottom fields */
+		/* Register VTG Vsync callback to handle bottom/top fields */
 		if (sti_vtg_register_client(hqvdp->vtg,
 					    &hqvdp->vtg_nb,
 					    crtc)) {
@@ -1175,8 +1185,14 @@  static void sti_hqvdp_atomic_update(struct drm_plane *drm_plane,
 
 	/* Handle interlaced */
 	if (fb->flags & DRM_MODE_FB_INTERLACED) {
-		/* Top field to display */
-		cmd->top.config = TOP_CONFIG_INTER_TOP;
+		/* Top or bottom field */
+		if (fb->flags & DRM_MODE_FB_BFF) {
+			cmd->top.config = TOP_CONFIG_INTER_BTM;
+			cmd->top.current_luma += cmd->top.luma_src_pitch;
+			cmd->top.current_chroma += cmd->top.chroma_src_pitch;
+		} else {
+			cmd->top.config = TOP_CONFIG_INTER_TOP;
+		}
 
 		/* Update pitches and vert size */
 		cmd->top.input_frame_size = (src_h / 2) << 16 | src_w;
@@ -1201,9 +1217,9 @@  static void sti_hqvdp_atomic_update(struct drm_plane *drm_plane,
 	writel(hqvdp->hqvdp_cmd_paddr + cmd_offset,
 	       hqvdp->regs + HQVDP_MBX_NEXT_CMD);
 
-	/* Interlaced : get ready to display the bottom field at next Vsync */
+	/* Interlaced : get ready to display the next field at next Vsync */
 	if (fb->flags & DRM_MODE_FB_INTERLACED)
-		hqvdp->btm_field_pending = true;
+		hqvdp->nxt_field_pending = true;
 
 	dev_dbg(hqvdp->dev, "%s Posted command:0x%x\n",
 		__func__, hqvdp->hqvdp_cmd_paddr + cmd_offset);