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