Add interrupt-driven waitqueue for better GPU synchronisation
authorThomas White <taw@bitwiz.org.uk>
Mon, 9 Nov 2009 23:06:38 +0000 (00:06 +0100)
committerThomas White <taw@bitwiz.org.uk>
Sun, 15 Nov 2009 13:24:28 +0000 (14:24 +0100)
Signed-off-by: Thomas White <taw@bitwiz.org.uk>
13 files changed:
drivers/mfd/glamo/Makefile
drivers/mfd/glamo/glamo-buffer.c
drivers/mfd/glamo/glamo-cmdq.c
drivers/mfd/glamo/glamo-cmdq.h
drivers/mfd/glamo/glamo-core.c
drivers/mfd/glamo/glamo-core.h
drivers/mfd/glamo/glamo-display.c
drivers/mfd/glamo/glamo-drm-drv.c
drivers/mfd/glamo/glamo-drm-private.h
drivers/mfd/glamo/glamo-fence.c [new file with mode: 0644]
drivers/mfd/glamo/glamo-fence.h [new file with mode: 0644]
drivers/mfd/glamo/glamo-kms-fb.c
drivers/mfd/glamo/glamo-regs.h

index 155427c..fb37517 100644 (file)
@@ -13,4 +13,4 @@ obj-$(CONFIG_MFD_GLAMO_MCI)           += glamo-mci.o
 obj-$(CONFIG_MFD_GLAMO_DRM)            += glamo-drm.o
 
 glamo-drm-objs :=  glamo-drm-drv.o glamo-cmdq.o glamo-buffer.o \
-                    glamo-display.o glamo-kms-fb.o
+                    glamo-display.o glamo-kms-fb.o glamo-fence.o
index a6d085f..2bf9fb5 100644 (file)
@@ -151,8 +151,8 @@ int glamodrm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
                       PAGE_SHIFT;
 
        mutex_lock(&dev->struct_mutex);
-       pfn = ((gdrm->vram->start + gobj->block->start) >> PAGE_SHIFT)
-              + page_offset;
+       pfn = ((gdrm->vram->start + GLAMO_OFFSET_FB + gobj->block->start)
+              >> PAGE_SHIFT) + page_offset;
        ret = vm_insert_pfn(vma, (unsigned long)vmf->virtual_address, pfn);
        mutex_unlock(&dev->struct_mutex);
 
@@ -346,6 +346,19 @@ int glamo_buffer_init(struct glamodrm_handle *gdrm)
 {
        gdrm->mmgr = drm_calloc(1, sizeof(struct drm_mm), DRM_MEM_DRIVER);
        drm_mm_init(gdrm->mmgr, 0, gdrm->vram_size);
+
+       /* Reserve a scratch buffer.  We do this outside the protections
+        * of the other GEM code.  To do this safely, the allocation must
+        * be a multiple of PAGE_SIZE. */
+       gdrm->scratch = drm_mm_search_free(gdrm->mmgr, PAGE_SIZE, 4, 1);
+       if ( gdrm->scratch ) {
+               gdrm->scratch = drm_mm_get_block(gdrm->scratch, PAGE_SIZE, 4);
+       }
+       if ( !gdrm->scratch ) {
+               printk(KERN_WARNING "[glamo-drm] Couldn't allocate"
+                                   " scratch buffer!\n");
+       }
+
        return 0;
 }
 
index 215017d..f3dcc83 100644 (file)
@@ -51,8 +51,6 @@
  */
 
 
-#include <linux/irq.h>
-#include <linux/interrupt.h>
 #include <drm/drmP.h>
 #include <drm/glamo_drm.h>
 
@@ -93,34 +91,9 @@ static u32 glamo_get_write(struct glamodrm_handle *gdrm)
 }
 
 
-static void glamo_enable_cmdq_irq(struct glamodrm_handle *gdrm)
-{
-       uint16_t irq_status = reg_read(gdrm, GLAMO_REG_IRQ_ENABLE);
-       irq_status |= GLAMO_IRQ_CMDQUEUE;
-       reg_write(gdrm, GLAMO_REG_IRQ_ENABLE, irq_status);
-}
-
-
-static void glamo_set_cmdq_irq(struct glamodrm_handle *gdrm)
-{
-       uint16_t irq_status = reg_read(gdrm, GLAMO_REG_IRQ_SET);
-       irq_status |= GLAMO_IRQ_CMDQUEUE;
-       reg_write(gdrm, GLAMO_REG_IRQ_SET, irq_status);
-}
-
-
-static void glamo_cmdq_irq(unsigned int irq, struct irq_desc *desc)
-{
-       struct glamodrm_handle *gdrm = desc->handler_data;
-
-       if (!gdrm) return;
-       reg_write(gdrm, GLAMO_REG_IRQ_CLEAR, GLAMO_IRQ_CMDQUEUE);
-}
-
-
 /* Add commands to the ring buffer */
-static int glamo_add_to_ring(struct glamodrm_handle *gdrm, u16 *addr,
-                             unsigned int count)
+int glamo_add_to_ring(struct glamodrm_handle *gdrm, u16 *addr,
+                      unsigned int count)
 {
        size_t ring_write, ring_read;
        size_t new_ring_write;
@@ -323,8 +296,6 @@ int glamo_ioctl_cmdbuf(struct drm_device *dev, void *data,
 
        glamo_add_to_ring(gdrm, cmds, count);
 
-       glamo_set_cmdq_irq(gdrm);
-
 cleanup:
        drm_free(cmds, 1, DRM_MEM_DRIVER);
 
@@ -472,7 +443,6 @@ int glamo_ioctl_cmdburst(struct drm_device *dev, void *data,
 
        /* Add to command queue */
        glamo_add_to_ring(gdrm, burst, burst_size);
-       glamo_set_cmdq_irq(gdrm);
 
 cleanup:
        drm_free(burst, 1, DRM_MEM_DRIVER);
@@ -481,53 +451,6 @@ cleanup:
 }
 
 
-/* TODO: Banish this to the nether regions of Hades */
-static void glamo_cmdq_wait(struct glamodrm_handle *gdrm,
-                            enum glamo_engine engine)
-{
-       u16 mask, val, status;
-       int i;
-
-       switch (engine)
-       {
-               case GLAMO_ENGINE_ALL:
-                       mask = 1 << 2;
-                       val  = mask;
-                       break;
-               default:
-                       return;
-       }
-
-       for ( i=0; i<1000; i++ ) {
-               status = reg_read(gdrm, GLAMO_REG_CMDQ_STATUS);
-               if ((status & mask) == val) break;
-               mdelay(1);
-       }
-       if ( i == 1000 ) {
-               size_t ring_read;
-               printk(KERN_WARNING "[glamo-drm] CmdQ timeout!\n");
-               printk(KERN_WARNING "[glamo-drm] status = %x\n", status);
-               ring_read = reg_read(gdrm, GLAMO_REG_CMDQ_READ_ADDRL);
-               ring_read |= ((reg_read(gdrm, GLAMO_REG_CMDQ_READ_ADDRH)
-                               & 0x7) << 16);
-               printk(KERN_INFO "[glamo-drm] ring_read now 0x%x\n",
-                                ring_read);
-       }
-}
-
-
-int glamo_ioctl_gem_wait_rendering(struct drm_device *dev, void *data,
-                                   struct drm_file *file_priv)
-{
-       struct glamodrm_handle *gdrm;
-
-       gdrm = dev->dev_private;
-       glamo_cmdq_wait(gdrm, GLAMO_ENGINE_ALL);
-
-       return 0;
-}
-
-
 int glamo_cmdq_init(struct glamodrm_handle *gdrm)
 {
        unsigned int i;
@@ -561,19 +484,12 @@ int glamo_cmdq_init(struct glamodrm_handle *gdrm)
                                         5 << 8  |   /* no interrupt */
                                         8 << 4);    /* HQ threshold */
 
-       /* Set up IRQ */
-       set_irq_handler(IRQ_GLAMO(GLAMO_IRQIDX_CMDQUEUE), glamo_cmdq_irq);
-       set_irq_data(IRQ_GLAMO(GLAMO_IRQIDX_CMDQUEUE), gdrm);
-
-       glamo_enable_cmdq_irq(gdrm);
-
        return 0;
 }
 
 
 int glamo_cmdq_shutdown(struct glamodrm_handle *gdrm)
 {
-       set_irq_handler(IRQ_GLAMO(GLAMO_IRQIDX_CMDQUEUE), handle_level_irq);
        return 0;
 }
 
index d5a00e6..510d195 100644 (file)
@@ -35,8 +35,6 @@ extern int glamo_ioctl_cmdbuf(struct drm_device *dev, void *data,
                              struct drm_file *file_priv);
 extern int glamo_ioctl_cmdburst(struct drm_device *dev, void *data,
                                struct drm_file *file_priv);
-extern int glamo_ioctl_gem_wait_rendering(struct drm_device *dev, void *data,
-                                          struct drm_file *file_priv);
 extern void glamo_cmdq_blank(struct glamodrm_handle *gdrm,
                              struct drm_gem_object *obj);
 
@@ -45,4 +43,7 @@ extern int glamo_cmdq_shutdown(struct glamodrm_handle *gdrm);
 extern void glamo_cmdq_suspend(struct glamodrm_handle *gdrm);
 extern void glamo_cmdq_resume(struct glamodrm_handle *gdrm);
 
+extern int glamo_add_to_ring(struct glamodrm_handle *gdrm, u16 *addr,
+                             unsigned int count);
+
 #endif /* __GLAMO_CMDQ_H */
index d8ebf40..3dcb358 100644 (file)
@@ -198,6 +198,11 @@ static struct resource glamo_graphics_resources[] = {
                .start  = GLAMO_REGOFS_LCD,
                .end    = GLAMO_REGOFS_MMC - 1,
                .flags  = IORESOURCE_MEM,
+       }, {
+               .name   = "glamo-2d-regs",
+               .start  = GLAMO_REGOFS_2D,
+               .end    = GLAMO_REGOFS_3D- 1,
+               .flags  = IORESOURCE_MEM,
        }
 };
 
@@ -349,6 +354,24 @@ static void glamo_irq_demux_handler(unsigned int irq, struct irq_desc *desc)
 }
 
 
+void glamo_clear_irq(struct glamo_core *glamo, unsigned int irq)
+{
+       /* set interrupt source */
+       __reg_write(glamo, GLAMO_REG_IRQ_CLEAR, irq);
+}
+
+
+void glamo_enable_irq(struct glamo_core *glamo, unsigned int irq)
+{
+       u_int16_t tmp;
+
+       /* set bit in enable register */
+       tmp = __reg_read(glamo, GLAMO_REG_IRQ_ENABLE);
+       tmp |= irq;
+       __reg_write(glamo, GLAMO_REG_IRQ_ENABLE, tmp);
+}
+
+
 static ssize_t regs_write(struct device *dev, struct device_attribute *attr,
                           const char *buf, size_t count)
 {
index 4808ad7..1fe16df 100644 (file)
@@ -100,6 +100,9 @@ void glamo_engine_reset(struct glamo_core *glamo, enum glamo_engine engine);
 int glamo_engine_reclock(struct glamo_core *glamo,
                         enum glamo_engine engine, int ps);
 
+extern void glamo_clear_irq(struct glamo_core *glamo, unsigned int irq);
+extern void glamo_enable_irq(struct glamo_core *glamo, unsigned int irq);
+
 void glamo_engine_clkreg_set(struct glamo_core *glamo,
                             enum glamo_engine engine,
                             u_int16_t mask, u_int16_t val);
index 4b91a9a..f3bab3a 100644 (file)
@@ -214,7 +214,8 @@ static struct glamo_script lcd_init_script[] = {
           * np cpu if, 9bit serial data, sclk rising edge latch data
           * 01 00 0 100 0 000 01 0 0 */
        /* The following values assume 640*480@16bpp */
-       { GLAMO_REG_LCD_A_BASE1, 0x0000 }, /* display A base address 15:0 */
+       /* FIXME: fb0 has not yet been allocated! */
+       { GLAMO_REG_LCD_A_BASE1, PAGE_SIZE }, /* display A base address 15:0 */
        { GLAMO_REG_LCD_A_BASE2, 0x0000 }, /* display A base address 22:16 */
        { GLAMO_REG_LCD_B_BASE1, 0x6000 }, /* display B base address 15:0 */
        { GLAMO_REG_LCD_B_BASE2, 0x0009 }, /* display B base address 22:16 */
index c0c5c05..6b78ea7 100644 (file)
@@ -35,6 +35,7 @@
 #include "glamo-drm-private.h"
 #include "glamo-display.h"
 #include "glamo-kms-fb.h"
+#include "glamo-fence.h"
 
 #define DRIVER_AUTHOR           "Openmoko, Inc."
 #define DRIVER_NAME             "glamo-drm"
@@ -72,7 +73,7 @@ struct drm_ioctl_desc glamo_ioctls[] = {
        DRM_IOCTL_DEF(DRM_GLAMO_GEM_PREAD, glamo_ioctl_gem_pread, DRM_AUTH),
        DRM_IOCTL_DEF(DRM_GLAMO_GEM_PWRITE, glamo_ioctl_gem_pwrite, DRM_AUTH),
        DRM_IOCTL_DEF(DRM_GLAMO_GEM_WAIT_RENDERING,
-                               glamo_ioctl_gem_wait_rendering, DRM_AUTH),
+                     glamo_ioctl_wait_rendering, DRM_AUTH),
 };
 
 
@@ -130,6 +131,7 @@ static int glamodrm_load(struct drm_device *dev, unsigned long flags)
 
        glamo_buffer_init(gdrm);
        glamo_cmdq_init(gdrm);
+       glamo_fence_init(gdrm);
        glamo_display_init(dev);
 
        return 0;
@@ -145,6 +147,7 @@ static int glamodrm_unload(struct drm_device *dev)
        glamo_engine_disable(gdrm->glamo_core, GLAMO_ENGINE_2D);
        glamo_engine_disable(gdrm->glamo_core, GLAMO_ENGINE_3D);
        glamo_buffer_final(gdrm);
+       glamo_fence_shutdown(gdrm);
 
        return 0;
 }
@@ -285,6 +288,28 @@ static int glamodrm_probe(struct platform_device *pdev)
                goto out_release_lcd;
        }
 
+       /* Find the 2D engine */
+       gdrm->twod_regs = platform_get_resource(pdev, IORESOURCE_MEM, 4);
+       if ( !gdrm->twod_regs ) {
+               dev_err(&pdev->dev, "Unable to find 2D registers.\n");
+               rc = -ENOENT;
+               goto out_unmap_lcd;
+       }
+       gdrm->twod_regs = request_mem_region(gdrm->twod_regs->start,
+                                           RESSIZE(gdrm->twod_regs),
+                                           pdev->name);
+       if ( !gdrm->twod_regs ) {
+               dev_err(&pdev->dev, "failed to request 2D registers\n");
+               rc = -ENOENT;
+               goto out_unmap_lcd;
+       }
+       gdrm->twod_base = ioremap(gdrm->twod_regs->start, RESSIZE(gdrm->twod_regs));
+       if ( !gdrm->twod_base ) {
+               dev_err(&pdev->dev, "failed to ioremap() 2D registers\n");
+               rc = -ENOENT;
+               goto out_release_2d;
+       }
+
        gdrm->vram_size = GLAMO_FB_SIZE;
        printk(KERN_INFO "[glamo-drm] %lli bytes of VRAM\n",
                         (long long int)gdrm->vram_size);
@@ -294,6 +319,10 @@ static int glamodrm_probe(struct platform_device *pdev)
 
        return 0;
 
+out_release_2d:
+       release_mem_region(gdrm->twod_regs->start, RESSIZE(gdrm->twod_regs));
+out_unmap_lcd:
+       iounmap(gdrm->lcd_base);
 out_release_lcd:
        release_mem_region(gdrm->lcd_regs->start, RESSIZE(gdrm->lcd_regs));
 out_unmap_cmdq:
@@ -332,10 +361,14 @@ static int glamodrm_remove(struct platform_device *pdev)
 //     iounmap(gdrm->vram_base);
        release_mem_region(gdrm->vram->start, RESSIZE(gdrm->vram));
 
-       /* Release command queue  */
+       /* Release command queue */
        iounmap(gdrm->cmdq_base);
        release_mem_region(gdrm->cmdq->start, RESSIZE(gdrm->cmdq));
 
+       /* Release 2D engine  */
+       iounmap(gdrm->twod_base);
+       release_mem_region(gdrm->twod_regs->start, RESSIZE(gdrm->twod_regs));
+
        kfree(gdrm);
 
        return 0;
index 7b6ae21..02ae7e9 100644 (file)
@@ -31,6 +31,8 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/semaphore.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
 
 #include "glamo-core.h"
 
@@ -66,6 +68,10 @@ struct glamodrm_handle {
        struct resource *lcd_regs;
        char __iomem *lcd_base;
 
+       /* 2D engine registers */
+       struct resource *twod_regs;
+       char __iomem *twod_base;
+
        ssize_t vram_size;
 
        /* Memory management */
@@ -89,6 +95,16 @@ struct glamodrm_handle {
        u_int16_t saved_vrtren;
        u_int16_t saved_vdspst;
        u_int16_t saved_vdspen;
+
+       /* Fencing */
+       atomic_t curr_seq;              /* The last used stamp number */
+       struct list_head fence_list;    /* List of active fences */
+       rwlock_t fence_list_lock;       /* Lock to protect fence_list */
+       wait_queue_head_t fence_queue;  /* Waitqueue */
+       struct tasklet_struct fence_tl; /* Tasklet for fence IRQ */
+
+       /* A scratch block */
+       struct drm_mm_node *scratch;
 };
 
 
diff --git a/drivers/mfd/glamo/glamo-fence.c b/drivers/mfd/glamo/glamo-fence.c
new file mode 100644 (file)
index 0000000..2222b23
--- /dev/null
@@ -0,0 +1,352 @@
+/*
+ * SMedia Glamo 336x/337x fence objects
+ *
+ * Copyright (c) 2009 Thomas White <taw@bitwiz.org.uk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Loosely based on radeon_fence.c, to which the following notice applies:
+ *
+ * Copyright 2009 Jerome Glisse.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ */
+/*
+ * Authors:
+ *    Jerome Glisse <glisse@freedesktop.org>
+ *    Dave Airlie
+ */
+
+
+#include <drm/drmP.h>
+#include <drm/glamo_drm.h>
+#include <linux/kernel.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/lockdep.h>
+
+#include "glamo-drm-private.h"
+#include "glamo-regs.h"
+#include "glamo-core.h"
+#include "glamo-cmdq.h"
+
+
+static struct lock_class_key glamo_fence_lock_key;
+
+
+struct glamo_fence
+{
+       struct list_head list;
+       uint16_t               seq;       /* Wait for at least this ID */
+       int                    signalled; /* Non-zero when fence has passed */
+       struct glamodrm_handle *gdrm;
+};
+
+
+static void glamo_fence_emit(struct glamo_fence *fence)
+{
+       u16 fring[26];
+       u32 addr;
+
+       addr = GLAMO_OFFSET_FB + fence->gdrm->scratch->start;
+
+       fring[0] = 0x8000 | GLAMO_REG_2D_DST_X;
+       fring[1] = 11;
+       fring[2] = 0;         /* dest X */
+       fring[3] = 0;         /* dest Y */
+       fring[4] = addr & 0xffff;       /* dest buffer */
+       fring[5] = (addr >> 16) & 0x7f; /* dest buffer */
+       fring[6] = 1;         /* dest pitch */
+       fring[7] = 1;         /* dest height */
+       fring[8] = 1;         /* rect width */
+       fring[9] = 1;         /* rect height */
+       fring[10] = 0x0000;   /* patt L */
+       fring[11] = 0x0000;   /* patt H */
+       fring[12] = 0x0000;   /* FG colour */
+       fring[13] = 0x0000;   /* Padding */
+
+       fring[14] = 0x8000 | GLAMO_REG_2D_COMMAND1;
+       fring[15] = 3;
+       fring[16] = 0x0000;
+       fring[17] = 0xf0 << 8;
+       fring[18] = 0x0000;
+       fring[19] = 0x0000;  /* Padding */
+
+       fring[20] = 0x8000 | GLAMO_REG_2D_ID1;
+       fring[21] = 3;
+       fence->seq = atomic_inc_return(&fence->gdrm->curr_seq);
+       if ( fence->seq > 1<<14 ) {
+               atomic_set(&fence->gdrm->curr_seq, 0);
+               fence->seq = atomic_inc_return(&fence->gdrm->curr_seq);
+       }
+       fring[22] = 1<<15 | fence->seq;
+       fring[23] = 0;  /* Unused */
+       fring[24] = 0;  /* Unused */
+       fring[25] = 0;  /* Padding */
+
+       glamo_add_to_ring(fence->gdrm, fring, 52);
+}
+
+
+static void glamo_fence_enable(struct glamodrm_handle *gdrm)
+{
+       glamo_enable_irq(gdrm->glamo_core, GLAMO_IRQ_2D);
+}
+
+
+static inline u16 reg_read_2d(struct glamodrm_handle *gdrm, u_int16_t reg)
+{
+       /* For command queue, the address is given relative to
+        * the overall base of Glamo.  This isn't the case here. */
+       return ioread16(gdrm->twod_base + reg-GLAMO_REGOFS_2D);
+}
+
+
+static inline u16 reg_read_cmdq(struct glamodrm_handle *gdrm, u_int16_t reg)
+{
+       return ioread16(gdrm->reg_base + reg);
+}
+
+
+static void glamo_cmdq_wait(struct glamodrm_handle *gdrm,
+                            enum glamo_engine engine)
+{
+       u16 mask, val, status;
+       int i;
+
+       switch (engine)
+       {
+               case GLAMO_ENGINE_ALL:
+                       mask = 1 << 2;
+                       val  = mask;
+                       break;
+               default:
+                       return;
+       }
+
+       for ( i=0; i<1000; i++ ) {
+               status = reg_read_cmdq(gdrm, GLAMO_REG_CMDQ_STATUS);
+               if ((status & mask) == val) break;
+               mdelay(1);
+       }
+       if ( i == 1000 ) {
+               size_t ring_read;
+               printk(KERN_WARNING "[glamo-drm] CmdQ timeout!\n");
+               printk(KERN_WARNING "[glamo-drm] status = %x\n", status);
+               ring_read = reg_read_cmdq(gdrm, GLAMO_REG_CMDQ_READ_ADDRL);
+               ring_read |= ((reg_read_cmdq(gdrm, GLAMO_REG_CMDQ_READ_ADDRH)
+                               & 0x7) << 16);
+               printk(KERN_INFO "[glamo-drm] ring_read now 0x%x\n",
+                                ring_read);
+       }
+}
+
+
+static void glamo_fence_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+       struct glamodrm_handle *gdrm = desc->handler_data;
+
+       if (!gdrm) {
+               printk(KERN_ERR "[glamo-drm] 2D IRQ called with no data\n");
+               return;
+       }
+       glamo_clear_irq(gdrm->glamo_core, GLAMO_IRQ_2D);
+
+       tasklet_schedule(&gdrm->fence_tl);
+}
+
+
+/* This is nasty.  I'm sorry. */
+static void glamo_fence_debodge(struct glamodrm_handle *gdrm)
+{
+       struct list_head *tmp;
+
+       printk(KERN_ERR "[glamo-drm] Attempting to recover...\n");
+
+       glamo_cmdq_wait(gdrm, GLAMO_ENGINE_ALL);
+       glamo_engine_reset(gdrm->glamo_core, GLAMO_ENGINE_2D);
+
+       read_lock(&gdrm->fence_list_lock);
+       list_for_each(tmp, &gdrm->fence_list) {
+
+               struct glamo_fence *fence;
+
+               fence = list_entry(tmp, struct glamo_fence, list);
+
+               if ( fence->signalled != 1 ) {
+                       printk(KERN_ERR "[glamo-drm] Fence seq#%i was not"
+                                       " signalled\n", fence->seq);
+               }
+               fence->signalled = 1;
+
+       }
+       read_unlock(&gdrm->fence_list_lock);
+
+       wake_up_all(&gdrm->fence_queue);
+}
+
+
+static void glamo_fence_tl(unsigned long data)
+{
+       struct glamodrm_handle *gdrm = (struct glamodrm_handle *)data;
+       int wake = 0;
+       u16 seq;
+       struct list_head *tmp;
+
+
+       seq = reg_read_2d(gdrm, GLAMO_REG_2D_ID1) & 0x7fff;
+
+       read_lock(&gdrm->fence_list_lock);
+       list_for_each(tmp, &gdrm->fence_list) {
+
+               struct glamo_fence *fence;
+
+               fence = list_entry(tmp, struct glamo_fence, list);
+               if ( seq >= fence->seq ) {
+                       fence->signalled = 1;
+                       wake = 1;
+               }
+
+       }
+       read_unlock(&gdrm->fence_list_lock);
+
+       if ( wake ) wake_up_all(&gdrm->fence_queue);
+}
+
+
+static struct glamo_fence *glamo_fence_new(struct glamodrm_handle *gdrm)
+{
+       struct glamo_fence *fence;
+       unsigned long irq_flags;
+
+       fence = drm_calloc(1, sizeof(*fence), DRM_MEM_DRIVER);
+       fence->signalled = 0;
+       fence->gdrm = gdrm;
+
+       /* Add to list */
+       write_lock_irqsave(&gdrm->fence_list_lock, irq_flags);
+       list_add(&fence->list, &gdrm->fence_list);
+       write_unlock_irqrestore(&gdrm->fence_list_lock, irq_flags);
+
+       return fence;
+}
+
+
+static struct glamo_fence *glamo_fence_destroy(struct glamo_fence *fence)
+{
+       unsigned long irq_flags;
+       struct glamodrm_handle *gdrm = fence->gdrm;
+
+       /* Remove from list */
+       write_lock_irqsave(&gdrm->fence_list_lock, irq_flags);
+       list_del(&fence->list);
+       write_unlock_irqrestore(&gdrm->fence_list_lock, irq_flags);
+
+       drm_free(fence, 1, DRM_MEM_DRIVER);
+
+       return fence;
+}
+
+
+int glamo_ioctl_wait_rendering(struct drm_device *dev, void *data,
+                               struct drm_file *file_priv)
+{
+       struct glamodrm_handle *gdrm;
+       struct drm_glamo_gem_wait_rendering *args = data;
+       struct glamo_fence *fence;
+       int r;
+
+       gdrm = dev->dev_private;
+
+       if ( !args->have_handle ) {
+               glamo_cmdq_wait(gdrm, GLAMO_ENGINE_ALL);
+               return 0;
+       }
+
+       fence = glamo_fence_new(gdrm);
+       if ( fence == NULL ) {
+               printk(KERN_WARNING "[glamo-drm] Couldn't allocate fence -"
+                                   " falling back to busy wait.\n");
+               glamo_cmdq_wait(gdrm, GLAMO_ENGINE_ALL);
+               return 0;
+       }
+
+       glamo_fence_emit(fence);
+
+       /* Wait... */
+       r = wait_event_interruptible_timeout(gdrm->fence_queue,
+                                            fence->signalled, HZ);
+       if ( r == 0 ) {
+               printk(KERN_ERR "[glamo-drm] Timeout!\n");
+               glamo_fence_debodge(gdrm);
+       }
+
+       glamo_fence_destroy(fence);
+
+       return 0;
+}
+
+
+void glamo_fence_init(struct glamodrm_handle *gdrm)
+{
+       unsigned long irq_flags;
+
+       gdrm->fence_list_lock = __RW_LOCK_UNLOCKED(gdrm->fence_list_lock);
+       lockdep_set_class(&gdrm->fence_list_lock, &glamo_fence_lock_key);
+       init_waitqueue_head(&gdrm->fence_queue);
+
+       atomic_set(&gdrm->curr_seq, 0);
+
+       write_lock_irqsave(&gdrm->fence_list_lock, irq_flags);
+       INIT_LIST_HEAD(&gdrm->fence_list);
+       write_unlock_irqrestore(&gdrm->fence_list_lock, irq_flags);
+
+       tasklet_init(&gdrm->fence_tl, glamo_fence_tl, (unsigned long)gdrm);
+
+       /* Set up IRQ */
+       set_irq_handler(IRQ_GLAMO(GLAMO_IRQIDX_2D), glamo_fence_irq_handler);
+       set_irq_data(IRQ_GLAMO(GLAMO_IRQIDX_2D), gdrm);
+
+       glamo_fence_enable(gdrm);
+}
+
+
+void glamo_fence_shutdown(struct glamodrm_handle *gdrm)
+{
+       set_irq_handler(IRQ_GLAMO(GLAMO_IRQIDX_CMDQUEUE), handle_level_irq);
+       wake_up_all(&gdrm->fence_queue);
+       tasklet_kill(&gdrm->fence_tl);
+}
diff --git a/drivers/mfd/glamo/glamo-fence.h b/drivers/mfd/glamo/glamo-fence.h
new file mode 100644 (file)
index 0000000..deda995
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * SMedia Glamo 336x/337x fence objects
+ *
+ * Copyright (c) 2009 Thomas White <taw@bitwiz.org.uk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef __GLAMO_FENCE_H
+#define __GLAMO_FENCE_H
+
+#include <drm/drmP.h>
+
+#include "glamo-drm-private.h"
+
+extern void glamo_fence_init(struct glamodrm_handle *gdrm);
+extern void glamo_fence_shutdown(struct glamodrm_handle *gdrm);
+
+extern int glamo_ioctl_wait_rendering(struct drm_device *dev, void *data,
+                                      struct drm_file *file_priv);
+
+#endif /* __GLAMO_FENCE_H */
index 8fdfb87..61cd605 100644 (file)
@@ -436,7 +436,7 @@ int glamofb_create(struct drm_device *dev, uint32_t fb_width,
        info->flags = FBINFO_DEFAULT;
 
        offs = gobj->block->start;
-       info->screen_base = ioremap(gdrm->vram->start + offs,
+       info->screen_base = ioremap(gdrm->vram->start + offs + GLAMO_OFFSET_FB,
                                    GLAMO_FRAMEBUFFER_ALLOCATION);
        if (!info->screen_base) {
                printk(KERN_ERR "[glamo-drm] Couldn't map framebuffer!\n");
index 738cb64..7876cdf 100644 (file)
@@ -642,4 +642,15 @@ enum glamo_register_cq {
        GLAMO_REG_CMDQ_STATUS         = 0x12,
 };
 
+#define REG_2D(x)              (GLAMO_REGOFS_2D+(x))
+
+enum glamo_register_2d {
+       GLAMO_REG_2D_DST_X              = REG_2D(0x0a),
+       GLAMO_REG_2D_COMMAND1           = REG_2D(0x3a),
+       GLAMO_REG_2D_STATUS             = REG_2D(0x42),
+       GLAMO_REG_2D_ID1                = REG_2D(0x44),
+       GLAMO_REG_2D_ID2                = REG_2D(0x46),
+       GLAMO_REG_2D_ID3                = REG_2D(0x48),
+};
+
 #endif /* _GLAMO_REGS_H */