aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc
diff options
context:
space:
mode:
authorAlexei Shlychkov <x0177296@ti.com>2012-07-12 11:13:55 -0700
committerZiyann <jaraidaniel@gmail.com>2014-10-01 13:00:52 +0200
commite8f4f54fc9d41b938205a384ab8fde661b9dd126 (patch)
tree39ae347749284e78d065652eb789d6353e189561 /drivers/misc
parent8d130955e675f415cfd543a8ef3ed78f1dbabc3d (diff)
downloadkernel_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.c85
-rw-r--r--drivers/misc/gcx/gccore/gcmmu.c24
-rw-r--r--drivers/misc/gcx/gccore/gcqueue.c84
-rw-r--r--drivers/misc/gcx/gccore/gcqueue.h7
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);