* one vsync per frame.
         */
        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);
 
        if (0) IVTV_DEBUG_IRQ("DEC VSYNC\n");
 
-       if (((frame ^ itv->yuv_info.sync_field[last_dma_frame]) == 0 &&
-               ((itv->last_vsync_field & 1) ^ itv->yuv_info.sync_field[last_dma_frame])) ||
-                       (frame != (itv->last_vsync_field & 1) && !itv->yuv_info.frame_interlaced)) {
+       if (((frame ^ yi->sync_field[last_dma_frame]) == 0 &&
+               ((itv->last_vsync_field & 1) ^ yi->sync_field[last_dma_frame])) ||
+                       (frame != (itv->last_vsync_field & 1) && !yi->frame_interlaced)) {
                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 (next_dma_frame >= 0 && next_dma_frame != atomic_read(&itv->yuv_info.next_fill_frame)) {
+               if (!(yi->frame_interlaced && yi->field_delay[next_dma_frame] && yi->fields_lapsed < 1)) {
+                       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] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x830);
                                write_reg(yuv_offset[next_dma_frame] >> 4, 0x834);
                                write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x838);
-                               next_dma_frame = (next_dma_frame + 1) & 0x3;
-                               atomic_set(&itv->yuv_info.next_dma_frame, next_dma_frame);
-                               itv->yuv_info.fields_lapsed = -1;
+                               next_dma_frame = (next_dma_frame + 1) % IVTV_YUV_BUFFERS;
+                               atomic_set(&yi->next_dma_frame, next_dma_frame);
+                               yi->fields_lapsed = -1;
                        }
                }
        }
                }
 
                /* 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 (!itv->yuv_info.new_frame_info[last_dma_frame].update)
+               if ((yi->yuv_forced_update || yi->new_frame_info[last_dma_frame].update) && last_dma_frame != -1) {
+                       if (!yi->new_frame_info[last_dma_frame].update)
                                last_dma_frame = (last_dma_frame - 1) & 3;
 
-                       if (itv->yuv_info.new_frame_info[last_dma_frame].src_w) {
-                               itv->yuv_info.update_frame = last_dma_frame;
-                               itv->yuv_info.new_frame_info[last_dma_frame].update = 0;
-                               itv->yuv_info.yuv_forced_update = 0;
+                       if (yi->new_frame_info[last_dma_frame].src_w) {
+                               yi->update_frame = last_dma_frame;
+                               yi->new_frame_info[last_dma_frame].update = 0;
+                               yi->yuv_forced_update = 0;
                                set_bit(IVTV_F_I_WORK_HANDLER_YUV, &itv->i_flags);
                                set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags);
                        }
                }
 
-               itv->yuv_info.fields_lapsed ++;
+               yi->fields_lapsed++;
        }
 }
 
 
 #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,
 
        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;
        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);
                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;