diff options
author | Alexei Shlychkov <x0177296@ti.com> | 2012-07-12 11:13:55 -0700 |
---|---|---|
committer | Ziyann <jaraidaniel@gmail.com> | 2014-10-01 13:00:52 +0200 |
commit | e8f4f54fc9d41b938205a384ab8fde661b9dd126 (patch) | |
tree | 39ae347749284e78d065652eb789d6353e189561 /drivers/misc | |
parent | 8d130955e675f415cfd543a8ef3ed78f1dbabc3d (diff) | |
download | kernel_samsung_tuna-e8f4f54fc9d41b938205a384ab8fde661b9dd126.zip kernel_samsung_tuna-e8f4f54fc9d41b938205a384ab8fde661b9dd126.tar.gz kernel_samsung_tuna-e8f4f54fc9d41b938205a384ab8fde661b9dd126.tar.bz2 |
gcx: rotation fixes.
Fixed 90/270 degree rotation.
Fixed clipping for multi-source setup.
Fixed thread racing condition.
Also adds 8-pixel source stride check.
Change-Id: If718d8b84565ea5da4c48e6387c4e41242c4dff7
Signed-off-by: Alexei Shlychkov <x0177296@ti.com>
Diffstat (limited to 'drivers/misc')
-rw-r--r-- | drivers/misc/gcx/gcbv/gcbv.c | 85 | ||||
-rw-r--r-- | drivers/misc/gcx/gccore/gcmmu.c | 24 | ||||
-rw-r--r-- | drivers/misc/gcx/gccore/gcqueue.c | 84 | ||||
-rw-r--r-- | drivers/misc/gcx/gccore/gcqueue.h | 7 |
4 files changed, 116 insertions, 84 deletions
diff --git a/drivers/misc/gcx/gcbv/gcbv.c b/drivers/misc/gcx/gcbv/gcbv.c index f08f67b..e183a7c 100644 --- a/drivers/misc/gcx/gcbv/gcbv.c +++ b/drivers/misc/gcx/gcbv/gcbv.c @@ -2674,6 +2674,7 @@ static enum bverror parse_destination(struct bvbltparams *bltparams, if ((batch->batchflags & BVBATCH_DST) != 0) { struct bvbuffdesc *dstdesc; struct bvsurfgeom *dstgeom; + unsigned int stridealign; /* Make shortcuts to the destination objects. */ dstdesc = bltparams->dstdesc; @@ -2683,7 +2684,7 @@ static enum bverror parse_destination(struct bvbltparams *bltparams, switch (dstgeom->format) { case OCDFMT_NV12: BVSETBLTERROR(BVERR_DSTGEOM_FORMAT, - "destination format unsupported"); + "destination format unsupported"); goto exit; default: @@ -2706,10 +2707,12 @@ static enum bverror parse_destination(struct bvbltparams *bltparams, goto exit; } - /* Destination must be 16 byte aligned */ - if (dstgeom->virtstride & 15) { + /* Destination stride must be 8 pixel aligned. */ + stridealign = batch->dstformat->bitspp - 1; + if ((dstgeom->virtstride & stridealign) != 0) { BVSETBLTERROR(BVERR_DSTGEOM_STRIDE, - "destination stride must be 16 byte aligned"); + "destination stride must be 8 pixel " + "aligned."); goto exit; } @@ -2825,6 +2828,7 @@ static enum bverror parse_source(struct bvbltparams *bltparams, struct bvbuffdesc *srcdesc; struct bvsurfgeom *srcgeom; struct bvrect *srcrect; + unsigned int stridealign; /* Make shortcuts to the source objects. */ srcdesc = srcinfo->buf.desc; @@ -2838,7 +2842,7 @@ static enum bverror parse_source(struct bvbltparams *bltparams, BVSETBLTERROR((srcinfo->index == 0) ? BVERR_SRC1GEOM_FORMAT : BVERR_SRC2GEOM_FORMAT, - "invalid source #%d format (%d)", + "invalid source #%d format (%d).", srcinfo->index + 1, srcgeom->format); goto exit; @@ -2849,25 +2853,19 @@ static enum bverror parse_source(struct bvbltparams *bltparams, BVSETBLTERROR((srcinfo->index == 0) ? BVERR_SRC1GEOM : BVERR_SRC2GEOM, - "source%d geom exceeds surface size", + "source%d geom exceeds surface size.", srcinfo->index + 1); goto exit; } - /* Format specific stride check */ - switch (srcgeom->format) { - case OCDFMT_NV12: - case OCDFMT_UYVY: - case OCDFMT_YUY2: - if (srcgeom->virtstride & 15) { - BVSETBLTERROR(BVERR_SRC1GEOM_STRIDE, - "stride must be 16 byte aligned for yuv"); - goto exit; - } - break; - - default: - break; + /* Source must be 8 pixel aligned. */ + stridealign = srcinfo->format->bitspp - 1; + if ((srcgeom->virtstride & stridealign) != 0) { + BVSETBLTERROR((srcinfo->index == 0) + ? BVERR_SRC1GEOM_STRIDE + : BVERR_SRC2GEOM_STRIDE, + "source stride must be 8 pixel aligned."); + goto exit; } /* Parse orientation. */ @@ -3241,6 +3239,7 @@ static enum bverror do_blit(struct bvbltparams *bltparams, int dstleft, dsttop, dstright, dstbottom; int srcsurfwidth, srcsurfheight; unsigned int physwidth, physheight; + int orthogonal; int multisrc; GCENTER(GCZONE_DO_BLIT); @@ -3263,12 +3262,20 @@ static enum bverror do_blit(struct bvbltparams *bltparams, * Determine source surface alignment offset. */ + /* Determine whether the source and the destination are orthogonal + * to each other. */ + orthogonal = (srcinfo->angle % 2) != (batch->dstangle % 2); + /* Compute adjusted destination rectangle. */ dstleft = batch->clippedleft + batch->dstoffsetX; dsttop = batch->clippedtop + batch->dstoffsetY; dstright = batch->clippedright + batch->dstoffsetX; dstbottom = batch->clippedbottom + batch->dstoffsetY; + /* Compute clipped source origin. */ + srcleft = srcrect->left + batch->deltaleft; + srctop = srcrect->top + batch->deltatop; + GCDBG(GCZONE_SURF, "adjusted dstrect = (%d,%d)-(%d,%d), %dx%d\n", dstleft, dsttop, dstright, dstbottom, dstright - dstleft, dstbottom - dsttop); @@ -3276,27 +3283,27 @@ static enum bverror do_blit(struct bvbltparams *bltparams, /* Compute the source surface shift. */ switch (srcinfo->angle) { case ROT_ANGLE_0: - srcshiftX = srcrect->left - dstleft; - srcshiftY = srcrect->top - dsttop; + srcshiftX = srcleft - dstleft; + srcshiftY = srctop - dsttop; break; case ROT_ANGLE_90: - srcshiftX = srcrect->top - dsttop; - srcshiftY = (srcgeom->width - srcrect->left) + srcshiftX = srctop - dsttop; + srcshiftY = (srcgeom->width - srcleft) - (batch->dstwidth - dstleft); break; case ROT_ANGLE_180: - srcshiftX = (srcgeom->width - srcrect->left) + srcshiftX = (srcgeom->width - srcleft) - (batch->dstwidth - dstleft); - srcshiftY = (srcgeom->height - srcrect->top) + srcshiftY = (srcgeom->height - srctop) - (batch->dstheight - dsttop); break; case ROT_ANGLE_270: - srcshiftX = (srcgeom->height - srcrect->top) + srcshiftX = (srcgeom->height - srctop) - (batch->dstheight - dsttop); - srcshiftY = srcrect->left - dstleft; + srcshiftY = srcleft - dstleft; break; default: @@ -3351,8 +3358,8 @@ static enum bverror do_blit(struct bvbltparams *bltparams, dstalign); if ((srcformat->format == GCREG_DE_FORMAT_NV12) || - (dstalign != 0) || - ((srcalign != 0) && (srcinfo->angle == batch->dstangle))) { + (dstalign != 0) || + ((srcalign != 0) && (srcinfo->angle == batch->dstangle))) { /* Compute the source offset in pixels needed to compensate * for the surface base address misalignment if any. */ srcalign = get_pixeloffset(srcdesc, srcformat, 0); @@ -3369,10 +3376,6 @@ static enum bverror do_blit(struct bvbltparams *bltparams, GCDBG(GCZONE_SURF, " dstsurf offset (bytes) = 0x%08X\n", dstbyteshift); - /* Compute the source origin. */ - srcleft = srcrect->left + batch->deltaleft; - srctop = srcrect->top + batch->deltatop; - switch (srcinfo->angle) { case ROT_ANGLE_0: /* Adjust left coordinate. */ @@ -3490,8 +3493,13 @@ static enum bverror do_blit(struct bvbltparams *bltparams, } /* Source geometry is now the same as the destination. */ - srcsurfwidth = physwidth; - srcsurfheight = physheight; + if (orthogonal) { + srcsurfwidth = physheight; + srcsurfheight = physwidth; + } else { + srcsurfwidth = physwidth; + srcsurfheight = physheight; + } /* Enable multi-source. */ multisrc = 1; @@ -3567,9 +3575,8 @@ static enum bverror do_blit(struct bvbltparams *bltparams, */ /* We need to walk in blocks if the source and the destination - * surfaces are perpendicular to each other. */ - if ((srcinfo->angle % 2) != (batch->dstangle % 2)) - batch->blockenable = 1; + * surfaces are orthogonal to each other. */ + batch->blockenable = orthogonal; /* Allocate command buffer. */ bverror = claim_buffer(bltparams, batch, diff --git a/drivers/misc/gcx/gccore/gcmmu.c b/drivers/misc/gcx/gccore/gcmmu.c index 508ed93..7c5a671 100644 --- a/drivers/misc/gcx/gccore/gcmmu.c +++ b/drivers/misc/gcx/gccore/gcmmu.c @@ -73,7 +73,10 @@ static void event_enable_mmu(struct gcevent *gcevent, unsigned int *flags) /* After MMU command buffer is processed, FE will stop. * Let the control thread know that FE needs to be restarted. */ - *flags |= GC_CMDBUF_START_FE; + if (flags == NULL) + GCERR("flags are not set.\n"); + else + *flags |= GC_CMDBUF_START_FE; GCEXIT(GCZONE_INIT); } @@ -622,18 +625,18 @@ enum gcerror gcmmu_enable(struct gccorecontext *gccorecontext, if (gcerror != GCERR_NONE) goto fail; - /* Attach records. */ - list_add_tail(&gcevent->link, &gccmdbuf->events); - list_add(&gccmdbuf->link, &gcqueue->queue); - - /* Initialize the event and add to the list. */ - gcevent->handler = event_enable_mmu; - /* Get free interrupt. */ gcerror = gcqueue_alloc_int(gcqueue, &gccmdbuf->interrupt); if (gcerror != GCERR_NONE) goto fail; + /* Initialize the event and add to the list. */ + gcevent->handler = event_enable_mmu; + + /* Attach records. */ + list_add_tail(&gcevent->link, &gccmdbuf->events); + list_add(&gccmdbuf->link, &gcqueue->queue); + /* Program the safe zone and the master table address. */ gcmommuinit = (struct gcmommuinit *) gcmmu->cmdbuflog; gcmommuinit->safe_ldst = gcmommuinit_safe_ldst; @@ -669,8 +672,11 @@ enum gcerror gcmmu_enable(struct gccorecontext *gccorecontext, return GCERR_NONE; fail: + if (gcevent != NULL) + gcqueue_free_event(gcqueue, gcevent); + if (gccmdbuf != NULL) - gcqueue_free_cmdbuf(gcqueue, gccmdbuf); + gcqueue_free_cmdbuf(gcqueue, gccmdbuf, NULL); GCEXITARG(GCZONE_CONTEXT, "gcerror = 0x%08X\n", gcerror); return gcerror; diff --git a/drivers/misc/gcx/gccore/gcqueue.c b/drivers/misc/gcx/gccore/gcqueue.c index 9ceb563..725429d 100644 --- a/drivers/misc/gcx/gccore/gcqueue.c +++ b/drivers/misc/gcx/gccore/gcqueue.c @@ -184,6 +184,19 @@ exit: return gcerror; } +enum gcerror gcqueue_free_event(struct gcqueue *gcqueue, + struct gcevent *gcevent) +{ + GCENTER(GCZONE_EVENT); + + GCLOCK(&gcqueue->vaceventlock); + list_move(&gcevent->link, &gcqueue->vacevents); + GCUNLOCK(&gcqueue->vaceventlock); + + GCEXIT(GCZONE_EVENT); + return GCERR_NONE; +} + enum gcerror gcqueue_alloc_cmdbuf(struct gcqueue *gcqueue, struct gccmdbuf **gccmdbuf) { @@ -224,15 +237,30 @@ exit: return gcerror; } -void gcqueue_free_cmdbuf(struct gcqueue *gcqueue, struct gccmdbuf *gccmdbuf) +void gcqueue_free_cmdbuf(struct gcqueue *gcqueue, + struct gccmdbuf *gccmdbuf, + unsigned int *flags) { + struct list_head *head; + struct gcevent *gcevent; + GCENTERARG(GCZONE_QUEUE, "queue entry = 0x%08X\n", (unsigned int) gccmdbuf); - /* Move all event entries to the vacant list. */ - GCLOCK(&gcqueue->vaceventlock); - list_splice_init(&gccmdbuf->events, &gcqueue->vacevents); - GCUNLOCK(&gcqueue->vaceventlock); + /* Have events? */ + if (!list_empty(&gccmdbuf->events)) { + /* Events not expected? */ + if (flags == NULL) + GCERR("buffer has events.\n"); + + /* Execute and free all events. */ + while (!list_empty(&gccmdbuf->events)) { + head = gccmdbuf->events.next; + gcevent = list_entry(head, struct gcevent, link); + gcevent->handler(gcevent, flags); + gcqueue_free_event(gcqueue, gcevent); + } + } /* Move the queue entry to the vacant list. */ GCLOCK(&gcqueue->vacqueuelock); @@ -515,7 +543,6 @@ static int gccmdthread(void *_gccorecontext) unsigned int i, triggered, ints2process, intmask; struct list_head *head; struct gccmdbuf *headcmdbuf; - struct gcevent *gcevent; unsigned int flags; unsigned int dmapc, pc1, pc2; @@ -605,11 +632,8 @@ static int gccmdthread(void *_gccorecontext) GCDBG(GCZONE_THREAD, "buffer has no interrupt.\n"); - if (!list_empty(&headcmdbuf->events)) - GCERR("buffer has events.\n"); - /* Free the entry. */ - gcqueue_free_cmdbuf(gcqueue, headcmdbuf); + gcqueue_free_cmdbuf(gcqueue, headcmdbuf, NULL); continue; } @@ -641,16 +665,8 @@ static int gccmdthread(void *_gccorecontext) /* Free the interrupt. */ free_interrupt(gcqueue, headcmdbuf->interrupt); - /* Execute events if any. */ - list_for_each(head, &headcmdbuf->events) { - gcevent = list_entry(head, - struct gcevent, - link); - gcevent->handler(gcevent, &flags); - } - - /* Free the entry. */ - gcqueue_free_cmdbuf(gcqueue, headcmdbuf); + /* Execute events if any and free the entry. */ + gcqueue_free_cmdbuf(gcqueue, headcmdbuf, &flags); } GCUNLOCK(&gcqueue->queuelock); @@ -669,14 +685,9 @@ static int gccmdthread(void *_gccorecontext) struct gccmdbuf, link); - list_for_each(head, &headcmdbuf->events) { - gcevent = list_entry(head, - struct gcevent, - link); - gcevent->handler(gcevent, &flags); - } - - gcqueue_free_cmdbuf(gcqueue, headcmdbuf); + /* Execute events if any and free the entry. */ + gcqueue_free_cmdbuf(gcqueue, headcmdbuf, + &flags); } GCUNLOCK(&gcqueue->queuelock); @@ -774,6 +785,8 @@ static int gccmdthread(void *_gccorecontext) * in progress or scheduled. */ timeout = msecs_to_jiffies(GC_TIMEOUT); } else { + GCLOCK(&gcqueue->queuelock); + GCDBG(GCZONE_THREAD, "timedout while waiting for ready signal.\n"); @@ -801,18 +814,17 @@ static int gccmdthread(void *_gccorecontext) GCDBG(GCZONE_THREAD, "execution finished, shutting down.\n"); - GCLOCK(&gcqueue->queuelock); - /* Free the queue. */ while (!list_empty(&gcqueue->queue)) { head = gcqueue->queue.next; headcmdbuf = list_entry(head, struct gccmdbuf, link); - gcqueue_free_cmdbuf(gcqueue, headcmdbuf); - } - GCUNLOCK(&gcqueue->queuelock); + /* Free the entry. */ + gcqueue_free_cmdbuf(gcqueue, headcmdbuf, + NULL); + } /* Convert WAIT to END. */ gcqueue->gcmoterminator->u2.end.cmd.raw @@ -831,6 +843,8 @@ static int gccmdthread(void *_gccorecontext) /* Set timeout to infinity. */ timeout = MAX_SCHEDULE_TIMEOUT; + + GCUNLOCK(&gcqueue->queuelock); } } @@ -1022,14 +1036,14 @@ enum gcerror gcqueue_stop(struct gccorecontext *gccorecontext) while (!list_empty(&gcqueue->cmdbufhead)) { head = gcqueue->cmdbufhead.next; gccmdbuf = list_entry(head, struct gccmdbuf, link); - gcqueue_free_cmdbuf(gcqueue, gccmdbuf); + gcqueue_free_cmdbuf(gcqueue, gccmdbuf, NULL); } /* Free command queue entries. */ while (!list_empty(&gcqueue->queue)) { head = gcqueue->queue.next; gccmdbuf = list_entry(head, struct gccmdbuf, link); - gcqueue_free_cmdbuf(gcqueue, gccmdbuf); + gcqueue_free_cmdbuf(gcqueue, gccmdbuf, NULL); } /* Free vacant entry lists. */ diff --git a/drivers/misc/gcx/gccore/gcqueue.h b/drivers/misc/gcx/gccore/gcqueue.h index a695c6f..8b7e409 100644 --- a/drivers/misc/gcx/gccore/gcqueue.h +++ b/drivers/misc/gcx/gccore/gcqueue.h @@ -210,9 +210,14 @@ enum gcerror gcqueue_execute(struct gccorecontext *gccorecontext, enum gcerror gcqueue_alloc_event(struct gcqueue *gcqueue, struct gcevent **gcevent); +enum gcerror gcqueue_free_event(struct gcqueue *gcqueue, + struct gcevent *gcevent); + enum gcerror gcqueue_alloc_cmdbuf(struct gcqueue *gcqueue, struct gccmdbuf **gccmdbuf); -void gcqueue_free_cmdbuf(struct gcqueue *gcqueue, struct gccmdbuf *gccmdbuf); +void gcqueue_free_cmdbuf(struct gcqueue *gcqueue, + struct gccmdbuf *gccmdbuf, + unsigned int *flags); enum gcerror gcqueue_alloc_int(struct gcqueue *gcqueue, unsigned int *interrupt); |