From: Fabien Dessenne <fabien.desse...@st.com>

Support top field first and bottom field first interlaced buffers

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

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);
-- 
1.9.1

Reply via email to