Commit a3e5f5e2 authored by Ian Armstrong's avatar Ian Armstrong Committed by Mauro Carvalho Chehab

V4L/DVB (6713): ivtv: ivtv_yuv_prep_frame breakup and yuv hardware buffer changes

ivtv_yuv_prep_frame is split in smaller code blocks.

Modified yuv buffer handling on the PVR350 itself. We now cycle through all 8
hardware buffers.

With this patch in place, driver behaviour should remain unchanged from the
existing release.
Signed-off-by: default avatarIan Armstrong <ian@iarmst.demon.co.uk>
Signed-off-by: default avatarHans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@infradead.org>
parent c240ad00
...@@ -697,6 +697,7 @@ static int __devinit ivtv_init_struct1(struct ivtv *itv) ...@@ -697,6 +697,7 @@ static int __devinit ivtv_init_struct1(struct ivtv *itv)
atomic_set(&itv->yuv_info.next_dma_frame, -1); atomic_set(&itv->yuv_info.next_dma_frame, -1);
itv->yuv_info.lace_mode = ivtv_yuv_mode; itv->yuv_info.lace_mode = ivtv_yuv_mode;
itv->yuv_info.lace_threshold = ivtv_yuv_threshold; itv->yuv_info.lace_threshold = ivtv_yuv_threshold;
itv->yuv_info.max_frames_buffered = 3;
return 0; return 0;
} }
......
...@@ -403,6 +403,8 @@ struct yuv_frame_info ...@@ -403,6 +403,8 @@ struct yuv_frame_info
#define IVTV_YUV_SYNC_ODD 0x04 #define IVTV_YUV_SYNC_ODD 0x04
#define IVTV_YUV_SYNC_MASK 0x04 #define IVTV_YUV_SYNC_MASK 0x04
#define IVTV_YUV_BUFFERS 8
struct yuv_playback_info struct yuv_playback_info
{ {
u32 reg_2834; u32 reg_2834;
...@@ -475,11 +477,11 @@ struct yuv_playback_info ...@@ -475,11 +477,11 @@ struct yuv_playback_info
u32 yuv_forced_update; u32 yuv_forced_update;
int update_frame; int update_frame;
int sync_field[4]; /* Field to sync on */ int sync_field[IVTV_YUV_BUFFERS]; /* Field to sync on */
int field_delay[4]; /* Flag to extend duration of previous frame */ int field_delay[IVTV_YUV_BUFFERS]; /* Flag to extend duration of previous frame */
u8 fields_lapsed; /* Counter used when delaying a frame */ u8 fields_lapsed; /* Counter used when delaying a frame */
struct yuv_frame_info new_frame_info[4]; struct yuv_frame_info new_frame_info[IVTV_YUV_BUFFERS];
struct yuv_frame_info old_frame_info; struct yuv_frame_info old_frame_info;
struct yuv_frame_info old_frame_info_args; struct yuv_frame_info old_frame_info_args;
...@@ -487,6 +489,9 @@ struct yuv_playback_info ...@@ -487,6 +489,9 @@ struct yuv_playback_info
dma_addr_t blanking_dmaptr; dma_addr_t blanking_dmaptr;
int stream_size; int stream_size;
u8 draw_frame; /* PVR350 buffer to draw into */
u8 max_frames_buffered; /* Maximum number of frames to buffer */
}; };
#define IVTV_VBI_FRAMES 32 #define IVTV_VBI_FRAMES 32
......
...@@ -744,24 +744,25 @@ static void ivtv_irq_vsync(struct ivtv *itv) ...@@ -744,24 +744,25 @@ static void ivtv_irq_vsync(struct ivtv *itv)
* one vsync per frame. * one vsync per frame.
*/ */
unsigned int frame = read_reg(0x28c0) & 1; unsigned int frame = read_reg(0x28c0) & 1;
struct yuv_playback_info *yi = &itv->yuv_info;
int last_dma_frame = atomic_read(&itv->yuv_info.next_dma_frame); int last_dma_frame = atomic_read(&itv->yuv_info.next_dma_frame);
if (0) IVTV_DEBUG_IRQ("DEC VSYNC\n"); if (0) IVTV_DEBUG_IRQ("DEC VSYNC\n");
if (((frame ^ itv->yuv_info.sync_field[last_dma_frame]) == 0 && if (((frame ^ yi->sync_field[last_dma_frame]) == 0 &&
((itv->last_vsync_field & 1) ^ itv->yuv_info.sync_field[last_dma_frame])) || ((itv->last_vsync_field & 1) ^ yi->sync_field[last_dma_frame])) ||
(frame != (itv->last_vsync_field & 1) && !itv->yuv_info.frame_interlaced)) { (frame != (itv->last_vsync_field & 1) && !yi->frame_interlaced)) {
int next_dma_frame = last_dma_frame; int next_dma_frame = last_dma_frame;
if (!(itv->yuv_info.frame_interlaced && itv->yuv_info.field_delay[next_dma_frame] && itv->yuv_info.fields_lapsed < 1)) { if (!(yi->frame_interlaced && yi->field_delay[next_dma_frame] && yi->fields_lapsed < 1)) {
if (next_dma_frame >= 0 && next_dma_frame != atomic_read(&itv->yuv_info.next_fill_frame)) { if (next_dma_frame >= 0 && next_dma_frame != atomic_read(&yi->next_fill_frame)) {
write_reg(yuv_offset[next_dma_frame] >> 4, 0x82c); write_reg(yuv_offset[next_dma_frame] >> 4, 0x82c);
write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x830); write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x830);
write_reg(yuv_offset[next_dma_frame] >> 4, 0x834); write_reg(yuv_offset[next_dma_frame] >> 4, 0x834);
write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x838); write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x838);
next_dma_frame = (next_dma_frame + 1) & 0x3; next_dma_frame = (next_dma_frame + 1) % IVTV_YUV_BUFFERS;
atomic_set(&itv->yuv_info.next_dma_frame, next_dma_frame); atomic_set(&yi->next_dma_frame, next_dma_frame);
itv->yuv_info.fields_lapsed = -1; yi->fields_lapsed = -1;
} }
} }
} }
...@@ -794,20 +795,20 @@ static void ivtv_irq_vsync(struct ivtv *itv) ...@@ -794,20 +795,20 @@ static void ivtv_irq_vsync(struct ivtv *itv)
} }
/* Check if we need to update the yuv registers */ /* Check if we need to update the yuv registers */
if ((itv->yuv_info.yuv_forced_update || itv->yuv_info.new_frame_info[last_dma_frame].update) && last_dma_frame != -1) { if ((yi->yuv_forced_update || yi->new_frame_info[last_dma_frame].update) && last_dma_frame != -1) {
if (!itv->yuv_info.new_frame_info[last_dma_frame].update) if (!yi->new_frame_info[last_dma_frame].update)
last_dma_frame = (last_dma_frame - 1) & 3; last_dma_frame = (last_dma_frame - 1) & 3;
if (itv->yuv_info.new_frame_info[last_dma_frame].src_w) { if (yi->new_frame_info[last_dma_frame].src_w) {
itv->yuv_info.update_frame = last_dma_frame; yi->update_frame = last_dma_frame;
itv->yuv_info.new_frame_info[last_dma_frame].update = 0; yi->new_frame_info[last_dma_frame].update = 0;
itv->yuv_info.yuv_forced_update = 0; yi->yuv_forced_update = 0;
set_bit(IVTV_F_I_WORK_HANDLER_YUV, &itv->i_flags); set_bit(IVTV_F_I_WORK_HANDLER_YUV, &itv->i_flags);
set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags); set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags);
} }
} }
itv->yuv_info.fields_lapsed ++; yi->fields_lapsed++;
} }
} }
......
...@@ -22,11 +22,16 @@ ...@@ -22,11 +22,16 @@
#include "ivtv-udma.h" #include "ivtv-udma.h"
#include "ivtv-yuv.h" #include "ivtv-yuv.h"
const u32 yuv_offset[4] = { /* YUV buffer offsets */
IVTV_YUV_BUFFER_OFFSET, const u32 yuv_offset[IVTV_YUV_BUFFERS] = {
IVTV_YUV_BUFFER_OFFSET_1, 0x001a8600,
IVTV_YUV_BUFFER_OFFSET_2, 0x00240400,
IVTV_YUV_BUFFER_OFFSET_3 0x002d8200,
0x00370000,
0x00029000,
0x000C0E00,
0x006B0400,
0x00748200
}; };
static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
...@@ -37,10 +42,9 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, ...@@ -37,10 +42,9 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
int i; int i;
int y_pages, uv_pages; int y_pages, uv_pages;
u8 frame = itv->yuv_info.draw_frame;
unsigned long y_buffer_offset, uv_buffer_offset; unsigned long y_buffer_offset, uv_buffer_offset;
int y_decode_height, uv_decode_height, y_size; int y_decode_height, uv_decode_height, y_size;
int frame = atomic_read(&itv->yuv_info.next_fill_frame);
y_buffer_offset = IVTV_DECODER_OFFSET + yuv_offset[frame]; y_buffer_offset = IVTV_DECODER_OFFSET + yuv_offset[frame];
uv_buffer_offset = y_buffer_offset + IVTV_YUV_BUFFER_UV_OFFSET; uv_buffer_offset = y_buffer_offset + IVTV_YUV_BUFFER_UV_OFFSET;
...@@ -954,76 +958,105 @@ static void ivtv_yuv_init (struct ivtv *itv) ...@@ -954,76 +958,105 @@ static void ivtv_yuv_init (struct ivtv *itv)
atomic_set(&yi->next_dma_frame, 0); atomic_set(&yi->next_dma_frame, 0);
} }
int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args) /* Get next available yuv buffer on PVR350 */
void ivtv_yuv_next_free(struct ivtv *itv)
{ {
DEFINE_WAIT(wait); int draw, display;
int rc = 0; struct yuv_playback_info *yi = &itv->yuv_info;
int got_sig = 0;
int frame, next_fill_frame, last_fill_frame;
int register_update = 0;
IVTV_DEBUG_INFO("yuv_prep_frame\n"); if (atomic_read(&yi->next_dma_frame) == -1)
ivtv_yuv_init(itv);
if (atomic_read(&itv->yuv_info.next_dma_frame) == -1) ivtv_yuv_init(itv); draw = atomic_read(&yi->next_fill_frame);
display = atomic_read(&yi->next_dma_frame);
frame = atomic_read(&itv->yuv_info.next_fill_frame); if (display > draw)
next_fill_frame = (frame + 1) & 0x3; display -= IVTV_YUV_BUFFERS;
last_fill_frame = (atomic_read(&itv->yuv_info.next_dma_frame)+1) & 0x3;
if (next_fill_frame != last_fill_frame && last_fill_frame != frame) { if (draw - display >= yi->max_frames_buffered)
/* Buffers are full - Overwrite the last frame */ draw = (u8)(draw - 1) % IVTV_YUV_BUFFERS;
next_fill_frame = frame; else
frame = (frame - 1) & 3; yi->new_frame_info[draw].update = 0;
register_update = itv->yuv_info.new_frame_info[frame].update;
} yi->draw_frame = draw;
}
/* Set up frame according to ivtv_dma_frame parameters */
void ivtv_yuv_setup_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
{
struct yuv_playback_info *yi = &itv->yuv_info;
u8 frame = yi->draw_frame;
/* Preserve old update flag in case we're overwriting a queued frame */
int register_update = yi->new_frame_info[frame].update;
/* Take a snapshot of the yuv coordinate information */ /* Take a snapshot of the yuv coordinate information */
itv->yuv_info.new_frame_info[frame].src_x = args->src.left; yi->new_frame_info[frame].src_x = args->src.left;
itv->yuv_info.new_frame_info[frame].src_y = args->src.top; yi->new_frame_info[frame].src_y = args->src.top;
itv->yuv_info.new_frame_info[frame].src_w = args->src.width; yi->new_frame_info[frame].src_w = args->src.width;
itv->yuv_info.new_frame_info[frame].src_h = args->src.height; yi->new_frame_info[frame].src_h = args->src.height;
itv->yuv_info.new_frame_info[frame].dst_x = args->dst.left; yi->new_frame_info[frame].dst_x = args->dst.left;
itv->yuv_info.new_frame_info[frame].dst_y = args->dst.top; yi->new_frame_info[frame].dst_y = args->dst.top;
itv->yuv_info.new_frame_info[frame].dst_w = args->dst.width; yi->new_frame_info[frame].dst_w = args->dst.width;
itv->yuv_info.new_frame_info[frame].dst_h = args->dst.height; yi->new_frame_info[frame].dst_h = args->dst.height;
itv->yuv_info.new_frame_info[frame].tru_x = args->dst.left; yi->new_frame_info[frame].tru_x = args->dst.left;
itv->yuv_info.new_frame_info[frame].tru_w = args->src_width; yi->new_frame_info[frame].tru_w = args->src_width;
itv->yuv_info.new_frame_info[frame].tru_h = args->src_height; yi->new_frame_info[frame].tru_h = args->src_height;
/* Snapshot field order */ /* Snapshot field order */
itv->yuv_info.sync_field[frame] = itv->yuv_info.lace_sync_field; yi->sync_field[frame] = yi->lace_sync_field;
/* Are we going to offset the Y plane */ /* Are we going to offset the Y plane */
if (args->src.height + args->src.top < 512-16) if (args->src.height + args->src.top < 512-16)
itv->yuv_info.new_frame_info[frame].offset_y = 1; yi->new_frame_info[frame].offset_y = 1;
else else
itv->yuv_info.new_frame_info[frame].offset_y = 0; yi->new_frame_info[frame].offset_y = 0;
/* Snapshot the osd pan info */ /* Snapshot the osd pan info */
itv->yuv_info.new_frame_info[frame].pan_x = itv->yuv_info.osd_x_pan; yi->new_frame_info[frame].pan_x = yi->osd_x_pan;
itv->yuv_info.new_frame_info[frame].pan_y = itv->yuv_info.osd_y_pan; yi->new_frame_info[frame].pan_y = yi->osd_y_pan;
itv->yuv_info.new_frame_info[frame].vis_w = itv->yuv_info.osd_vis_w; yi->new_frame_info[frame].vis_w = yi->osd_vis_w;
itv->yuv_info.new_frame_info[frame].vis_h = itv->yuv_info.osd_vis_h; yi->new_frame_info[frame].vis_h = yi->osd_vis_h;
itv->yuv_info.new_frame_info[frame].update = 0; yi->new_frame_info[frame].update = 0;
itv->yuv_info.new_frame_info[frame].interlaced_y = 0; yi->new_frame_info[frame].interlaced_y = 0;
itv->yuv_info.new_frame_info[frame].interlaced_uv = 0; yi->new_frame_info[frame].interlaced_uv = 0;
itv->yuv_info.new_frame_info[frame].lace_mode = itv->yuv_info.lace_mode; yi->new_frame_info[frame].lace_mode = yi->lace_mode;
if (memcmp (&itv->yuv_info.old_frame_info_args, &itv->yuv_info.new_frame_info[frame], if (memcmp(&yi->old_frame_info_args, &yi->new_frame_info[frame],
sizeof (itv->yuv_info.new_frame_info[frame]))) { sizeof(yi->new_frame_info[frame]))) {
memcpy(&itv->yuv_info.old_frame_info_args, &itv->yuv_info.new_frame_info[frame], sizeof (itv->yuv_info.old_frame_info_args)); yi->old_frame_info_args = yi->new_frame_info[frame];
itv->yuv_info.new_frame_info[frame].update = 1; yi->new_frame_info[frame].update = 1;
/* IVTV_DEBUG_YUV ("Requesting register update for frame %d\n",frame); */ /* IVTV_DEBUG_YUV ("Requesting register update for frame %d\n",frame); */
} }
itv->yuv_info.new_frame_info[frame].update |= register_update; yi->new_frame_info[frame].update |= register_update;
/* Should this frame be delayed ? */ /* Should this frame be delayed ? */
if (itv->yuv_info.sync_field[frame] != itv->yuv_info.sync_field[(frame - 1) & 3]) if (yi->sync_field[frame] !=
itv->yuv_info.field_delay[frame] = 1; yi->sync_field[(frame - 1) % IVTV_YUV_BUFFERS])
yi->field_delay[frame] = 1;
else else
itv->yuv_info.field_delay[frame] = 0; yi->field_delay[frame] = 0;
}
/* Frame is complete & ready for display */
void ivtv_yuv_frame_complete(struct ivtv *itv)
{
atomic_set(&itv->yuv_info.next_fill_frame,
(itv->yuv_info.draw_frame + 1) % IVTV_YUV_BUFFERS);
}
int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
{
DEFINE_WAIT(wait);
int rc = 0;
int got_sig = 0;
IVTV_DEBUG_INFO("yuv_prep_frame\n");
ivtv_yuv_next_free(itv);
ivtv_yuv_setup_frame(itv, args);
/* DMA the frame */ /* DMA the frame */
mutex_lock(&itv->udma.lock); mutex_lock(&itv->udma.lock);
...@@ -1057,7 +1090,7 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args) ...@@ -1057,7 +1090,7 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
return -EINTR; return -EINTR;
} }
atomic_set(&itv->yuv_info.next_fill_frame, next_fill_frame); ivtv_yuv_frame_complete(itv);
mutex_unlock(&itv->udma.lock); mutex_unlock(&itv->udma.lock);
return rc; return rc;
......
...@@ -21,11 +21,6 @@ ...@@ -21,11 +21,6 @@
#ifndef IVTV_YUV_H #ifndef IVTV_YUV_H
#define IVTV_YUV_H #define IVTV_YUV_H
/* Buffers on hardware offsets */
#define IVTV_YUV_BUFFER_OFFSET 0x001a8600 /* First YUV Buffer */
#define IVTV_YUV_BUFFER_OFFSET_1 0x00240400 /* Second YUV Buffer */
#define IVTV_YUV_BUFFER_OFFSET_2 0x002d8200 /* Third YUV Buffer */
#define IVTV_YUV_BUFFER_OFFSET_3 0x00370000 /* Fourth YUV Buffer */
#define IVTV_YUV_BUFFER_UV_OFFSET 0x65400 /* Offset to UV Buffer */ #define IVTV_YUV_BUFFER_UV_OFFSET 0x65400 /* Offset to UV Buffer */
/* Offset to filter table in firmware */ /* Offset to filter table in firmware */
...@@ -36,7 +31,7 @@ ...@@ -36,7 +31,7 @@
#define IVTV_YUV_UPDATE_VERTICAL 0x02 #define IVTV_YUV_UPDATE_VERTICAL 0x02
#define IVTV_YUV_UPDATE_INVALID 0x04 #define IVTV_YUV_UPDATE_INVALID 0x04
extern const u32 yuv_offset[4]; extern const u32 yuv_offset[IVTV_YUV_BUFFERS];
int ivtv_yuv_filter_check(struct ivtv *itv); int ivtv_yuv_filter_check(struct ivtv *itv);
int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args); int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment