diff options
author | Lajos Molnar <molnar@ti.com> | 2011-04-07 08:41:23 +0100 |
---|---|---|
committer | Andy Green <andy.green@linaro.org> | 2011-04-07 08:41:23 +0100 |
commit | ceda3165bc1cf6520cd9247db2cf3d75489e7aa8 (patch) | |
tree | c357f3f75d3decae6d26a54c78284aeabcc6c209 /drivers/media/video/tiler | |
parent | 9698d09c6cc64be204917f48be91a3a67b01501b (diff) |
TILER: Combined dmm and tiler folders and renamed files.
Renamed (and moved around) files in preparation for upstreaming activity.
Also fixed spacing checkpatch errors that are new since the creation of
these files.
Signed-off-by: Lajos Molnar <molnar@ti.com>
Diffstat (limited to 'drivers/media/video/tiler')
-rw-r--r-- | drivers/media/video/tiler/Kconfig | 4 | ||||
-rw-r--r-- | drivers/media/video/tiler/Makefile | 8 | ||||
-rw-r--r-- | drivers/media/video/tiler/dmm.c | 335 | ||||
-rw-r--r-- | drivers/media/video/tiler/tcm.h (renamed from drivers/media/video/tiler/tcm/tcm.h) | 0 | ||||
-rw-r--r-- | drivers/media/video/tiler/tcm/Makefile | 2 | ||||
-rw-r--r-- | drivers/media/video/tiler/tcm/_tcm-sita.h (renamed from drivers/media/video/tiler/tcm/_tcm_sita.h) | 2 | ||||
-rw-r--r-- | drivers/media/video/tiler/tcm/tcm-sita.c (renamed from drivers/media/video/tiler/tcm/tcm_sita.c) | 7 | ||||
-rw-r--r-- | drivers/media/video/tiler/tcm/tcm-sita.h (renamed from drivers/media/video/tiler/tcm/tcm_sita.h) | 2 | ||||
-rw-r--r-- | drivers/media/video/tiler/tcm/tcm-utils.h (renamed from drivers/media/video/tiler/tcm/tcm_utils.h) | 2 | ||||
-rw-r--r-- | drivers/media/video/tiler/tiler-def.h (renamed from drivers/media/video/tiler/tiler_def.h) | 0 | ||||
-rw-r--r-- | drivers/media/video/tiler/tiler-geom.c (renamed from drivers/media/video/tiler/tiler_rot.c) | 2 | ||||
-rw-r--r-- | drivers/media/video/tiler/tiler-main.c (renamed from drivers/media/video/tiler/tiler.c) | 8 | ||||
-rw-r--r-- | drivers/media/video/tiler/tiler-reserve.c (renamed from drivers/media/video/tiler/tiler_pack.c) | 3 | ||||
-rw-r--r-- | drivers/media/video/tiler/tiler-reserve.h (renamed from drivers/media/video/tiler/tiler_pack.h) | 0 | ||||
-rw-r--r-- | drivers/media/video/tiler/tmm-pat.c | 313 | ||||
-rw-r--r-- | drivers/media/video/tiler/tmm.h | 107 |
16 files changed, 777 insertions, 18 deletions
diff --git a/drivers/media/video/tiler/Kconfig b/drivers/media/video/tiler/Kconfig index 09c2215abcf..13570ed9f88 100644 --- a/drivers/media/video/tiler/Kconfig +++ b/drivers/media/video/tiler/Kconfig @@ -8,7 +8,9 @@ menuconfig TI_TILER default y depends on HAVE_TI_TILER help - TILER driver for TI chips. + TILER and TILER-DMM driver for TI chips. The TI TILER device + enables video rotation on certain TI chips such as OMAP4 or + Netra. Video rotation will be limited without TILER support. config TILER_GRANULARITY int "Allocation granularity (2^n)" diff --git a/drivers/media/video/tiler/Makefile b/drivers/media/video/tiler/Makefile index a3933b65743..4a4b48b73ea 100644 --- a/drivers/media/video/tiler/Makefile +++ b/drivers/media/video/tiler/Makefile @@ -1,4 +1,8 @@ obj-$(CONFIG_TI_TILER) += tcm/ -obj-$(CONFIG_TI_TILER) += tiler_omap.o -tiler_omap-objs = tiler.o tiler_pack.o tiler_rot.o + +obj-$(CONFIG_TI_TILER) += tiler.o +tiler-objs = tiler-main.o tiler-reserve.o tiler-geom.o tmm-pat.o + +obj-$(CONFIG_TI_TILER) += tiler_dmm.o +tiler_dmm-objs = dmm.o diff --git a/drivers/media/video/tiler/dmm.c b/drivers/media/video/tiler/dmm.c new file mode 100644 index 00000000000..8663b36a5e7 --- /dev/null +++ b/drivers/media/video/tiler/dmm.c @@ -0,0 +1,335 @@ +/* + * dmm.c + * + * DMM driver support functions for TI OMAP processors. + * + * Copyright (C) 2009-2010 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/cdev.h> /* struct cdev */ +#include <linux/kdev_t.h> /* MKDEV() */ +#include <linux/fs.h> /* register_chrdev_region() */ +#include <linux/device.h> /* struct class */ +#include <linux/platform_device.h> /* platform_device() */ +#include <linux/err.h> /* IS_ERR() */ +#include <linux/io.h> /* ioremap() */ +#include <linux/errno.h> +#include <linux/slab.h> + +#include <mach/dmm.h> + +#undef __DEBUG__ +#define BITS_32(in_NbBits) ((((u32)1 << in_NbBits) - 1) | ((u32)1 << in_NbBits)) +#define BITFIELD_32(in_UpBit, in_LowBit)\ + (BITS_32(in_UpBit) & ~((BITS_32(in_LowBit)) >> 1)) +#define BF BITFIELD_32 + +#ifdef __DEBUG__ +#define DEBUG(x, y) printk(KERN_NOTICE "%s()::%d:%s=(0x%08x)\n", \ + __func__, __LINE__, x, (s32)y); +#else +#define DEBUG(x, y) +#endif + +static s32 dmm_major; +static s32 dmm_minor; + +struct dmm_dev { + struct cdev cdev; +}; + +static struct dmm_dev *dmm_device; +static struct class *dmmdev_class; + +static struct platform_driver dmm_driver_ldm = { + .driver = { + .owner = THIS_MODULE, + .name = "dmm", + }, + .probe = NULL, + .shutdown = NULL, + .remove = NULL, +}; + +s32 dmm_pat_refill(struct dmm *dmm, struct pat *pd, enum pat_mode mode) +{ + void __iomem *r = NULL; + u32 v = -1, w = -1; + + /* Only manual refill supported */ + if (mode != MANUAL) + return -EFAULT; + + /* + * Check that the DMM_PAT_STATUS register + * has not reported an error. + */ + r = (void __iomem *)((u32)dmm->base | DMM_PAT_STATUS__0); + v = __raw_readl(r); + if ((v & 0xFC00) != 0) { + while (1) + printk(KERN_ERR "dmm_pat_refill() error.\n"); + } + + /* Set "next" register to NULL */ + r = (void __iomem *)((u32)dmm->base | DMM_PAT_DESCR__0); + v = __raw_readl(r); + w = (v & (~(BF(31, 4)))) | ((((u32)NULL) << 4) & BF(31, 4)); + __raw_writel(w, r); + + /* Set area to be refilled */ + r = (void __iomem *)((u32)dmm->base | DMM_PAT_AREA__0); + v = __raw_readl(r); + w = (v & (~(BF(30, 24)))) | ((((s8)pd->area.y1) << 24) & BF(30, 24)); + __raw_writel(w, r); + + v = __raw_readl(r); + w = (v & (~(BF(23, 16)))) | ((((s8)pd->area.x1) << 16) & BF(23, 16)); + __raw_writel(w, r); + + v = __raw_readl(r); + w = (v & (~(BF(14, 8)))) | ((((s8)pd->area.y0) << 8) & BF(14, 8)); + __raw_writel(w, r); + + v = __raw_readl(r); + w = (v & (~(BF(7, 0)))) | ((((s8)pd->area.x0) << 0) & BF(7, 0)); + __raw_writel(w, r); + wmb(); + +#ifdef __DEBUG__ + printk(KERN_NOTICE "\nx0=(%d),y0=(%d),x1=(%d),y1=(%d)\n", + (char)pd->area.x0, + (char)pd->area.y0, + (char)pd->area.x1, + (char)pd->area.y1); +#endif + + /* First, clear the DMM_PAT_IRQSTATUS register */ + r = (void __iomem *)((u32)dmm->base | (u32)DMM_PAT_IRQSTATUS); + __raw_writel(0xFFFFFFFF, r); + wmb(); + + r = (void __iomem *)((u32)dmm->base | (u32)DMM_PAT_IRQSTATUS_RAW); + v = 0xFFFFFFFF; + + while (v != 0x0) { + v = __raw_readl(r); + DEBUG("DMM_PAT_IRQSTATUS_RAW", v); + } + + /* Fill data register */ + r = (void __iomem *)((u32)dmm->base | DMM_PAT_DATA__0); + v = __raw_readl(r); + + /* Apply 4 bit left shft to counter the 4 bit right shift */ + w = (v & (~(BF(31, 4)))) | ((((u32)(pd->data >> 4)) << 4) & BF(31, 4)); + __raw_writel(w, r); + wmb(); + + /* Read back PAT_DATA__0 to see if write was successful */ + v = 0x0; + while (v != pd->data) { + v = __raw_readl(r); + DEBUG("DMM_PAT_DATA__0", v); + } + + r = (void __iomem *)((u32)dmm->base | (u32)DMM_PAT_CTRL__0); + v = __raw_readl(r); + + w = (v & (~(BF(31, 28)))) | ((((u32)pd->ctrl.ini) << 28) & BF(31, 28)); + __raw_writel(w, r); + + v = __raw_readl(r); + w = (v & (~(BF(16, 16)))) | ((((u32)pd->ctrl.sync) << 16) & BF(16, 16)); + __raw_writel(w, r); + + v = __raw_readl(r); + w = (v & (~(BF(9, 8)))) | ((((u32)pd->ctrl.lut_id) << 8) & BF(9, 8)); + __raw_writel(w, r); + + v = __raw_readl(r); + w = (v & (~(BF(6, 4)))) | ((((u32)pd->ctrl.dir) << 4) & BF(6, 4)); + __raw_writel(w, r); + + v = __raw_readl(r); + w = (v & (~(BF(0, 0)))) | ((((u32)pd->ctrl.start) << 0) & BF(0, 0)); + __raw_writel(w, r); + wmb(); + + /* + * Now, check if PAT_IRQSTATUS_RAW has been + * set after the PAT has been refilled + */ + r = (void __iomem *)((u32)dmm->base | (u32)DMM_PAT_IRQSTATUS_RAW); + v = 0x0; + while ((v & 0x3) != 0x3) { + v = __raw_readl(r); + DEBUG("DMM_PAT_IRQSTATUS_RAW", v); + } + + /* Again, clear the DMM_PAT_IRQSTATUS register */ + r = (void __iomem *)((u32)dmm->base | (u32)DMM_PAT_IRQSTATUS); + __raw_writel(0xFFFFFFFF, r); + wmb(); + + r = (void __iomem *)((u32)dmm->base | (u32)DMM_PAT_IRQSTATUS_RAW); + v = 0xFFFFFFFF; + + while (v != 0x0) { + v = __raw_readl(r); + DEBUG("DMM_PAT_IRQSTATUS_RAW", v); + } + + /* Again, set "next" register to NULL to clear any PAT STATUS errors */ + r = (void __iomem *)((u32)dmm->base | DMM_PAT_DESCR__0); + v = __raw_readl(r); + w = (v & (~(BF(31, 4)))) | ((((u32)NULL) << 4) & BF(31, 4)); + __raw_writel(w, r); + + /* + * Now, check that the DMM_PAT_STATUS register + * has not reported an error before exiting. + */ + r = (void __iomem *)((u32)dmm->base | DMM_PAT_STATUS__0); + v = __raw_readl(r); + if ((v & 0xFC00) != 0) { + while (1) + printk(KERN_ERR "dmm_pat_refill() error.\n"); + } + + return 0; +} +EXPORT_SYMBOL(dmm_pat_refill); + +static s32 dmm_open(struct inode *ip, struct file *filp) +{ + return 0; +} + +static s32 dmm_release(struct inode *ip, struct file *filp) +{ + return 0; +} + +static const struct file_operations dmm_fops = { + .open = dmm_open, + .release = dmm_release, +}; + +struct dmm *dmm_pat_init(u32 id) +{ + u32 base = 0; + struct dmm *dmm = NULL; + switch (id) { + case 0: + /* only support id 0 for now */ + base = DMM_BASE; + break; + default: + return NULL; + } + + dmm = kmalloc(sizeof(*dmm), GFP_KERNEL); + if (!dmm) + return NULL; + + dmm->base = ioremap(base, DMM_SIZE); + if (!dmm->base) { + kfree(dmm); + return NULL; + } + + __raw_writel(0x88888888, dmm->base + DMM_PAT_VIEW__0); + __raw_writel(0x88888888, dmm->base + DMM_PAT_VIEW__1); + __raw_writel(0x80808080, dmm->base + DMM_PAT_VIEW_MAP__0); + __raw_writel(0x80000000, dmm->base + DMM_PAT_VIEW_MAP_BASE); + __raw_writel(0x88888888, dmm->base + DMM_TILER_OR__0); + __raw_writel(0x88888888, dmm->base + DMM_TILER_OR__1); + + return dmm; +} +EXPORT_SYMBOL(dmm_pat_init); + +/** + * Clean up the physical address translator. + * @param dmm Device data + * @return an error status. + */ +void dmm_pat_release(struct dmm *dmm) +{ + if (dmm) { + iounmap(dmm->base); + kfree(dmm); + } +} +EXPORT_SYMBOL(dmm_pat_release); + +static s32 __init dmm_init(void) +{ + dev_t dev = 0; + s32 r = -1; + struct device *device = NULL; + + if (dmm_major) { + dev = MKDEV(dmm_major, dmm_minor); + r = register_chrdev_region(dev, 1, "dmm"); + } else { + r = alloc_chrdev_region(&dev, dmm_minor, 1, "dmm"); + dmm_major = MAJOR(dev); + } + + dmm_device = kmalloc(sizeof(*dmm_device), GFP_KERNEL); + if (!dmm_device) { + unregister_chrdev_region(dev, 1); + return -ENOMEM; + } + memset(dmm_device, 0x0, sizeof(struct dmm_dev)); + + cdev_init(&dmm_device->cdev, &dmm_fops); + dmm_device->cdev.owner = THIS_MODULE; + dmm_device->cdev.ops = &dmm_fops; + + r = cdev_add(&dmm_device->cdev, dev, 1); + if (r) + printk(KERN_ERR "cdev_add():failed\n"); + + dmmdev_class = class_create(THIS_MODULE, "dmm"); + + if (IS_ERR(dmmdev_class)) { + printk(KERN_ERR "class_create():failed\n"); + goto EXIT; + } + + device = device_create(dmmdev_class, NULL, dev, NULL, "dmm"); + if (device == NULL) + printk(KERN_ERR "device_create() fail\n"); + + r = platform_driver_register(&dmm_driver_ldm); + +EXIT: + return r; +} + +static void __exit dmm_exit(void) +{ + platform_driver_unregister(&dmm_driver_ldm); + cdev_del(&dmm_device->cdev); + kfree(dmm_device); + device_destroy(dmmdev_class, MKDEV(dmm_major, dmm_minor)); + class_destroy(dmmdev_class); +} + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("davidsin@ti.com"); +module_init(dmm_init); +module_exit(dmm_exit); diff --git a/drivers/media/video/tiler/tcm/tcm.h b/drivers/media/video/tiler/tcm.h index 11201674fdc..11201674fdc 100644 --- a/drivers/media/video/tiler/tcm/tcm.h +++ b/drivers/media/video/tiler/tcm.h diff --git a/drivers/media/video/tiler/tcm/Makefile b/drivers/media/video/tiler/tcm/Makefile index d0642102eb8..efd62d77847 100644 --- a/drivers/media/video/tiler/tcm/Makefile +++ b/drivers/media/video/tiler/tcm/Makefile @@ -1,2 +1,2 @@ -obj-$(CONFIG_TI_TILER) += tcm_sita.o +obj-$(CONFIG_TI_TILER) += tcm-sita.o diff --git a/drivers/media/video/tiler/tcm/_tcm_sita.h b/drivers/media/video/tiler/tcm/_tcm-sita.h index 7a7f847e8b4..ef4da6c9ad2 100644 --- a/drivers/media/video/tiler/tcm/_tcm_sita.h +++ b/drivers/media/video/tiler/tcm/_tcm-sita.h @@ -19,7 +19,7 @@ #ifndef _TCM_SITA_H_ #define _TCM_SITA_H_ -#include "tcm.h" +#include "../tcm.h" #define TL_CORNER 0 #define TR_CORNER 1 diff --git a/drivers/media/video/tiler/tcm/tcm_sita.c b/drivers/media/video/tiler/tcm/tcm-sita.c index 0aea8f12be2..2ab5ac59ae2 100644 --- a/drivers/media/video/tiler/tcm/tcm_sita.c +++ b/drivers/media/video/tiler/tcm/tcm-sita.c @@ -18,11 +18,11 @@ */ #include <linux/slab.h> -#include "_tcm_sita.h" -#include "tcm_sita.h" +#include "_tcm-sita.h" +#include "tcm-sita.h" #define TCM_ALG_NAME "tcm_sita" -#include "tcm_utils.h" +#include "tcm-utils.h" #define X_SCAN_LIMITER 1 #define Y_SCAN_LIMITER 1 @@ -1355,4 +1355,3 @@ static s32 move_right(struct tcm *tcm, u16 x, u16 y, u32 num_pages, *yy = pos / pvt->width; return 0; } - diff --git a/drivers/media/video/tiler/tcm/tcm_sita.h b/drivers/media/video/tiler/tcm/tcm-sita.h index cfdf810fc3c..8b6607652bb 100644 --- a/drivers/media/video/tiler/tcm/tcm_sita.h +++ b/drivers/media/video/tiler/tcm/tcm-sita.h @@ -19,7 +19,7 @@ #ifndef TCM_SITA_H_ #define TCM_SITA_H_ -#include "tcm.h" +#include "../tcm.h" /** * Create a SiTA tiler container manager. diff --git a/drivers/media/video/tiler/tcm/tcm_utils.h b/drivers/media/video/tiler/tcm/tcm-utils.h index 7d0ed5c149b..1013929a455 100644 --- a/drivers/media/video/tiler/tcm/tcm_utils.h +++ b/drivers/media/video/tiler/tcm/tcm-utils.h @@ -17,7 +17,7 @@ #ifndef _TCM_UTILS_H #define _TCM_UTILS_H -#include "tcm.h" +#include "../tcm.h" #define AREA_FMT "(%03d %03d)-(%03d %03d)" #define AREA(area) (area).p0.x, (area).p0.y, (area).p1.x, (area).p1.y diff --git a/drivers/media/video/tiler/tiler_def.h b/drivers/media/video/tiler/tiler-def.h index d931e18de15..d931e18de15 100644 --- a/drivers/media/video/tiler/tiler_def.h +++ b/drivers/media/video/tiler/tiler-def.h diff --git a/drivers/media/video/tiler/tiler_rot.c b/drivers/media/video/tiler/tiler-geom.c index aa38d72187d..d85f54cf885 100644 --- a/drivers/media/video/tiler/tiler_rot.c +++ b/drivers/media/video/tiler/tiler-geom.c @@ -17,7 +17,7 @@ #include <linux/init.h> #include <linux/module.h> #include <mach/tiler.h> -#include "tiler_def.h" +#include "tiler-def.h" #define DMM_SHIFT_PER_X_8 0 #define DMM_SHIFT_PER_Y_8 0 diff --git a/drivers/media/video/tiler/tiler.c b/drivers/media/video/tiler/tiler-main.c index 911a039a612..d964b15baad 100644 --- a/drivers/media/video/tiler/tiler.c +++ b/drivers/media/video/tiler/tiler-main.c @@ -35,10 +35,10 @@ #include <asm/mach/map.h> /* for ioremap_page */ #include <mach/tiler.h> #include <mach/dmm.h> -#include "../dmm/tmm.h" -#include "tiler_def.h" -#include "tcm/tcm_sita.h" /* Algo Specific header */ -#include "tiler_pack.h" +#include "tmm.h" +#include "tiler-def.h" +#include "tcm/tcm-sita.h" /* Algo Specific header */ +#include "tiler-reserve.h" #include <linux/syscalls.h> diff --git a/drivers/media/video/tiler/tiler_pack.c b/drivers/media/video/tiler/tiler-reserve.c index 542b789f8f7..ddc6b7d38eb 100644 --- a/drivers/media/video/tiler/tiler_pack.c +++ b/drivers/media/video/tiler/tiler-reserve.c @@ -17,7 +17,7 @@ #include <linux/init.h> #include <linux/module.h> #include <mach/tiler.h> -#include "tiler_def.h" +#include "tiler-def.h" /* we want to find the most effective packing for the smallest area */ @@ -284,4 +284,3 @@ u16 nv12_together(u16 o, u16 w, u16 a, u16 n, u16 *area, u8 *packing) return n_best; } - diff --git a/drivers/media/video/tiler/tiler_pack.h b/drivers/media/video/tiler/tiler-reserve.h index e454b1d240f..e454b1d240f 100644 --- a/drivers/media/video/tiler/tiler_pack.h +++ b/drivers/media/video/tiler/tiler-reserve.h diff --git a/drivers/media/video/tiler/tmm-pat.c b/drivers/media/video/tiler/tmm-pat.c new file mode 100644 index 00000000000..4ffd8ae2b3b --- /dev/null +++ b/drivers/media/video/tiler/tmm-pat.c @@ -0,0 +1,313 @@ +/* + * tmm_pat.c + * + * DMM driver support functions for TI OMAP processors. + * + * Copyright (C) 2009-2010 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ +#include <linux/init.h> +#include <linux/module.h> +#include <linux/mm.h> +#include <linux/mmzone.h> +#include <asm/cacheflush.h> +#include <linux/mutex.h> +#include <linux/list.h> +#include <linux/slab.h> + +#include "tmm.h" + +/** + * Number of pages to allocate when + * refilling the free page stack. + */ +#define MAX 16 +#define DMM_PAGE 0x1000 + +/** + * Used to keep track of mem per + * dmm_get_pages call. + */ +struct fast { + struct list_head list; + struct mem **mem; + u32 *pa; + u32 num; +}; + +/** + * Used to keep track of the page struct ptrs + * and physical addresses of each page. + */ +struct mem { + struct list_head list; + struct page *pg; + u32 pa; +}; + +/** + * TMM PAT private structure + */ +struct dmm_mem { + struct fast fast_list; + struct mem free_list; + struct mem used_list; + struct mutex mtx; + struct dmm *dmm; +}; + +static void dmm_free_fast_list(struct fast *fast) +{ + struct list_head *pos = NULL, *q = NULL; + struct fast *f = NULL; + s32 i = 0; + + /* mutex is locked */ + list_for_each_safe(pos, q, &fast->list) { + f = list_entry(pos, struct fast, list); + for (i = 0; i < f->num; i++) + __free_page(f->mem[i]->pg); + kfree(f->pa); + kfree(f->mem); + list_del(pos); + kfree(f); + } +} + +static u32 fill_page_stack(struct mem *mem, struct mutex *mtx) +{ + s32 i = 0; + struct mem *m = NULL; + + for (i = 0; i < MAX; i++) { + m = kmalloc(sizeof(*m), GFP_KERNEL); + if (!m) + return -ENOMEM; + memset(m, 0x0, sizeof(*m)); + + m->pg = alloc_page(GFP_KERNEL | GFP_DMA); + if (!m->pg) { + kfree(m); + return -ENOMEM; + } + + m->pa = page_to_phys(m->pg); + + /** + * Note: we need to flush the cache + * entry for each page we allocate. + */ + dmac_flush_range((void *)page_address(m->pg), + (void *)page_address(m->pg) + DMM_PAGE); + outer_flush_range(m->pa, m->pa + DMM_PAGE); + + mutex_lock(mtx); + list_add(&m->list, &mem->list); + mutex_unlock(mtx); + } + return 0x0; +} + +static void dmm_free_page_stack(struct mem *mem) +{ + struct list_head *pos = NULL, *q = NULL; + struct mem *m = NULL; + + /* mutex is locked */ + list_for_each_safe(pos, q, &mem->list) { + m = list_entry(pos, struct mem, list); + __free_page(m->pg); + list_del(pos); + kfree(m); + } +} + +static void tmm_pat_deinit(struct tmm *tmm) +{ + struct dmm_mem *pvt = (struct dmm_mem *) tmm->pvt; + + mutex_lock(&pvt->mtx); + dmm_free_fast_list(&pvt->fast_list); + dmm_free_page_stack(&pvt->free_list); + dmm_free_page_stack(&pvt->used_list); + mutex_destroy(&pvt->mtx); +} + +static u32 *tmm_pat_get_pages(struct tmm *tmm, s32 n) +{ + s32 i = 0; + struct list_head *pos = NULL, *q = NULL; + struct mem *m = NULL; + struct fast *f = NULL; + struct dmm_mem *pvt = (struct dmm_mem *) tmm->pvt; + + if (n <= 0 || n > 0x8000) + return NULL; + + if (list_empty_careful(&pvt->free_list.list)) + if (fill_page_stack(&pvt->free_list, &pvt->mtx)) + return NULL; + + f = kmalloc(sizeof(*f), GFP_KERNEL); + if (!f) + return NULL; + memset(f, 0x0, sizeof(*f)); + + /* array of mem struct pointers */ + f->mem = kmalloc(n * sizeof(*f->mem), GFP_KERNEL); + if (!f->mem) { + kfree(f); return NULL; + } + memset(f->mem, 0x0, n * sizeof(*f->mem)); + + /* array of physical addresses */ + f->pa = kmalloc(n * sizeof(*f->pa), GFP_KERNEL); + if (!f->pa) { + kfree(f->mem); kfree(f); return NULL; + } + memset(f->pa, 0x0, n * sizeof(*f->pa)); + + /* + * store the number of mem structs so that we + * know how many to free later. + */ + f->num = n; + + for (i = 0; i < n; i++) { + if (list_empty_careful(&pvt->free_list.list)) + if (fill_page_stack(&pvt->free_list, &pvt->mtx)) + goto cleanup; + + mutex_lock(&pvt->mtx); + pos = NULL; + q = NULL; + + /* + * remove one mem struct from the free list and + * add the address to the fast struct mem array + */ + list_for_each_safe(pos, q, &pvt->free_list.list) { + m = list_entry(pos, struct mem, list); + f->mem[i] = m; + list_del(pos); + break; + } + mutex_unlock(&pvt->mtx); + + if (m != NULL) + f->pa[i] = m->pa; + else + goto cleanup; + } + + mutex_lock(&pvt->mtx); + list_add(&f->list, &pvt->fast_list.list); + mutex_unlock(&pvt->mtx); + + if (f != NULL) + return f->pa; +cleanup: + for (; i > 0; i--) { + mutex_lock(&pvt->mtx); + list_add(&f->mem[i - 1]->list, &pvt->free_list.list); + mutex_unlock(&pvt->mtx); + } + kfree(f->pa); + kfree(f->mem); + kfree(f); + return NULL; +} + +static void tmm_pat_free_pages(struct tmm *tmm, u32 *list) +{ + struct dmm_mem *pvt = (struct dmm_mem *) tmm->pvt; + struct list_head *pos = NULL, *q = NULL; + struct fast *f = NULL; + s32 i = 0; + + mutex_lock(&pvt->mtx); + pos = NULL; + q = NULL; + list_for_each_safe(pos, q, &pvt->fast_list.list) { + f = list_entry(pos, struct fast, list); + if (f->pa[0] == list[0]) { + for (i = 0; i < f->num; i++) { + list_add(&((struct mem *)f->mem[i])->list, + &pvt->free_list.list); + } + list_del(pos); + kfree(f->pa); + kfree(f->mem); + kfree(f); + break; + } + } + mutex_unlock(&pvt->mtx); +} + +static s32 tmm_pat_map(struct tmm *tmm, struct pat_area area, u32 page_pa) +{ + struct dmm_mem *pvt = (struct dmm_mem *) tmm->pvt; + struct pat pat_desc = {0}; + + /* send pat descriptor to dmm driver */ + pat_desc.ctrl.dir = 0; + pat_desc.ctrl.ini = 0; + pat_desc.ctrl.lut_id = 0; + pat_desc.ctrl.start = 1; + pat_desc.ctrl.sync = 0; + pat_desc.area = area; + pat_desc.next = NULL; + + /* must be a 16-byte aligned physical address */ + pat_desc.data = page_pa; + return dmm_pat_refill(pvt->dmm, &pat_desc, MANUAL); +} + +struct tmm *tmm_pat_init(u32 pat_id) +{ + struct tmm *tmm = NULL; + struct dmm_mem *pvt = NULL; + + struct dmm *dmm = dmm_pat_init(pat_id); + if (dmm) + tmm = kmalloc(sizeof(*tmm), GFP_KERNEL); + if (tmm) + pvt = kmalloc(sizeof(*pvt), GFP_KERNEL); + if (pvt) { + /* private data */ + pvt->dmm = dmm; + INIT_LIST_HEAD(&pvt->free_list.list); + INIT_LIST_HEAD(&pvt->used_list.list); + INIT_LIST_HEAD(&pvt->fast_list.list); + mutex_init(&pvt->mtx); + + if (list_empty_careful(&pvt->free_list.list)) + if (fill_page_stack(&pvt->free_list, &pvt->mtx)) + goto error; + + /* public data */ + tmm->pvt = pvt; + tmm->deinit = tmm_pat_deinit; + tmm->get = tmm_pat_get_pages; + tmm->free = tmm_pat_free_pages; + tmm->map = tmm_pat_map; + tmm->clear = NULL; /* not yet supported */ + + return tmm; + } + +error: + kfree(pvt); + kfree(tmm); + dmm_pat_release(dmm); + return NULL; +} +EXPORT_SYMBOL(tmm_pat_init); diff --git a/drivers/media/video/tiler/tmm.h b/drivers/media/video/tiler/tmm.h new file mode 100644 index 00000000000..deaeca51a90 --- /dev/null +++ b/drivers/media/video/tiler/tmm.h @@ -0,0 +1,107 @@ +/* + * tmm.h + * + * TMM interface definition for TI TILER. + * + * Copyright (C) 2009-2010 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ +#ifndef TMM_H +#define TMM_H + +#include <mach/dmm.h> +/** + * TMM interface + */ +struct tmm { + void *pvt; + + /* function table */ + u32 *(*get) (struct tmm *tmm, s32 num_pages); + void (*free) (struct tmm *tmm, u32 *pages); + s32 (*map) (struct tmm *tmm, struct pat_area area, u32 page_pa); + void (*clear) (struct tmm *tmm, struct pat_area area); + void (*deinit) (struct tmm *tmm); +}; + +/** + * Request a set of pages from the DMM free page stack. + * @return a pointer to a list of physical page addresses. + */ +static inline +u32 *tmm_get(struct tmm *tmm, s32 num_pages) +{ + if (tmm && tmm->pvt) + return tmm->get(tmm, num_pages); + return NULL; +} + +/** + * Return a set of used pages to the DMM free page stack. + * @param list a pointer to a list of physical page addresses. + */ +static inline +void tmm_free(struct tmm *tmm, u32 *pages) +{ + if (tmm && tmm->pvt) + tmm->free(tmm, pages); +} + +/** + * Program the physical address translator. + * @param area PAT area + * @param list of pages + */ +static inline +s32 tmm_map(struct tmm *tmm, struct pat_area area, u32 page_pa) +{ + if (tmm && tmm->map && tmm->pvt) + return tmm->map(tmm, area, page_pa); + return -ENODEV; +} + +/** + * Clears the physical address translator. + * @param area PAT area + */ +static inline +void tmm_clear(struct tmm *tmm, struct pat_area area) +{ + if (tmm && tmm->clear && tmm->pvt) + tmm->clear(tmm, area); +} + +/** + * Checks whether tiler memory manager supports mapping + */ +static inline +bool tmm_can_map(struct tmm *tmm) +{ + return tmm && tmm->map; +} + +/** + * Deinitialize tiler memory manager + */ +static inline +void tmm_deinit(struct tmm *tmm) +{ + if (tmm && tmm->pvt) + tmm->deinit(tmm); +} + +/** + * TMM implementation for PAT support. + * + * Initialize TMM for PAT with given id. + */ +struct tmm *tmm_pat_init(u32 pat_id); + +#endif |