diff options
Diffstat (limited to 'drivers/media/video/ivtv/ivtv-yuv.c')
-rw-r--r-- | drivers/media/video/ivtv/ivtv-yuv.c | 149 |
1 files changed, 91 insertions, 58 deletions
diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c index 9091c4837bb..15e9bd2486d 100644 --- a/drivers/media/video/ivtv/ivtv-yuv.c +++ b/drivers/media/video/ivtv/ivtv-yuv.c @@ -22,11 +22,16 @@ #include "ivtv-udma.h" #include "ivtv-yuv.h" -const u32 yuv_offset[4] = { - IVTV_YUV_BUFFER_OFFSET, - IVTV_YUV_BUFFER_OFFSET_1, - IVTV_YUV_BUFFER_OFFSET_2, - IVTV_YUV_BUFFER_OFFSET_3 +/* YUV buffer offsets */ +const u32 yuv_offset[IVTV_YUV_BUFFERS] = { + 0x001a8600, + 0x00240400, + 0x002d8200, + 0x00370000, + 0x00029000, + 0x000C0E00, + 0x006B0400, + 0x00748200 }; 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 y_pages, uv_pages; - + u8 frame = itv->yuv_info.draw_frame; unsigned long y_buffer_offset, uv_buffer_offset; 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]; uv_buffer_offset = y_buffer_offset + IVTV_YUV_BUFFER_UV_OFFSET; @@ -954,76 +958,105 @@ static void ivtv_yuv_init (struct ivtv *itv) 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 rc = 0; - int got_sig = 0; - int frame, next_fill_frame, last_fill_frame; - int register_update = 0; + int draw, display; + struct yuv_playback_info *yi = &itv->yuv_info; - 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); - next_fill_frame = (frame + 1) & 0x3; - last_fill_frame = (atomic_read(&itv->yuv_info.next_dma_frame)+1) & 0x3; + if (display > draw) + display -= IVTV_YUV_BUFFERS; - if (next_fill_frame != last_fill_frame && last_fill_frame != frame) { - /* Buffers are full - Overwrite the last frame */ - next_fill_frame = frame; - frame = (frame - 1) & 3; - register_update = itv->yuv_info.new_frame_info[frame].update; - } + if (draw - display >= yi->max_frames_buffered) + draw = (u8)(draw - 1) % IVTV_YUV_BUFFERS; + else + yi->new_frame_info[draw].update = 0; + + 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 */ - itv->yuv_info.new_frame_info[frame].src_x = args->src.left; - itv->yuv_info.new_frame_info[frame].src_y = args->src.top; - itv->yuv_info.new_frame_info[frame].src_w = args->src.width; - itv->yuv_info.new_frame_info[frame].src_h = args->src.height; - itv->yuv_info.new_frame_info[frame].dst_x = args->dst.left; - itv->yuv_info.new_frame_info[frame].dst_y = args->dst.top; - itv->yuv_info.new_frame_info[frame].dst_w = args->dst.width; - itv->yuv_info.new_frame_info[frame].dst_h = args->dst.height; - itv->yuv_info.new_frame_info[frame].tru_x = args->dst.left; - itv->yuv_info.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].src_x = args->src.left; + yi->new_frame_info[frame].src_y = args->src.top; + yi->new_frame_info[frame].src_w = args->src.width; + yi->new_frame_info[frame].src_h = args->src.height; + yi->new_frame_info[frame].dst_x = args->dst.left; + yi->new_frame_info[frame].dst_y = args->dst.top; + yi->new_frame_info[frame].dst_w = args->dst.width; + yi->new_frame_info[frame].dst_h = args->dst.height; + yi->new_frame_info[frame].tru_x = args->dst.left; + yi->new_frame_info[frame].tru_w = args->src_width; + yi->new_frame_info[frame].tru_h = args->src_height; /* 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 */ 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 - itv->yuv_info.new_frame_info[frame].offset_y = 0; + yi->new_frame_info[frame].offset_y = 0; /* Snapshot the osd pan info */ - itv->yuv_info.new_frame_info[frame].pan_x = itv->yuv_info.osd_x_pan; - itv->yuv_info.new_frame_info[frame].pan_y = itv->yuv_info.osd_y_pan; - itv->yuv_info.new_frame_info[frame].vis_w = itv->yuv_info.osd_vis_w; - itv->yuv_info.new_frame_info[frame].vis_h = itv->yuv_info.osd_vis_h; - - itv->yuv_info.new_frame_info[frame].update = 0; - itv->yuv_info.new_frame_info[frame].interlaced_y = 0; - itv->yuv_info.new_frame_info[frame].interlaced_uv = 0; - itv->yuv_info.new_frame_info[frame].lace_mode = itv->yuv_info.lace_mode; - - if (memcmp (&itv->yuv_info.old_frame_info_args, &itv->yuv_info.new_frame_info[frame], - sizeof (itv->yuv_info.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)); - itv->yuv_info.new_frame_info[frame].update = 1; -/* IVTV_DEBUG_YUV ("Requesting register update for frame %d\n",frame); */ + yi->new_frame_info[frame].pan_x = yi->osd_x_pan; + yi->new_frame_info[frame].pan_y = yi->osd_y_pan; + yi->new_frame_info[frame].vis_w = yi->osd_vis_w; + yi->new_frame_info[frame].vis_h = yi->osd_vis_h; + + yi->new_frame_info[frame].update = 0; + yi->new_frame_info[frame].interlaced_y = 0; + yi->new_frame_info[frame].interlaced_uv = 0; + yi->new_frame_info[frame].lace_mode = yi->lace_mode; + + if (memcmp(&yi->old_frame_info_args, &yi->new_frame_info[frame], + sizeof(yi->new_frame_info[frame]))) { + yi->old_frame_info_args = yi->new_frame_info[frame]; + yi->new_frame_info[frame].update = 1; +/* 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 ? */ - if (itv->yuv_info.sync_field[frame] != itv->yuv_info.sync_field[(frame - 1) & 3]) - itv->yuv_info.field_delay[frame] = 1; + if (yi->sync_field[frame] != + yi->sync_field[(frame - 1) % IVTV_YUV_BUFFERS]) + yi->field_delay[frame] = 1; 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 */ mutex_lock(&itv->udma.lock); @@ -1057,7 +1090,7 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args) return -EINTR; } - atomic_set(&itv->yuv_info.next_fill_frame, next_fill_frame); + ivtv_yuv_frame_complete(itv); mutex_unlock(&itv->udma.lock); return rc; |