Tiling and Isometric Lightweight Engine for Rotation (TILER) driver
Dynamic Memory Manager (DMM) is a hardware block made by Texas Instruments.
Within the DMM exists at least one TILER hardware component. Its purpose is to
organize video/image memory in a 2-dimensional fashion to limit memory
bandwidth and facilitate 0 effort rotation and mirroring. The TILER driver
facilitates allocating, freeing, as well as mapping 2D blocks (areas) in the
TILER container(s). It also facilitates rotating and mirroring the allocated
blocks or its rectangular subsections.
TERMINOLOGY
"slot"
The basic TILER driver operates on blocks of slots. A slot is the granularity
of the TILER hardware device. For all current uses it is 4K, but could also be
16 or 64K. The DMM-TILER TRM refers to this as "page" but we want to separate
this concept from the MMU pages.
"page"
The granularity of the MMU, used by the kernel. This is 4K.
"block"
The TILER hardware component supports 1D and 2D blocks. A 2D block is a
rectangular arrangement of slots with arbitrary width and height in a 2D
container. A 1D block is a linear arrangement of slots with arbitrary length
in a 1D container. This TILER driver only supports 2D blocks.
"container"
The TILER driver supports an arbitrary TILER container size. However, for
all current implementations it is 256 by 128 slots. The container currently can
only be used as a 2D container.
"reserved area"
Each block resides within a reserved area in the container. This area may
be larger than the actual set of slots that a block occupies. The reason for
this is to protect access from one block into another. Since TILER container is
mmap-ped into user space as individual pages, all slots that are spanned by
that page become visible to the user. The tiler driver allows restricting the
granularity of the reserved area (default alignment) as well as the mapped
area (granularity).
Changes made from RFC v1: http://www.spinics.net/lists/linux-omap/msg33867.html
Santosh Shilimkar:
1) Correct documentation location
2) Remove ioremap of RAM
3) Implement probe function and hwmod
4) Correct commenting style
5) Reduce use of barrier instances
Linus Walleij:
1) Define TCM acryonym
Russell King:
1) Implement probe function
2) Fix spelling mistake
3) Remove GFP_ATOMIC flag when calling dma_alloc_coherent for PAT array mem
4) Replace alloc_page and flush range calls with dma_alloc_coherent
Nishanth Menon:
1) Address infinite while loop when reading dmm register
Benoit Cousson:
1) Fix source file headers
2) Correct logical errors in device file
Kevin Hilman:
1) Move DMM/TILER source code into driver/misc/tiler until a recommendation
is made as to where it should go
List of pending items in proposed order:
* Determine driver source code location
(Currently, resides in drivers/misc/tiler)
* Add area packing support (multiple blocks can reside in the same band/area)
to optimize area use
* Add group-ID support (to specify which blocks can reside together in the
same area)
* Add multiple search directions to TCM-SiTA
* Add 1D block support (including adding 1D search algo to TCM-SiTA)
* Optimize mutex handling (don.t hold mutex during memory
allocation/mapping/cache flushing)
* Add block reference counting, support for sharing blocks
* Move all kernel-API-s to tiler-iface.c
* Support orphaned block support (in preparation for process cleanup support)
* Change block identification from physical address to key-ID pair
(in preparation for user space support, and process security)
* Add support for process security (blocks from separate processes never
reside in the same band)
* Support file interface (ioctl and mmap)
* Support for buffers (ordered list of blocks that are mapped to userspace
together, such as YUV420sp)
* Support 1D user buffer mapping into TILER container
* Support for block pre-reservation (to further optimize area use)
David Sin (1):
TILER-DMM: DMM-PAT driver for TI TILER
Lajos Molnar (6):
TILER-DMM: Container manager interface and utility definitons
TILER-DMM: TILER Memory Manager interface and implementation
TILER-DMM: TILER interface file and documentation
TILER-DMM: Geometry and view manipulation functions
TILER-DMM: Main TILER driver implementation
TILER-DMM: Linking TILER driver into the Linux kernel build
Ravi Ramachandra (1):
TILER-DMM: Sample TCM implementation: Simple TILER Allocator (SiTA)
Documentation/arm/OMAP/TILER | 126 +++++++++
arch/arm/mach-omap2/Makefile | 1 +
arch/arm/mach-omap2/dmm-omap44xx.c | 81 ++++++
arch/arm/mach-omap2/include/mach/dmm.h | 92 +++++++
arch/arm/mach-omap2/include/mach/tiler.h | 173 ++++++++++++
drivers/misc/Kconfig | 5 +
drivers/misc/Makefile | 1 +
drivers/misc/tiler/Kconfig | 72 +++++
drivers/misc/tiler/Makefile | 7 +
drivers/misc/tiler/_tiler.h | 48 ++++
drivers/misc/tiler/dmm-main.c | 187 +++++++++++++
drivers/misc/tiler/tcm.h | 171 ++++++++++++
drivers/misc/tiler/tcm/Makefile | 1 +
drivers/misc/tiler/tcm/_tcm-sita.h | 61 +++++
drivers/misc/tiler/tcm/tcm-sita.c | 422 ++++++++++++++++++++++++++++++
drivers/misc/tiler/tcm/tcm-sita.h | 28 ++
drivers/misc/tiler/tcm/tcm-utils.h | 51 ++++
drivers/misc/tiler/tiler-geom.c | 362 +++++++++++++++++++++++++
drivers/misc/tiler/tiler-iface.c | 66 +++++
drivers/misc/tiler/tiler-main.c | 405 ++++++++++++++++++++++++++++
drivers/misc/tiler/tmm-pat.c | 266 +++++++++++++++++++
drivers/misc/tiler/tmm.h | 103 ++++++++
22 files changed, 2729 insertions(+), 0 deletions(-)
create mode 100644 Documentation/arm/OMAP/TILER
create mode 100644 arch/arm/mach-omap2/dmm-omap44xx.c
create mode 100644 arch/arm/mach-omap2/include/mach/dmm.h
create mode 100644 arch/arm/mach-omap2/include/mach/tiler.h
create mode 100644 drivers/misc/tiler/Kconfig
create mode 100644 drivers/misc/tiler/Makefile
create mode 100644 drivers/misc/tiler/_tiler.h
create mode 100644 drivers/misc/tiler/dmm-main.c
create mode 100644 drivers/misc/tiler/tcm.h
create mode 100644 drivers/misc/tiler/tcm/Makefile
create mode 100644 drivers/misc/tiler/tcm/_tcm-sita.h
create mode 100644 drivers/misc/tiler/tcm/tcm-sita.c
create mode 100644 drivers/misc/tiler/tcm/tcm-sita.h
create mode 100644 drivers/misc/tiler/tcm/tcm-utils.h
create mode 100644 drivers/misc/tiler/tiler-geom.c
create mode 100644 drivers/misc/tiler/tiler-iface.c
create mode 100644 drivers/misc/tiler/tiler-main.c
create mode 100644 drivers/misc/tiler/tmm-pat.c
create mode 100644 drivers/misc/tiler/tmm.h
From: Ravi Ramachandra <[email protected]>
This patch implements a simple TILER Container Manager (TCM).
Signed-off-by: Ravi Ramachandra <[email protected]>
Signed-off-by: Lajos Molnar <[email protected]>
Signed-off-by: David Sin <[email protected]>
---
drivers/misc/tiler/tcm/Makefile | 1 +
drivers/misc/tiler/tcm/_tcm-sita.h | 61 +++++
drivers/misc/tiler/tcm/tcm-sita.c | 422 ++++++++++++++++++++++++++++++++++++
drivers/misc/tiler/tcm/tcm-sita.h | 28 +++
4 files changed, 512 insertions(+), 0 deletions(-)
create mode 100644 drivers/misc/tiler/tcm/Makefile
create mode 100644 drivers/misc/tiler/tcm/_tcm-sita.h
create mode 100644 drivers/misc/tiler/tcm/tcm-sita.c
create mode 100644 drivers/misc/tiler/tcm/tcm-sita.h
diff --git a/drivers/misc/tiler/tcm/Makefile b/drivers/misc/tiler/tcm/Makefile
new file mode 100644
index 0000000..8434607
--- /dev/null
+++ b/drivers/misc/tiler/tcm/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_TI_TILER) += tcm-sita.o
diff --git a/drivers/misc/tiler/tcm/_tcm-sita.h b/drivers/misc/tiler/tcm/_tcm-sita.h
new file mode 100644
index 0000000..6e4d292
--- /dev/null
+++ b/drivers/misc/tiler/tcm/_tcm-sita.h
@@ -0,0 +1,61 @@
+/*
+ * SImple Tiler Allocator (SiTA) private structures.
+ *
+ * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _TCM_SITA_H
+#define _TCM_SITA_H
+
+#include "../tcm.h"
+
+/* length between two coordinates */
+#define LEN(a, b) ((a) > (b) ? (a) - (b) + 1 : (b) - (a) + 1)
+
+enum criteria {
+ CR_MAX_NEIGHS = 0x01,
+ CR_FIRST_FOUND = 0x10,
+ CR_BIAS_HORIZONTAL = 0x20,
+ CR_BIAS_VERTICAL = 0x40,
+ CR_DIAGONAL_BALANCE = 0x80
+};
+
+/* nearness to the beginning of the search field from 0 to 1000 */
+struct nearness_factor {
+ s32 x;
+ s32 y;
+};
+
+/*
+ * Statistics on immediately neighboring slots. Edge is the number of
+ * border segments that are also border segments of the scan field. Busy
+ * refers to the number of neighbors that are occupied.
+ */
+struct neighbor_stats {
+ u16 edge;
+ u16 busy;
+};
+
+/* structure to keep the score of a potential allocation */
+struct score {
+ struct nearness_factor f;
+ struct neighbor_stats n;
+ struct tcm_area a;
+ u16 neighs; /* number of busy neighbors */
+};
+
+struct sita_pvt {
+ struct mutex mtx;
+ struct tcm_area ***map; /* pointers to the parent area for each slot */
+};
+
+#endif
diff --git a/drivers/misc/tiler/tcm/tcm-sita.c b/drivers/misc/tiler/tcm/tcm-sita.c
new file mode 100644
index 0000000..a7ceac4
--- /dev/null
+++ b/drivers/misc/tiler/tcm/tcm-sita.c
@@ -0,0 +1,422 @@
+/*
+ * SImple Tiler Allocator (SiTA): 2D and 1D allocation(reservation) algorithm
+ *
+ * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/slab.h>
+
+#include "_tcm-sita.h"
+#include "tcm-sita.h"
+
+#define TCM_ALG_NAME "tcm_sita"
+#include "tcm-utils.h"
+
+#define ALIGN_DOWN(value, align) ((value) & ~((align) - 1))
+
+/* Individual selection criteria for different scan areas */
+static s32 CR_L2R_T2B = CR_BIAS_HORIZONTAL;
+
+/*
+ * TCM API - Sita Implementation
+ */
+static s32 sita_reserve_2d(struct tcm *tcm, u16 h, u16 w, u8 align,
+ struct tcm_area *area);
+static s32 sita_free(struct tcm *tcm, struct tcm_area *area);
+static void sita_deinit(struct tcm *tcm);
+
+/*
+ * Main Scanner functions
+ */
+static s32 scan_areas_and_find_fit(struct tcm *tcm, u16 w, u16 h, u16 align,
+ struct tcm_area *area);
+
+static s32 scan_l2r_t2b(struct tcm *tcm, u16 w, u16 h, u16 align,
+ struct tcm_area *field, struct tcm_area *area);
+
+/*
+ * Support Infrastructure Methods
+ */
+static s32 is_area_free(struct tcm_area ***map, u16 x0, u16 y0, u16 w, u16 h);
+
+static s32 update_candidate(struct tcm *tcm, u16 x0, u16 y0, u16 w, u16 h,
+ struct tcm_area *field, s32 criteria,
+ struct score *best);
+
+static void get_nearness_factor(struct tcm_area *field,
+ struct tcm_area *candidate,
+ struct nearness_factor *nf);
+
+static void get_neighbor_stats(struct tcm *tcm, struct tcm_area *area,
+ struct neighbor_stats *stat);
+
+static void fill_area(struct tcm *tcm,
+ struct tcm_area *area, struct tcm_area *parent);
+
+/*
+ * Utility Methods
+ */
+struct tcm *sita_init(u16 width, u16 height, void *attr)
+{
+ struct tcm *tcm;
+ struct sita_pvt *pvt;
+ struct tcm_area area = {NULL};
+ s32 i;
+
+ if (width == 0 || height == 0)
+ return NULL;
+
+ tcm = kzalloc(sizeof(*tcm), GFP_KERNEL);
+ pvt = kzalloc(sizeof(*pvt), GFP_KERNEL);
+ if (!tcm || !pvt)
+ goto error;
+
+ /* Updating the pointers to SiTA implementation APIs */
+ tcm->height = height;
+ tcm->width = width;
+ tcm->reserve_2d = sita_reserve_2d;
+ tcm->free = sita_free;
+ tcm->deinit = sita_deinit;
+ tcm->pvt = (void *)pvt;
+
+ mutex_init(&(pvt->mtx));
+
+ /* Creating tam map */
+ pvt->map = kzalloc(sizeof(*pvt->map) * tcm->width, GFP_KERNEL);
+ if (!pvt->map)
+ goto error;
+
+ for (i = 0; i < tcm->width; i++) {
+ pvt->map[i] =
+ kzalloc(sizeof(**pvt->map) * tcm->height,
+ GFP_KERNEL);
+ if (pvt->map[i] == NULL) {
+ while (i--)
+ kfree(pvt->map[i]);
+ kfree(pvt->map);
+ goto error;
+ }
+ }
+
+ mutex_lock(&(pvt->mtx));
+ assign(&area, 0, 0, width - 1, height - 1);
+ fill_area(tcm, &area, NULL);
+ mutex_unlock(&(pvt->mtx));
+ return tcm;
+
+error:
+ kfree(tcm);
+ kfree(pvt);
+ return NULL;
+}
+
+static void sita_deinit(struct tcm *tcm)
+{
+ struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
+ struct tcm_area area = {NULL};
+ s32 i;
+
+ area.p1.x = tcm->width - 1;
+ area.p1.y = tcm->height - 1;
+
+ mutex_lock(&(pvt->mtx));
+ fill_area(tcm, &area, NULL);
+ mutex_unlock(&(pvt->mtx));
+
+ mutex_destroy(&(pvt->mtx));
+
+ for (i = 0; i < tcm->height; i++)
+ kfree(pvt->map[i]);
+ kfree(pvt->map);
+ kfree(pvt);
+}
+
+/*
+ * Reserve a 2D area in the container
+ */
+static s32 sita_reserve_2d(struct tcm *tcm, u16 h, u16 w, u8 align,
+ struct tcm_area *area)
+{
+ s32 ret;
+ struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
+
+ /* not supporting more than 64 as alignment */
+ if (align > 64)
+ return -EINVAL;
+
+ /* we prefer 1, 32 and 64 as alignment */
+ align = align <= 1 ? 1 : align <= 32 ? 32 : 64;
+
+ mutex_lock(&(pvt->mtx));
+ ret = scan_areas_and_find_fit(tcm, w, h, align, area);
+ if (!ret)
+ /* update map */
+ fill_area(tcm, area, area);
+
+ mutex_unlock(&(pvt->mtx));
+ return ret;
+}
+
+/*
+ * Unreserve a previously allocated 2D or 1D area
+ */
+static s32 sita_free(struct tcm *tcm, struct tcm_area *area)
+{
+ struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
+
+ mutex_lock(&(pvt->mtx));
+
+ /* Clear the contents of the associated tiles in the map */
+ fill_area(tcm, area, NULL);
+
+ mutex_unlock(&(pvt->mtx));
+
+ return 0;
+}
+
+/*
+ * Note: In general the cordinates in the scan field area relevant to the can
+ * sweep directions. The scan origin (e.g. top-left corner) will always be
+ * the p0 member of the field. Therfore, for a scan from top-left p0.x <= p1.x
+ * and p0.y <= p1.y; whereas, for a scan from bottom-right p1.x <= p0.x and p1.y
+ * <= p0.y
+ */
+
+/*
+ * Raster scan horizontally left to right from top to bottom to find a place for
+ * a 2D area of given size inside a scan field.
+ */
+static s32 scan_l2r_t2b(struct tcm *tcm, u16 w, u16 h, u16 align,
+ struct tcm_area *field, struct tcm_area *area)
+{
+ s32 x, y;
+ s16 start_x, end_x, start_y, end_y;
+ struct tcm_area ***map = ((struct sita_pvt *)tcm->pvt)->map;
+ struct score best = {{0}, {0}, {NULL}, 0};
+
+ PA(2, "scan_l2r_t2b:", field);
+
+ start_x = field->p0.x;
+ end_x = field->p1.x;
+ start_y = field->p0.y;
+ end_y = field->p1.y;
+
+ /* check scan area co-ordinates */
+ if (field->p1.x < field->p0.x ||
+ field->p1.y < field->p0.y)
+ return -EINVAL;
+
+ /* check if allocation would fit in scan area */
+ if (w > LEN(end_x, start_x) || h > LEN(end_y, start_y))
+ return -ENOSPC;
+
+ start_x = ALIGN(start_x, align);
+
+ /* check if allocation would still fit in scan area */
+ if (w > LEN(end_x, start_x))
+ return -ENOSPC;
+
+ /* adjust end_x and end_y, as allocation would not fit beyond */
+ end_x = end_x - w + 1; /* + 1 to be inclusive */
+ end_y = end_y - h + 1;
+
+ P2("ali=%d x=%d..%d y=%d..%d", align, start_x, end_x, start_y, end_y);
+
+ /* scan field top-to-bottom, left-to-right */
+ for (y = start_y; y <= end_y; y++) {
+ for (x = start_x; x <= end_x; x += align) {
+ if (is_area_free(map, x, y, w, h)) {
+ P3("found shoulder: %d,%d", x, y);
+
+ /* update best candidate */
+ if (update_candidate(tcm, x, y, w, h, field,
+ CR_L2R_T2B, &best))
+ goto done;
+ break;
+ } else if (map[x][y]) {
+ /* step over 2D areas */
+ x = ALIGN_DOWN(map[x][y]->p1.x, align);
+ P3("moving to: %d,%d", x, y);
+ }
+ }
+ }
+
+ if (!best.a.tcm)
+ return -ENOSPC;
+done:
+ assign(area, best.a.p0.x, best.a.p0.y, best.a.p1.x, best.a.p1.y);
+ return 0;
+}
+
+/*
+ * Find a place for a 2D area of given size inside a scan field based on its
+ * alignment needs.
+ */
+static s32 scan_areas_and_find_fit(struct tcm *tcm, u16 w, u16 h, u16 align,
+ struct tcm_area *area)
+{
+ struct tcm_area field = {NULL};
+
+ /* scan whole container left to right, top to bottom */
+ assign(&field, 0, 0, tcm->width - 1, tcm->height - 1);
+ return scan_l2r_t2b(tcm, w, h, align, &field, area);
+}
+
+/* check if an entire area is free */
+static s32 is_area_free(struct tcm_area ***map, u16 x0, u16 y0, u16 w, u16 h)
+{
+ u16 x = 0, y = 0;
+ for (y = y0; y < y0 + h; y++) {
+ for (x = x0; x < x0 + w; x++) {
+ if (map[x][y])
+ return false;
+ }
+ }
+ return true;
+}
+
+/* fills an area with a parent tcm_area */
+static void fill_area(struct tcm *tcm, struct tcm_area *area,
+ struct tcm_area *parent)
+{
+ s32 x, y;
+ struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
+
+ PA(2, "fill 2d area", area);
+ for (x = area->p0.x; x <= area->p1.x; ++x)
+ for (y = area->p0.y; y <= area->p1.y; ++y)
+ pvt->map[x][y] = parent;
+}
+
+/*
+ * Compares a candidate area to the current best area, and if it is a better
+ * fit, it updates the best to this one. Return 1 (true) if the candidate area
+ * is known to be the final best, so no more searching should be performed
+ */
+static s32 update_candidate(struct tcm *tcm, u16 x0, u16 y0, u16 w, u16 h,
+ struct tcm_area *field, s32 criteria,
+ struct score *best)
+{
+ struct score me; /* score for area */
+
+ /*
+ * If first found is enabled then we stop looking
+ * NOTE: For horizontal bias we always give the first found, because our
+ * scan is horizontal-raster-based and the first candidate will always
+ * have the horizontal bias.
+ */
+ bool first = criteria & (CR_FIRST_FOUND | CR_BIAS_HORIZONTAL);
+
+ assign(&me.a, x0, y0, x0 + w - 1, y0 + h - 1);
+
+ /* calculate score for current candidate */
+ if (!first) {
+ get_neighbor_stats(tcm, &me.a, &me.n);
+ me.neighs = me.n.edge + me.n.busy;
+ get_nearness_factor(field, &me.a, &me.f);
+ }
+
+ /* the 1st candidate is always the best */
+ if (!best->a.tcm)
+ goto better;
+
+ /* see if this are is better than the best so far */
+
+ /* neighbor check */
+ if ((criteria & CR_MAX_NEIGHS) &&
+ me.neighs > best->neighs)
+ goto better;
+
+ /* vertical bias check */
+ if ((criteria & CR_BIAS_VERTICAL) &&
+ /*
+ * NOTE: not checking if lengths are same, because that does not
+ * find new shoulders on the same row after a fit
+ */
+ LEN(me.a.p0.y, field->p0.y) >
+ LEN(best->a.p0.y, field->p0.y))
+ goto better;
+
+ /* diagonal balance check */
+ if ((criteria & CR_DIAGONAL_BALANCE) &&
+ best->neighs <= me.neighs &&
+ (best->neighs < me.neighs ||
+ /* this implies that neighs and occupied match */
+ best->n.busy < me.n.busy ||
+ (best->n.busy == me.n.busy &&
+ /* check the nearness factor */
+ best->f.x + best->f.y > me.f.x + me.f.y)))
+ goto better;
+
+ /* not better, keep going */
+ return 0;
+
+better:
+ /* save current area as best */
+ memcpy(best, &me, sizeof(me));
+ best->a.tcm = tcm;
+ return first;
+}
+
+/*
+ * Calculate the nearness factor of an area in a search field. The nearness
+ * factor is smaller if the area is closer to the search origin.
+ */
+static void get_nearness_factor(struct tcm_area *field, struct tcm_area *area,
+ struct nearness_factor *nf)
+{
+ /*
+ * Using signed math as field coordinates may be reversed if
+ * search direction is right-to-left or bottom-to-top.
+ */
+ nf->x = (s32)(area->p0.x - field->p0.x) * 1000 /
+ (field->p1.x - field->p0.x);
+ nf->y = (s32)(area->p0.y - field->p0.y) * 1000 /
+ (field->p1.y - field->p0.y);
+}
+
+/* get neighbor statistics */
+static void get_neighbor_stats(struct tcm *tcm, struct tcm_area *area,
+ struct neighbor_stats *stat)
+{
+ s16 x = 0, y = 0;
+ struct sita_pvt *pvt = (struct sita_pvt *)tcm->pvt;
+
+ /* Clearing any exisiting values */
+ memset(stat, 0, sizeof(*stat));
+
+ /* process top & bottom edges */
+ for (x = area->p0.x; x <= area->p1.x; x++) {
+ if (area->p0.y == 0)
+ stat->edge++;
+ else if (pvt->map[x][area->p0.y - 1])
+ stat->busy++;
+
+ if (area->p1.y == tcm->height - 1)
+ stat->edge++;
+ else if (pvt->map[x][area->p1.y + 1])
+ stat->busy++;
+ }
+
+ /* process left & right edges */
+ for (y = area->p0.y; y <= area->p1.y; ++y) {
+ if (area->p0.x == 0)
+ stat->edge++;
+ else if (pvt->map[area->p0.x - 1][y])
+ stat->busy++;
+
+ if (area->p1.x == tcm->width - 1)
+ stat->edge++;
+ else if (pvt->map[area->p1.x + 1][y])
+ stat->busy++;
+ }
+}
diff --git a/drivers/misc/tiler/tcm/tcm-sita.h b/drivers/misc/tiler/tcm/tcm-sita.h
new file mode 100644
index 0000000..a435bce
--- /dev/null
+++ b/drivers/misc/tiler/tcm/tcm-sita.h
@@ -0,0 +1,28 @@
+/*
+ * SImple Tiler Allocator (SiTA) interface.
+ *
+ * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef TCM_SITA_H
+#define TCM_SITA_H
+
+#include "../tcm.h"
+
+/*
+ * Create a SiTA tiler container manager.
+ */
+struct tcm *sita_init(u16 width, u16 height, void *attr);
+
+TCM_INIT(sita_init, void);
+
+#endif
--
1.7.0.4
From: Lajos Molnar <[email protected]>
This patch defines the TILER Memory Manager (TMM) interface and
provides implementation for a PAT-supporting TMM.
Signed-off-by: Lajos Molnar <[email protected]>
Signed-off-by: David Sin <[email protected]>
---
drivers/misc/tiler/tmm-pat.c | 266 ++++++++++++++++++++++++++++++++++++++++++
drivers/misc/tiler/tmm.h | 103 ++++++++++++++++
2 files changed, 369 insertions(+), 0 deletions(-)
create mode 100644 drivers/misc/tiler/tmm-pat.c
create mode 100644 drivers/misc/tiler/tmm.h
diff --git a/drivers/misc/tiler/tmm-pat.c b/drivers/misc/tiler/tmm-pat.c
new file mode 100644
index 0000000..26b4da3
--- /dev/null
+++ b/drivers/misc/tiler/tmm-pat.c
@@ -0,0 +1,266 @@
+/*
+ * DMM driver support functions for TI TILER hardware block.
+ *
+ * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#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 <linux/dma-mapping.h>
+
+#include "tmm.h"
+
+/* Page size granularity can be 4k, 16k, or 64k */
+#define DMM_PAGE SZ_4K
+
+/* Memory limit to cache free pages. TILER will eventually use this much */
+static u32 cache_limit = CONFIG_TILER_CACHE_LIMIT << 20;
+module_param_named(cache, cache_limit, uint, 0644);
+MODULE_PARM_DESC(cache, "Cache free pages if total memory is under this limit");
+
+/* global state - statically initialized */
+static LIST_HEAD(free_list); /* page cache: list of free pages */
+static u32 total_mem; /* total memory allocated (free & used) */
+static u32 refs; /* number of tmm_pat instances */
+static DEFINE_MUTEX(mtx); /* global mutex */
+
+/* The page struct pointer and physical address of each page.*/
+struct mem {
+ struct list_head list;
+ u32 *pg; /* page struct */
+ dma_addr_t pa; /* physical address */
+};
+
+/* Used to keep track of mem per tmm_pat_get_pages call */
+struct fast {
+ struct list_head list;
+ struct mem **mem; /* array of page info */
+ u32 *pa; /* array of physical addresses */
+ u32 num; /* number of pages */
+};
+
+/* TMM PAT private structure */
+struct dmm_mem {
+ struct list_head fast_list;
+ struct dmm *dmm;
+};
+
+/*
+ * Frees pages in a fast structure. Moves pages to the free list if there
+ * are less pages used than max_to_keep. Otherwise, it frees the pages
+ */
+static void free_fast(struct fast *f)
+{
+ s32 i = 0;
+
+ /* mutex is locked */
+ for (i = 0; i < f->num; i++) {
+ if (total_mem < cache_limit) {
+ /* cache free page if under the limit */
+ list_add(&f->mem[i]->list, &free_list);
+ } else {
+ /* otherwise, free */
+ total_mem -= PAGE_SIZE;
+ dma_free_coherent(NULL, DMM_PAGE, f->mem[i]->pg,
+ f->mem[i]->pa);
+ }
+ }
+ kfree(f->pa);
+ kfree(f->mem);
+ /* remove only if element was added */
+ if (f->list.next)
+ list_del(&f->list);
+ kfree(f);
+}
+
+/* allocate and flush a page */
+static struct mem *alloc_mem(void)
+{
+ struct mem *m = kzalloc(sizeof(*m), GFP_KERNEL);
+ if (!m)
+ return NULL;
+
+ m->pg = dma_alloc_coherent(NULL, DMM_PAGE, &m->pa, GFP_KERNEL);
+ if (!m->pg) {
+ kfree(m);
+ return NULL;
+ }
+ wmb();
+
+ return m;
+}
+
+static void free_page_cache(void)
+{
+ struct mem *m, *m_;
+
+ /* mutex is locked */
+ list_for_each_entry_safe(m, m_, &free_list, list) {
+ dma_free_coherent(NULL, DMM_PAGE, m->pg, m->pa);
+ total_mem -= PAGE_SIZE;
+ list_del(&m->list);
+ kfree(m);
+ }
+}
+
+static void tmm_pat_deinit(struct tmm *tmm)
+{
+ struct fast *f, *f_;
+ struct dmm_mem *pvt = (struct dmm_mem *) tmm->pvt;
+
+ mutex_lock(&mtx);
+
+ /* free all outstanding used memory */
+ list_for_each_entry_safe(f, f_, &pvt->fast_list, list)
+ free_fast(f);
+
+ /* if this is the last tmm_pat, free all memory */
+ if (--refs == 0)
+ free_page_cache();
+
+ mutex_unlock(&mtx);
+}
+
+static u32 *tmm_pat_get_pages(struct tmm *tmm, u32 n)
+{
+ struct mem *m;
+ struct fast *f;
+ struct dmm_mem *pvt = (struct dmm_mem *) tmm->pvt;
+
+ f = kzalloc(sizeof(*f), GFP_KERNEL);
+ if (!f)
+ return NULL;
+
+ /* array of mem struct pointers */
+ f->mem = kzalloc(n * sizeof(*f->mem), GFP_KERNEL);
+
+ /* array of physical addresses */
+ f->pa = kzalloc(n * sizeof(*f->pa), GFP_KERNEL);
+
+ /* no pages have been allocated yet (needed for cleanup) */
+ f->num = 0;
+
+ if (!f->mem || !f->pa)
+ goto cleanup;
+
+ /* fill out fast struct mem array with free pages */
+ mutex_lock(&mtx);
+ while (f->num < n) {
+ /* if there is a free cached page use it */
+ if (!list_empty(&free_list)) {
+ /* unbind first element from list */
+ m = list_first_entry(&free_list, typeof(*m), list);
+ list_del(&m->list);
+ } else {
+ mutex_unlock(&mtx);
+
+ /*
+ * Unlock mutex during allocation and cache flushing.
+ */
+ m = alloc_mem();
+ if (!m)
+ goto cleanup;
+
+ mutex_lock(&mtx);
+ total_mem += PAGE_SIZE;
+ }
+
+ f->mem[f->num] = m;
+ f->pa[f->num++] = m->pa;
+ }
+
+ list_add(&f->list, &pvt->fast_list);
+ mutex_unlock(&mtx);
+ return f->pa;
+
+cleanup:
+ free_fast(f);
+ return NULL;
+}
+
+static void tmm_pat_free_pages(struct tmm *tmm, u32 *page_list)
+{
+ struct dmm_mem *pvt = (struct dmm_mem *) tmm->pvt;
+ struct fast *f, *f_;
+
+ mutex_lock(&mtx);
+ /* find fast struct based on 1st page */
+ list_for_each_entry_safe(f, f_, &pvt->fast_list, list) {
+ if (f->pa[0] == page_list[0]) {
+ free_fast(f);
+ break;
+ }
+ }
+ mutex_unlock(&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 = {NULL};
+
+ /* 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 = kzalloc(sizeof(*tmm), GFP_KERNEL);
+ if (tmm)
+ pvt = kzalloc(sizeof(*pvt), GFP_KERNEL);
+ if (pvt) {
+ /* private data */
+ pvt->dmm = dmm;
+ INIT_LIST_HEAD(&pvt->fast_list);
+
+ /* increate tmm_pat references */
+ mutex_lock(&mtx);
+ refs++;
+ mutex_unlock(&mtx);
+
+ /* 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;
+ }
+
+ kfree(pvt);
+ kfree(tmm);
+ return NULL;
+}
+EXPORT_SYMBOL(tmm_pat_init);
diff --git a/drivers/misc/tiler/tmm.h b/drivers/misc/tiler/tmm.h
new file mode 100644
index 0000000..cb90664
--- /dev/null
+++ b/drivers/misc/tiler/tmm.h
@@ -0,0 +1,103 @@
+/*
+ * TMM interface definition for TI TILER driver.
+ *
+ * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef TMM_H
+#define TMM_H
+
+#include <mach/dmm.h>
+/*
+ * TMM interface
+ */
+struct tmm {
+ void *pvt;
+
+ /* function table */
+ u32 *(*get) (struct tmm *tmm, u32 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, u32 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.
+ */
+static inline
+void tmm_free(struct tmm *tmm, u32 *pages)
+{
+ if (tmm && tmm->pvt)
+ tmm->free(tmm, pages);
+}
+
+/*
+ * Program the physical address translator.
+ */
+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.
+ */
+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
--
1.7.0.4
From: Lajos Molnar <[email protected]>
This patch contains the TILER interface file and the documentation.
Signed-off-by: Lajos Molnar <[email protected]>
Signed-off-by: David Sin <[email protected]>
---
Documentation/arm/OMAP/TILER | 126 ++++++++++++++++++++++
arch/arm/mach-omap2/include/mach/tiler.h | 173 ++++++++++++++++++++++++++++++
2 files changed, 299 insertions(+), 0 deletions(-)
create mode 100644 Documentation/arm/OMAP/TILER
create mode 100644 arch/arm/mach-omap2/include/mach/tiler.h
diff --git a/Documentation/arm/OMAP/TILER b/Documentation/arm/OMAP/TILER
new file mode 100644
index 0000000..2e94ad7
--- /dev/null
+++ b/Documentation/arm/OMAP/TILER
@@ -0,0 +1,126 @@
+Tiling and Isometric Lightweight Engine for Rotation (TILER) driver
+
+Dynamic Memory Manager (DMM) is a hardware block made by Texas Instruments.
+Within the DMM exists at least one TILER hardware component. Its purpose is to
+organize video/image memory in a 2-dimensional fashion to limit memory
+bandwidth and facilitate 0 effort rotation and mirroring. The TILER driver
+facilitates allocating, freeing, as well as mapping 2D blocks (areas) in the
+TILER container(s). It also facilitates rotating and mirroring the allocated
+blocks or its rectangular subsections.
+
+TERMINOLOGY
+
+"slot"
+
+The basic TILER driver operates on blocks of slots. A slot is the granularity
+of the TILER hardware device. For all current uses it is 4K, but could also be
+16 or 64K. The DMM-TILER TRM refers to this as "page" but we want to separate
+this concept from the MMU pages.
+
+"page"
+
+The granularity of the MMU, used by the kernel. This is 4K.
+
+"block"
+
+The TILER hardware component supports 1D and 2D blocks. A 2D block is a
+rectangular arrangement of slots with arbitrary width and height in a 2D
+container. A 1D block is a linear arrangement of slots with arbitrary length
+ in a 1D container. This TILER driver only supports 2D blocks.
+
+"container"
+
+The TILER driver supports an arbitrary TILER container size. However, for
+all current implementations it is 256 by 128 slots. The container currently can
+only be used as a 2D container.
+
+"reserved area"
+
+Each block resides within a reserved area in the container. This area may
+be larger than the actual set of slots that a block occupies. The reason for
+this is to protect access from one block into another. Since TILER container is
+mmap-ped into user space as individual pages, all slots that are spanned by
+that page become visible to the user. The tiler driver allows restricting the
+granularity of the reserved area (default alignment) as well as the mapped
+area (granularity).
+
+Using TILER driver KERNEL APIs:
+
+1. Allocating and freeing a 1080p YUV422 block
+
+ struct tiler_block_t blk = {0};
+ int res;
+
+ blk.width = 1920;
+ blk.height = 1080;
+ res = tiler_alloc(&blk, TILFMT_16BIT, 0, 0);
+
+ tiler_free(&blk);
+
+2. Allocating and freeing a 1080p YUV420p block
+
+ struct tiler_block_t blk_Y = {0}, blk_UV = {0};
+ int res;
+
+ blk_Y.width = 1920;
+ blk_Y.height = 1080;
+ blk_UV.widht = 960;
+ blk_UV.height = 540;
+ res = tiler_alloc(&blk_Y, TILFMT_8BIT, 0, 0) ? :
+ tiler_alloc(&blk_UV, TILFMT_16BIT, PAGE_SIZE,
+ blk_y->phys & ~PAGE_MASK);
+
+ tiler_free(&blk_Y);
+ tiler_free(&blk_UV);
+
+Note how we allocated the UV block at the same in-page offset as the Y buffer.
+This facilitates mmap-ping both Y and UV blocks into userspace as one
+contiguous buffer.
+
+3. Mmap-ing YUV420p block into user space
+
+ static int my_mmap(struct file *file, struct vm_area_struct *vma)
+ {
+ unsigned long size = (vma->vm_end - vma->vm_start);
+ unsigned long start = vma->vm_start;
+
+ if (size != tiler_size(&blk_Y) + tiler_size(&blk_UV))
+ return -EINVAL;
+
+ return tiler_mmap_blk(&blk_Y, 0, tiler_size(&blk_Y), vma, 0) ?
+ : tiler_mmap_blk(&blk_UV, 0, tiler_size(&blk_UV), vma,
+ tiler_size(&blk_Y));
+ }
+
+CONFIGURATIONS
+
+The TILER driver allows specifying a container manager (tcm) for each
+pixel format. The same container manager can be specified for more than
+one pixel formats.
+
+Each container manager also operates on a Physical Address Translator PAT
+ instance. One can also specify a "virtual" PAT (with a linear preassigned
+ memory space no actual PAT programming), but it is not implemented.
+
+PARAMETERS
+
+The TILER driver allows specifying:
+
+ granularity (tiler.grain, CONFIG_TILER_GRANULARITY):
+
+ Each block is mapped in width-chunks of granularity.
+
+ default alignment (tiler.align, CONFIG_TILER_ALIGNMENT):
+
+ Default alignment if aligment is not specified (0). Otherwise,
+ blocks are allocated at an address aligned to the value given plus an
+ offset within the alignment.
+
+ cache limit (tiler.cache, CONFIG_TILER_CACHE_LIMIT):
+
+ TILER driver keeps a cache of allocated pages to speed up allocation of
+ TILER blocks. You can set a limit of how much memory the TILER driver
+ should keep if there are no actual TILER allocations. This also means
+ that if there is less memory used than this limit, the pages of freed
+ tiler blocks will not actually be freed, but instead are put into this
+ cache.
diff --git a/arch/arm/mach-omap2/include/mach/tiler.h b/arch/arm/mach-omap2/include/mach/tiler.h
new file mode 100644
index 0000000..280f7bb
--- /dev/null
+++ b/arch/arm/mach-omap2/include/mach/tiler.h
@@ -0,0 +1,173 @@
+/*
+ * TILER driver support functions for TI TILER hardware block.
+ *
+ * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef TILER_H
+#define TILER_H
+
+#include <linux/mm.h>
+
+/* API Definitions */
+
+/* return true if physical address is in the tiler container */
+bool is_tiler_addr(u32 phys);
+
+enum tiler_fmt {
+ TILFMT_MIN = -2,
+ TILFMT_INVALID = -2,
+ TILFMT_NONE = -1,
+ TILFMT_8BIT = 0,
+ TILFMT_16BIT = 1,
+ TILFMT_32BIT = 2,
+ TILFMT_MAX = 2,
+ TILFMT_PAGE = 3, /* for completeness */
+};
+
+/* tiler block info */
+struct tiler_block_t {
+ u32 phys; /* system space (L3) tiler addr */
+ u32 width; /* width */
+ u32 height; /* height */
+};
+
+/* tiler (image/video frame) view */
+struct tiler_view_t {
+ u32 tsptr; /* tiler space addr */
+ u32 width; /* width */
+ u32 height; /* height */
+ u32 bpp; /* bytes per pixel */
+ s32 h_inc; /* horizontal increment */
+ s32 v_inc; /* vertical increment */
+};
+
+/* get tiler format for a physical address */
+enum tiler_fmt tiler_fmt(u32 phys);
+
+/* get tiler block bytes-per-pixel */
+u32 tiler_bpp(const struct tiler_block_t *b);
+
+/* get tiler block physical stride */
+u32 tiler_pstride(const struct tiler_block_t *b);
+
+/* get tiler block virtual stride */
+static inline u32 tiler_vstride(const struct tiler_block_t *b)
+{
+ return PAGE_ALIGN((b->phys & ~PAGE_MASK) + tiler_bpp(b) * b->width);
+}
+
+/* returns the virtual size of the block (for mmap) */
+static inline u32 tiler_size(const struct tiler_block_t *b)
+{
+ return b->height * tiler_vstride(b);
+}
+
+/*
+ * Reserves a 2D TILER block area and memory.
+ *
+ * @blk: pointer to tiler block data. This must be set up ('phys' member must
+ * be 0) with the tiler block information.
+ * @fmt: TILER block format
+ * @align: block alignment (default: normally PAGE_SIZE)
+ * @offs: block offset
+ *
+ */
+s32 tiler_alloc(struct tiler_block_t *blk, enum tiler_fmt fmt, u32 align,
+ u32 offs);
+
+/*
+ * Mmaps a portion of a tiler block to a virtual address. Use this method in
+ * your driver's mmap function to potentially combine multiple tiler blocks as
+ * one virtual buffer.
+ *
+ * @blk: pointer to tiler block data
+ * @offs: offset from where to map (must be page aligned)
+ * @size: size of area to map (must be page aligned)
+ * @vma: VMM memory area to map to
+ * @voffs: offset (from vm_start) in the VMM memory area to start mapping at
+ *
+ */
+s32 tiler_mmap_blk(struct tiler_block_t *blk, u32 offs, u32 size,
+ struct vm_area_struct *vma, u32 voffs);
+
+/*
+ * Frees TILER memory. Since there may be multiple references for the same area
+ * if duplicated by tiler_dup, the area is only actually freed if all references
+ * have been freed.
+ *
+ * @blk: pointer to a tiler block data as filled by tiler_alloc, tiler_map
+ * or tiler_dup. 'phys' member will be set to 0 on success.
+ */
+void tiler_free(struct tiler_block_t *blk);
+
+/*
+ * Create a view based on a tiler address and width and height
+ *
+ * This method should only be used as a last resort, e.g. if tilview object
+ * cannot be passed because of incoherence with other view 2D objects that must
+ * be supported.
+ *
+ * @view: Pointer to a view where the information will be stored
+ * @ssptr: MUST BE a tiler address
+ * @width: view width
+ * @height: view height
+ */
+void tilview_create(struct tiler_view_t *view, u32 phys, u32 width, u32 height);
+
+/*
+ * Obtains the view information for a tiler block
+ *
+ * @view: Pointer to a view where the information will be stored
+ * @blk: Pointer to an existing allocated tiler block
+ */
+void tilview_get(struct tiler_view_t *view, struct tiler_block_t *blk);
+
+/*
+ * Crops a tiler view to a rectangular portion. Crop area must be fully within
+ * the orginal tiler view: 0 <= left <= left + width <= view->width, also:
+ * 0 <= top <= top + height <= view->height.
+ *
+ * @view: Pointer to tiler view to be cropped
+ * @left: x of top-left corner
+ * @top: y of top-left corner
+ * @width: crop width
+ * @height: crop height
+ *
+ * The view will be reduced to the crop region if the crop region is correct.
+ * Otherwise, no modifications are made.
+ */
+s32 tilview_crop(struct tiler_view_t *view, u32 left, u32 top, u32 width,
+ u32 height);
+
+/*
+ * Rotates a tiler view clockwise by a specified degree.
+ *
+ * @view: Pointer to tiler view to be cropped
+ * @rotate: Degree of rotation (clockwise). Must be a multiple of 90.
+ *
+ * View is not modified on error; otherwise, it is updated in place.
+ */
+s32 tilview_rotate(struct tiler_view_t *view, s32 rotation);
+
+/*
+ * Mirrors a tiler view horizontally and/or vertically.
+ *
+ * @view: Pointer to tiler view to be cropped
+ * @flip_x: Mirror horizontally (left-to-right)
+ * @flip_y: Mirror vertically (top-to-bottom)
+ *
+ * View is not modified on error; otherwise, it is updated in place.
+ */
+s32 tilview_flip(struct tiler_view_t *view, bool flip_x, bool flip_y);
+
+#endif
--
1.7.0.4
From: Lajos Molnar <[email protected]>
This patch contains information on TILER geometry, as well as
tiler_view_t object manipulation functions.
It also contains an internal TILER header file to share geometric
information with other TILER files.
Signed-off-by: Lajos Molnar <[email protected]>
Signed-off-by: David Sin <[email protected]>
---
drivers/misc/tiler/_tiler.h | 48 +++++
drivers/misc/tiler/tiler-geom.c | 362 +++++++++++++++++++++++++++++++++++++++
2 files changed, 410 insertions(+), 0 deletions(-)
create mode 100644 drivers/misc/tiler/_tiler.h
create mode 100644 drivers/misc/tiler/tiler-geom.c
diff --git a/drivers/misc/tiler/_tiler.h b/drivers/misc/tiler/_tiler.h
new file mode 100644
index 0000000..0f00330
--- /dev/null
+++ b/drivers/misc/tiler/_tiler.h
@@ -0,0 +1,48 @@
+/*
+ * TI TILER driver internal shared definitions.
+ *
+ * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _TILER_H
+#define _TILER_H
+
+#include <linux/kernel.h>
+#include <mach/tiler.h>
+#include "tcm.h"
+
+#define TILER_FORMATS (TILFMT_MAX - TILFMT_MIN + 1)
+
+/* tiler geometry information */
+struct tiler_geom {
+ u32 x_shft; /* unused X-bits (as part of bpp) */
+ u32 y_shft; /* unused Y-bits (as part of bpp) */
+ u32 bpp; /* bytes per pixel */
+ u32 slot_w; /* width of each slot (in pixels) */
+ u32 slot_h; /* height of each slot (in pixels) */
+};
+
+/* methods and variables shared between source files */
+struct tiler_ops {
+ /* geometry operations */
+ void (*xy) (u32 ssptr, u32 *x, u32 *y);
+ u32 (*addr) (enum tiler_fmt fmt, u32 x, u32 y);
+ const struct tiler_geom * (*geom) (enum tiler_fmt fmt);
+
+ u32 page; /* page size */
+ u32 width; /* container width */
+ u32 height; /* container height */
+};
+
+void tiler_geom_init(struct tiler_ops *tiler);
+
+#endif
diff --git a/drivers/misc/tiler/tiler-geom.c b/drivers/misc/tiler/tiler-geom.c
new file mode 100644
index 0000000..df5fe2c
--- /dev/null
+++ b/drivers/misc/tiler/tiler-geom.c
@@ -0,0 +1,362 @@
+/*
+ * TILER geometry functions for TI TILER hardware block.
+ *
+ * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include "_tiler.h"
+
+/* bits representing the same slot in DMM-TILER hw-block */
+#define SLOT_WIDTH_BITS 6
+#define SLOT_HEIGHT_BITS 6
+
+/* bits reserved to describe coordinates in DMM-TILER hw-block */
+#define CONT_WIDTH_BITS 14
+#define CONT_HEIGHT_BITS 13
+
+static struct tiler_geom geom[TILER_FORMATS] = {
+ {
+ .x_shft = 0,
+ .y_shft = 0,
+ },
+ {
+ .x_shft = 0,
+ .y_shft = 1,
+ },
+ {
+ .x_shft = 1,
+ .y_shft = 1,
+ },
+};
+
+/* tiler space addressing bitfields */
+#define MASK_XY_FLIP (1 << 31)
+#define MASK_Y_INVERT (1 << 30)
+#define MASK_X_INVERT (1 << 29)
+#define SHIFT_ACC_MODE 27
+#define MASK_ACC_MODE 3
+
+/* calculated constants */
+#define TILER_PAGE (1 << (SLOT_WIDTH_BITS + SLOT_HEIGHT_BITS))
+#define TILER_WIDTH (1 << (CONT_WIDTH_BITS - SLOT_WIDTH_BITS))
+#define TILER_HEIGHT (1 << (CONT_HEIGHT_BITS - SLOT_HEIGHT_BITS))
+
+#define VIEW_SIZE (1u << (CONT_WIDTH_BITS + CONT_HEIGHT_BITS))
+#define VIEW_MASK (VIEW_SIZE - 1u)
+
+#define MASK(bits) ((1 << (bits)) - 1)
+
+#define TILER_FMT(x) ((enum tiler_fmt) \
+ ((x >> SHIFT_ACC_MODE) & MASK_ACC_MODE))
+
+#define MASK_VIEW (MASK_X_INVERT | MASK_Y_INVERT | MASK_XY_FLIP)
+
+/* location of the various tiler views in physical address space */
+#define TILVIEW_8BIT 0x60000000u
+#define TILVIEW_16BIT (TILVIEW_8BIT + VIEW_SIZE)
+#define TILVIEW_32BIT (TILVIEW_16BIT + VIEW_SIZE)
+#define TILVIEW_PAGE (TILVIEW_32BIT + VIEW_SIZE)
+#define TILVIEW_END (TILVIEW_PAGE + VIEW_SIZE)
+
+/* create tsptr by adding view orientation and access mode */
+#define TIL_ADDR(x, orient, a)\
+ ((u32) (x) | (orient) | ((a) << SHIFT_ACC_MODE))
+
+bool is_tiler_addr(u32 phys)
+{
+ return phys >= TILVIEW_8BIT && phys < TILVIEW_END;
+}
+EXPORT_SYMBOL(is_tiler_addr);
+
+u32 tiler_bpp(const struct tiler_block_t *b)
+{
+ enum tiler_fmt fmt = tiler_fmt(b->phys);
+ BUG_ON(fmt == TILFMT_INVALID || fmt == TILFMT_PAGE);
+
+ return geom[fmt].bpp;
+}
+EXPORT_SYMBOL(tiler_bpp);
+
+/* return the stride of a tiler-block in tiler space */
+static inline s32 tiler_stride(u32 tsptr)
+{
+ enum tiler_fmt fmt = TILER_FMT(tsptr);
+
+ if (fmt == TILFMT_PAGE)
+ return 0;
+ else if (tsptr & MASK_XY_FLIP)
+ return 1 << (CONT_HEIGHT_BITS + geom[fmt].x_shft);
+ else
+ return 1 << (CONT_WIDTH_BITS + geom[fmt].y_shft);
+}
+
+u32 tiler_pstride(const struct tiler_block_t *b)
+{
+ enum tiler_fmt fmt = tiler_fmt(b->phys);
+ BUG_ON(fmt == TILFMT_INVALID);
+
+ /* return the virtual stride for page mode */
+ if (fmt == TILFMT_PAGE)
+ return tiler_vstride(b);
+
+ return tiler_stride(b->phys & ~MASK_VIEW);
+}
+EXPORT_SYMBOL(tiler_pstride);
+
+enum tiler_fmt tiler_fmt(u32 phys)
+{
+ if (!is_tiler_addr(phys))
+ return TILFMT_INVALID;
+
+ return TILER_FMT(phys);
+}
+EXPORT_SYMBOL(tiler_fmt);
+
+/* returns the tiler geometry information for a format */
+static const struct tiler_geom *get_geom(enum tiler_fmt fmt)
+{
+ if (fmt >= TILFMT_MIN && fmt <= TILFMT_MAX)
+ return geom + fmt;
+ return NULL;
+}
+
+/*
+ * Returns the natural x and y coordinates for a pixel in tiler space address.
+ * That is, the coordinates for the same pixel in the natural (non-rotated,
+ * non-mirrored) view. This allows to uniquely identify a tiler pixel in any
+ * view orientation.
+ */
+static void tiler_get_natural_xy(u32 tsptr, u32 *x, u32 *y)
+{
+ u32 x_bits, y_bits, offset;
+ enum tiler_fmt fmt;
+
+ fmt = TILER_FMT(tsptr);
+
+ x_bits = CONT_WIDTH_BITS - geom[fmt].x_shft;
+ y_bits = CONT_HEIGHT_BITS - geom[fmt].y_shft;
+ offset = (tsptr & VIEW_MASK) >> (geom[fmt].x_shft + geom[fmt].y_shft);
+
+ /* separate coordinate bitfields based on view orientation */
+ if (tsptr & MASK_XY_FLIP) {
+ *x = offset >> y_bits;
+ *y = offset & MASK(y_bits);
+ } else {
+ *x = offset & MASK(x_bits);
+ *y = offset >> x_bits;
+ }
+
+ /* account for mirroring */
+ if (tsptr & MASK_X_INVERT)
+ *x ^= MASK(x_bits);
+ if (tsptr & MASK_Y_INVERT)
+ *y ^= MASK(y_bits);
+}
+
+/* calculate the tiler space address of a pixel in a view orientation */
+static u32 tiler_get_address(u32 orient, enum tiler_fmt fmt, u32 x, u32 y)
+{
+ u32 x_bits, y_bits, tmp, x_mask, y_mask, alignment;
+
+ x_bits = CONT_WIDTH_BITS - geom[fmt].x_shft;
+ y_bits = CONT_HEIGHT_BITS - geom[fmt].y_shft;
+ alignment = geom[fmt].x_shft + geom[fmt].y_shft;
+
+ /* validate coordinate */
+ x_mask = MASK(x_bits);
+ y_mask = MASK(y_bits);
+ if (x < 0 || x > x_mask || y < 0 || y > y_mask)
+ return 0;
+
+ /* account for mirroring */
+ if (orient & MASK_X_INVERT)
+ x ^= x_mask;
+ if (orient & MASK_Y_INVERT)
+ y ^= y_mask;
+
+ /* get coordinate address */
+ if (orient & MASK_XY_FLIP)
+ tmp = ((x << y_bits) + y);
+ else
+ tmp = ((y << x_bits) + x);
+
+ return TIL_ADDR((tmp << alignment), orient, fmt);
+}
+
+void tilview_create(struct tiler_view_t *view, u32 phys, u32 width, u32 height)
+{
+ BUG_ON(!is_tiler_addr(phys));
+
+ view->tsptr = phys & ~MASK_VIEW;
+ view->bpp = geom[TILER_FMT(phys)].bpp;
+ view->width = width;
+ view->height = height;
+ view->h_inc = view->bpp;
+ view->v_inc = tiler_stride(view->tsptr);
+}
+EXPORT_SYMBOL(tilview_create);
+
+void tilview_get(struct tiler_view_t *view, struct tiler_block_t *blk)
+{
+ view->tsptr = blk->phys & ~MASK_VIEW;
+ view->bpp = tiler_bpp(blk);
+ view->width = blk->width;
+ view->height = blk->height;
+ view->h_inc = view->bpp;
+ view->v_inc = tiler_stride(view->tsptr);
+}
+EXPORT_SYMBOL(tilview_get);
+
+s32 tilview_crop(struct tiler_view_t *view, u32 left, u32 top, u32 width,
+ u32 height)
+{
+ /* check for valid crop */
+ if (left + width < left || left + width > view->width ||
+ top + height < top || top + height > view->height)
+ return -EINVAL;
+
+ view->tsptr += left * view->h_inc + top * view->v_inc;
+ view->width = width;
+ view->height = height;
+ return 0;
+}
+EXPORT_SYMBOL(tilview_crop);
+
+/* calculate tilerspace address and stride after view orientation change */
+static void reorient(struct tiler_view_t *view, u32 orient)
+{
+ u32 x, y;
+
+ tiler_get_natural_xy(view->tsptr, &x, &y);
+ view->tsptr = tiler_get_address(orient,
+ TILER_FMT(view->tsptr), x, y);
+ view->v_inc = tiler_stride(view->tsptr);
+}
+
+s32 tilview_rotate(struct tiler_view_t *view, s32 rotation)
+{
+ u32 orient;
+
+ if (rotation % 90)
+ return -EINVAL;
+
+ /* normalize rotation to quarters */
+ rotation = (rotation / 90) & 3;
+ if (!rotation)
+ return 0; /* nothing to do */
+
+ /* PAGE mode view cannot be rotated */
+ if (TILER_FMT(view->tsptr) == TILFMT_PAGE)
+ return -EPERM;
+
+ /*
+ * first adjust top-left corner. NOTE: it rotates counter-clockwise:
+ * 0 < 3
+ * v ^
+ * 1 > 2
+ */
+ if (rotation < 3)
+ view->tsptr += (view->height - 1) * view->v_inc;
+ if (rotation > 1)
+ view->tsptr += (view->width - 1) * view->h_inc;
+
+ /* then rotate view itself */
+ orient = view->tsptr & MASK_VIEW;
+
+ /* rotate first 2 quarters */
+ if (rotation & 2) {
+ orient ^= MASK_X_INVERT;
+ orient ^= MASK_Y_INVERT;
+ }
+
+ /* rotate last quarter */
+ if (rotation & 1) {
+ orient ^= (orient & MASK_XY_FLIP) ?
+ MASK_X_INVERT : MASK_Y_INVERT;
+
+ /* swap x & y */
+ orient ^= MASK_XY_FLIP;
+ swap(view->height, view->width);
+ }
+
+ /* finally reorient view */
+ reorient(view, orient);
+ return 0;
+}
+EXPORT_SYMBOL(tilview_rotate);
+
+s32 tilview_flip(struct tiler_view_t *view, bool flip_x, bool flip_y)
+{
+ u32 orient;
+ orient = view->tsptr & MASK_VIEW;
+
+ if (!flip_x && !flip_y)
+ return 0; /* nothing to do */
+
+ /* PAGE mode view cannot be flipped */
+ if (TILER_FMT(view->tsptr) == TILFMT_PAGE)
+ return -EPERM;
+
+ /* adjust top-left corner */
+ if (flip_x)
+ view->tsptr += (view->width - 1) * view->h_inc;
+ if (flip_y)
+ view->tsptr += (view->height - 1) * view->v_inc;
+
+ /* flip view orientation */
+ if (orient & MASK_XY_FLIP)
+ swap(flip_x, flip_y);
+
+ if (flip_x)
+ orient ^= MASK_X_INVERT;
+ if (flip_y)
+ orient ^= MASK_Y_INVERT;
+
+ /* finally reorient view */
+ reorient(view, orient);
+ return 0;
+}
+EXPORT_SYMBOL(tilview_flip);
+
+/* return the alias address for a coordinate */
+static inline u32 alias_address(enum tiler_fmt fmt, u32 x, u32 y)
+{
+ return tiler_get_address(0, fmt, x, y) + TILVIEW_8BIT;
+}
+
+/* get the coordinates for an alias address */
+static inline void alias_xy(u32 ssptr, u32 *x, u32 *y)
+{
+ tiler_get_natural_xy(ssptr & ~MASK_VIEW, x, y);
+}
+
+/* initialize shared geometric data */
+void tiler_geom_init(struct tiler_ops *tiler)
+{
+ struct tiler_geom *g;
+
+ tiler->xy = alias_xy;
+ tiler->addr = alias_address;
+ tiler->geom = get_geom;
+
+ tiler->page = TILER_PAGE;
+ tiler->width = TILER_WIDTH;
+ tiler->height = TILER_HEIGHT;
+
+ /* calculate geometry */
+ for (g = geom; g < geom + TILER_FORMATS; g++) {
+ g->bpp = 1 << (g->x_shft + g->y_shft);
+ g->slot_w = 1 << (SLOT_WIDTH_BITS - g->x_shft);
+ g->slot_h = 1 << (SLOT_HEIGHT_BITS - g->y_shft);
+ }
+}
--
1.7.0.4
From: Lajos Molnar <[email protected]>
This patch contains the TILER driver and implementation of the TILER
block manipulation and mapping functions.
It also contains the makefile and config file for the TILER driver.
Signed-off-by: Lajos Molnar <[email protected]>
Signed-off-by: David Sin <[email protected]>
---
arch/arm/mach-omap2/Makefile | 1 +
drivers/misc/tiler/Kconfig | 72 +++++++
drivers/misc/tiler/Makefile | 7 +
drivers/misc/tiler/tiler-iface.c | 66 ++++++
drivers/misc/tiler/tiler-main.c | 405 ++++++++++++++++++++++++++++++++++++++
5 files changed, 551 insertions(+), 0 deletions(-)
create mode 100644 drivers/misc/tiler/Kconfig
create mode 100644 drivers/misc/tiler/Makefile
create mode 100644 drivers/misc/tiler/tiler-iface.c
create mode 100644 drivers/misc/tiler/tiler-main.c
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index ebd2589..d55e29c 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -183,3 +183,4 @@ obj-y += $(nand-m) $(nand-y)
smc91x-$(CONFIG_SMC91X) := gpmc-smc91x.o
obj-y += $(smc91x-m) $(smc91x-y)
obj-$(CONFIG_ARCH_OMAP4) += hwspinlocks.o
+obj-$(CONFIG_ARCH_OMAP4) += dmm-omap44xx.o
diff --git a/drivers/misc/tiler/Kconfig b/drivers/misc/tiler/Kconfig
new file mode 100644
index 0000000..9b8bfed
--- /dev/null
+++ b/drivers/misc/tiler/Kconfig
@@ -0,0 +1,72 @@
+config HAVE_TI_DMM
+ bool
+ default y
+ depends on ARCH_OMAP4
+
+menuconfig TI_DMM
+ tristate "TI DMM support"
+ default y
+ depends on HAVE_TI_DMM
+ help
+ DMM driver for TI chips.
+
+menuconfig TI_TILER
+ tristate "TI TILER support"
+ default y
+ depends on TI_DMM
+ help
+ TILER driver for TI chips. The TI TILER device
+ enables video rotation on certain TI chips such as OMAP4 or
+ TI816x. Video rotation will be limited without TILER support.
+
+config TILER_GRANULARITY
+ int "Allocation granularity (2^n)"
+ range 1 4096
+ default 128
+ depends on TI_TILER
+ help
+ This option sets the default TILER allocation granularity. It can
+ be overriden by the tiler.grain boot argument.
+
+ The allocation granularity is the smallest TILER block size (in
+ bytes) managed distinctly by the TILER driver. TILER blocks of any
+ size are managed in chunks of at least this size.
+
+ Must be a 2^n in the range of 1 to 4096; however, the TILER driver
+ may use a larger supported granularity.
+
+ Supported values are: 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024,
+ 2048, 4096.
+
+config TILER_ALIGNMENT
+ int "Allocation alignment (2^n)"
+ range 1 4096
+ default 4096
+ depends on TI_TILER
+ help
+ This option sets the default TILER allocation alignment. It can
+ be overriden by the tiler.align boot argument.
+
+ Must be a 2^n in the range of 1 to 4096; however, it is naturally
+ aligned to the TILER granularity.
+
+ Supported values are: 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024,
+ 2048, 4096.
+
+config TILER_CACHE_LIMIT
+ int "Memory limit to cache free pages in MBytes"
+ range 0 128
+ default 40
+ depends on TI_TILER
+ help
+ This option sets the minimum memory that TILER retains even if
+ there is less TILER allocated memory is use. The unused memory is
+ instead stored in a cache to speed up allocation and freeing of
+ physical pages.
+
+ This option can be overriden by the tiler.cache boot argument.
+
+ While initially TILER will use less memory than this limit (0), it
+ will not release any memory used until it reaches this limit.
+ Thereafter, TILER will release any unused memory immediately as
+ long as there it is above this threshold.
diff --git a/drivers/misc/tiler/Makefile b/drivers/misc/tiler/Makefile
new file mode 100644
index 0000000..7dbc828
--- /dev/null
+++ b/drivers/misc/tiler/Makefile
@@ -0,0 +1,7 @@
+obj-$(CONFIG_TI_DMM) += dmm.o
+dmm-objs = dmm-main.o
+
+obj-$(CONFIG_TI_TILER) += tcm/
+
+obj-$(CONFIG_TI_TILER) += tiler.o
+tiler-objs = tiler-geom.o tiler-main.o tiler-iface.o tmm-pat.o
diff --git a/drivers/misc/tiler/tiler-iface.c b/drivers/misc/tiler/tiler-iface.c
new file mode 100644
index 0000000..3c64c00
--- /dev/null
+++ b/drivers/misc/tiler/tiler-iface.c
@@ -0,0 +1,66 @@
+/*
+ * TILER driver interace functions for TI TILER hardware block.
+ *
+ * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/mm_types.h>
+#include <asm/mach/map.h>
+
+#include "_tiler.h"
+
+/*
+ * Memory-Map Kernel APIs
+ */
+
+s32 tiler_mmap_blk(struct tiler_block_t *blk, u32 offs, u32 size,
+ struct vm_area_struct *vma, u32 voffs)
+{
+ u32 v, p, len;
+
+ /* don't allow mremap */
+ vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED;
+
+ /* mapping must fit into vma */
+ BUG_ON(vma->vm_start > vma->vm_start + voffs ||
+ vma->vm_start + voffs > vma->vm_start + voffs + size ||
+ vma->vm_start + voffs + size > vma->vm_end);
+
+ /* mapping must fit into block */
+ BUG_ON(offs > offs + size || offs + size > tiler_size(blk));
+
+ v = tiler_vstride(blk);
+ p = tiler_pstride(blk);
+
+ /* remap block portion */
+ len = v - (offs % v); /* initial area to map */
+ while (size) {
+ /* restrict to size still needs mapping */
+ if (len > size)
+ len = size;
+
+ vma->vm_pgoff = (blk->phys + offs) >> PAGE_SHIFT;
+ if (remap_pfn_range(vma, vma->vm_start + voffs, vma->vm_pgoff,
+ len, vma->vm_page_prot))
+ return -EAGAIN;
+ voffs += len;
+ offs += len + p - v;
+ size -= len;
+ len = v; /* subsequent area to map */
+ }
+ return 0;
+}
+EXPORT_SYMBOL(tiler_mmap_blk);
+
diff --git a/drivers/misc/tiler/tiler-main.c b/drivers/misc/tiler/tiler-main.c
new file mode 100644
index 0000000..64bcdd0
--- /dev/null
+++ b/drivers/misc/tiler/tiler-main.c
@@ -0,0 +1,405 @@
+/*
+ * TILER driver main support functions for TI TILER hardware block.
+ *
+ * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/errno.h>
+#include <linux/mutex.h>
+#include <linux/dma-mapping.h>
+#include <linux/pagemap.h>
+#include <linux/slab.h>
+
+#include <mach/dmm.h>
+#include "tmm.h"
+#include "_tiler.h"
+#include "tcm/tcm-sita.h"
+
+static uint default_align = CONFIG_TILER_ALIGNMENT;
+static uint granularity = CONFIG_TILER_GRANULARITY;
+
+module_param_named(align, default_align, uint, 0444);
+MODULE_PARM_DESC(align, "Default block ssptr alignment");
+module_param_named(grain, granularity, uint, 0444);
+MODULE_PARM_DESC(grain, "Granularity (bytes)");
+
+static struct tiler_ops tiler; /* shared methods and variables */
+
+static struct list_head blocks; /* all tiler blocks */
+
+static struct mutex mtx;
+static struct tcm *tcm[TILER_FORMATS];
+static struct tmm *tmm[TILER_FORMATS];
+static u32 *dmac_va;
+static dma_addr_t dmac_pa;
+
+/* info for a block */
+struct mem_info {
+ struct list_head global; /* global blocks */
+ struct tiler_block_t blk; /* block info */
+ struct tcm_area area;
+ u32 *mem; /* list of alloced phys addresses */
+};
+
+/*
+ * TILER Memory Manager (TMM) connectors
+ */
+
+/* wrapper around tmm_map */
+static s32 refill_pat(struct tmm *tmm, struct tcm_area *area, u32 *ptr)
+{
+ s32 res = 0;
+ struct pat_area p_area = {0};
+
+ p_area.x0 = area->p0.x;
+ p_area.y0 = area->p0.y;
+ p_area.x1 = area->p1.x;
+ p_area.y1 = area->p1.y;
+
+ memcpy(dmac_va, ptr, sizeof(*ptr) * tcm_sizeof(*area));
+
+ if (tmm_map(tmm, p_area, dmac_pa))
+ res = -EFAULT;
+
+ return res;
+}
+
+/* wrapper around tmm_clear */
+static void clear_pat(struct tmm *tmm, struct tcm_area *area)
+{
+ struct pat_area p_area = {0};
+
+ p_area.x0 = area->p0.x;
+ p_area.y0 = area->p0.y;
+ p_area.x1 = area->p1.x;
+ p_area.y1 = area->p1.y;
+
+ tmm_clear(tmm, p_area);
+}
+
+/*
+ * Area handling methods
+ */
+
+/* verify input params and calculate tiler container params for a block */
+static s32 __analyze_area(enum tiler_fmt fmt, u32 width, u32 height,
+ u16 *x_area, u16 *y_area, u16 *align, u16 *offs)
+{
+ /* input: width, height is in pixels, *align, *offs in bytes */
+ /* output: x_area, y_area, *align in slots */
+
+ /* slot width, height, and row size */
+ u32 slot_row, min_align;
+ const struct tiler_geom *g;
+
+ /* width and height must be positive, format must be 2D */
+ if (!width || !height || fmt == TILFMT_PAGE)
+ return -EINVAL;
+
+ /* align must be 2 power */
+ if (*align & (*align - 1))
+ return -EINVAL;
+
+ /* format must be valid */
+ g = tiler.geom(fmt);
+ if (!g)
+ return -EINVAL;
+
+ /* get the # of bytes per row in 1 slot */
+ slot_row = g->slot_w * g->bpp;
+
+ /* minimum alignment is at least 1 slot. Use default if needed */
+ min_align = max(slot_row, granularity);
+ *align = ALIGN(*align ? : default_align, min_align);
+
+ /* offset must be multiple of bpp */
+ if (*offs & (g->bpp - 1) || *offs >= *align)
+ return -EINVAL;
+
+ /* round down the offset to the nearest slot size, and increase width
+ to allow space for having the correct offset */
+ width += (*offs & (min_align - 1)) / g->bpp;
+
+ /* expand width to block size */
+ width = ALIGN(width, min_align / g->bpp);
+
+ /* adjust to slots */
+ *x_area = DIV_ROUND_UP(width, g->slot_w);
+ *y_area = DIV_ROUND_UP(height, g->slot_h);
+ *align /= slot_row;
+
+ if (*x_area > tiler.width || *y_area > tiler.height)
+ return -ENOMEM;
+ return 0;
+}
+
+/* allocate a mem_info structure and reserves a 2d container area */
+static struct mem_info *get_2d_area(u16 w, u16 h, u16 align, struct tcm *tcm)
+{
+ struct mem_info *mi = NULL;
+
+ /* reserve a block struct */
+ mi = kmalloc(sizeof(*mi), GFP_KERNEL);
+ if (!mi)
+ return mi;
+ memset(mi, 0, sizeof(*mi));
+
+ /* reserve an area */
+ if (tcm_reserve_2d(tcm, w, h, align, &mi->area)) {
+ kfree(mi);
+ return NULL;
+ }
+
+ return mi;
+}
+
+/*
+ * Block operations
+ */
+
+/* free a block */
+static s32 free_block(struct mem_info *mi)
+{
+ /* release memory */
+ if (mi->mem)
+ tmm_free(tmm[tiler_fmt(mi->blk.phys)], mi->mem);
+ clear_pat(tmm[tiler_fmt(mi->blk.phys)], &mi->area);
+
+ /* unreserve area */
+ tcm_free(&mi->area);
+
+ /* have mutex */
+
+ /* safe deletion as list may not have been assigned */
+ if (mi->global.next)
+ list_del(&mi->global);
+
+ kfree(mi);
+ return 0;
+}
+
+/* create an empty block with just an area and add it to the global list */
+static struct mem_info *get_area(enum tiler_fmt fmt, u32 width, u32 height,
+ u16 align, u16 offs)
+{
+ u16 x, y;
+ struct mem_info *mi = NULL;
+ const struct tiler_geom *g = tiler.geom(fmt);
+
+ /* calculate dimensions and alignment in slots */
+ if (__analyze_area(fmt, width, height, &x, &y, &align, &offs))
+ return NULL;
+
+ mi = get_2d_area(x, y, align, tcm[fmt]);
+ if (!mi)
+ return NULL;
+
+ /* have mutex */
+ list_add(&mi->global, &blocks);
+
+ mi->blk.phys = tiler.addr(fmt,
+ mi->area.p0.x * g->slot_w, mi->area.p0.y * g->slot_h)
+ + offs;
+ return mi;
+}
+
+/* allocate a new tiler block */
+static s32 alloc_block(enum tiler_fmt fmt, u32 width, u32 height,
+ u32 align, u32 offs, struct mem_info **info)
+{
+ struct mem_info *mi = NULL;
+
+ *info = NULL;
+
+ /* only support up to page alignment */
+ if (align > PAGE_SIZE || offs >= (align ? : default_align))
+ return -EINVAL;
+
+ mutex_lock(&mtx);
+
+ /* reserve area in tiler container */
+ mi = get_area(fmt, width, height, align, offs);
+ if (!mi)
+ goto nomem;
+
+ mi->blk.width = width;
+ mi->blk.height = height;
+
+ /* allocate and map if mapping is supported */
+ if (tmm_can_map(tmm[fmt])) {
+ mi->mem = tmm_get(tmm[fmt], tcm_sizeof(mi->area));
+ if (!mi->mem)
+ goto cleanup;
+
+ /* program PAT */
+ if (refill_pat(tmm[fmt], &mi->area, mi->mem))
+ goto cleanup;
+ }
+ *info = mi;
+ mutex_unlock(&mtx);
+ return 0;
+
+cleanup:
+ free_block(mi);
+nomem:
+ mutex_unlock(&mtx);
+ return -ENOMEM;
+}
+
+/*
+ * Driver code
+ */
+
+/* driver initialization */
+static s32 __init tiler_init(void)
+{
+ s32 r = 0;
+ struct tcm *sita = NULL;
+ struct tmm *tmm_pat = NULL;
+
+ tiler_geom_init(&tiler);
+
+ /* check module parameters for correctness */
+ if (default_align > PAGE_SIZE ||
+ default_align & (default_align - 1) ||
+ granularity < 1 || granularity > PAGE_SIZE ||
+ granularity & (granularity - 1))
+ return -EINVAL;
+
+ /*
+ * Array of physical pages for PAT programming, which must be a 16-byte
+ * aligned physical address.
+ */
+ dmac_va = dma_alloc_coherent(NULL, tiler.width * tiler.height *
+ sizeof(*dmac_va), &dmac_pa, GFP_KERNEL);
+ if (!dmac_va)
+ return -ENOMEM;
+
+ /* Allocate tiler container manager (we share 1 on OMAP4) */
+ sita = sita_init(tiler.width, tiler.height, NULL);
+
+ tcm[TILFMT_8BIT] = sita;
+ tcm[TILFMT_16BIT] = sita;
+ tcm[TILFMT_32BIT] = sita;
+
+ /* Allocate tiler memory manager (must have 1 unique TMM per TCM ) */
+ tmm_pat = tmm_pat_init(0);
+ tmm[TILFMT_8BIT] = tmm_pat;
+ tmm[TILFMT_16BIT] = tmm_pat;
+ tmm[TILFMT_32BIT] = tmm_pat;
+
+ if (!sita || !tmm_pat) {
+ r = -ENOMEM;
+ goto error;
+ }
+
+ mutex_init(&mtx);
+ INIT_LIST_HEAD(&blocks);
+
+error:
+ if (r) {
+ tcm_deinit(sita);
+ tmm_deinit(tmm_pat);
+ dma_free_coherent(NULL, tiler.width * tiler.height *
+ sizeof(*dmac_va), dmac_va, dmac_pa);
+ }
+
+ return r;
+}
+
+/* driver cleanup */
+static void __exit tiler_exit(void)
+{
+ int i, j;
+ struct mem_info *mi, *mi_;
+
+ mutex_lock(&mtx);
+
+ /* free all blocks */
+ list_for_each_entry_safe(mi, mi_, &blocks, global)
+ free_block(mi);
+
+ /* all lists should have cleared */
+ BUG_ON(!list_empty(&blocks));
+
+ mutex_unlock(&mtx);
+
+ dma_free_coherent(NULL, tiler.width * tiler.height * sizeof(*dmac_va),
+ dmac_va, dmac_pa);
+
+ /* close containers only once */
+ for (i = TILFMT_MIN; i <= TILFMT_MAX; i++) {
+ /*
+ * Remove identical containers. TILER Memory Manager (TMM)
+ * is unique per TILER Container Manager (TCM)
+ */
+ for (j = i + 1; j <= TILFMT_MAX; j++)
+ if (tcm[i] == tcm[j]) {
+ tcm[j] = NULL;
+ tmm[j] = NULL;
+ }
+
+ tcm_deinit(tcm[i]);
+ tmm_deinit(tmm[i]);
+ }
+
+ mutex_destroy(&mtx);
+}
+
+/*
+ * Block Kernel APIs
+ */
+
+s32 tiler_alloc(struct tiler_block_t *blk, enum tiler_fmt fmt,
+ u32 align, u32 offs)
+{
+ struct mem_info *mi;
+ s32 res;
+
+ /* blk must be valid, and blk->phys must be 0 */
+ BUG_ON(!blk || blk->phys);
+
+ res = alloc_block(fmt, blk->width, blk->height, align, offs, &mi);
+ if (mi)
+ blk->phys = mi->blk.phys;
+ return res;
+}
+EXPORT_SYMBOL(tiler_alloc);
+
+void tiler_free(struct tiler_block_t *blk)
+{
+ struct mem_info *mi;
+
+ mutex_lock(&mtx);
+
+ /* find block */
+ list_for_each_entry(mi, &blocks, global) {
+ if (mi->blk.phys == blk->phys) {
+ free_block(mi);
+ break;
+ }
+ }
+
+ blk->phys = 0;
+
+ mutex_unlock(&mtx);
+}
+EXPORT_SYMBOL(tiler_free);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Lajos Molnar <[email protected]>");
+MODULE_AUTHOR("David Sin <[email protected]>");
+module_init(tiler_init);
+module_exit(tiler_exit);
--
1.7.0.4
From: Lajos Molnar <[email protected]>
This patch links the TILER driver into the Linux kernel build
and config system.
Signed-off-by: Lajos Molnar <[email protected]>
Signed-off-by: David Sin <[email protected]>
---
drivers/misc/Kconfig | 5 +++++
drivers/misc/Makefile | 1 +
2 files changed, 6 insertions(+), 0 deletions(-)
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index ac6d6ac..fff7927 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -378,4 +378,9 @@ source "drivers/misc/eeprom/Kconfig"
source "drivers/misc/cb710/Kconfig"
source "drivers/misc/iwmc3200top/Kconfig"
+#
+# TI TILER driver support
+#
+source "drivers/misc/tiler/Kconfig"
+
endif # MISC_DEVICES
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index bf6f0e0..9985a6f 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -33,3 +33,4 @@ obj-y += eeprom/
obj-y += cb710/
obj-$(CONFIG_VMWARE_BALLOON) += vmware_balloon.o
obj-$(CONFIG_SENSORS_BH1780) += bh1780gli.o
+obj-$(CONFIG_TI_TILER) += tiler/
--
1.7.0.4
This patch adds support for DMM-PAT initialization and programming.
Signed-off-by: David Sin <[email protected]>
Signed-off-by: Lajos Molnar <[email protected]>
---
arch/arm/mach-omap2/dmm-omap44xx.c | 81 ++++++++++++++
arch/arm/mach-omap2/include/mach/dmm.h | 92 ++++++++++++++++
drivers/misc/tiler/dmm-main.c | 187 ++++++++++++++++++++++++++++++++
3 files changed, 360 insertions(+), 0 deletions(-)
create mode 100644 arch/arm/mach-omap2/dmm-omap44xx.c
create mode 100644 arch/arm/mach-omap2/include/mach/dmm.h
create mode 100644 drivers/misc/tiler/dmm-main.c
diff --git a/arch/arm/mach-omap2/dmm-omap44xx.c b/arch/arm/mach-omap2/dmm-omap44xx.c
new file mode 100644
index 0000000..2919d8e
--- /dev/null
+++ b/arch/arm/mach-omap2/dmm-omap44xx.c
@@ -0,0 +1,81 @@
+/*
+ * DMM driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <mach/dmm.h>
+#include <plat/omap_device.h>
+#include <plat/omap_hwmod.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+
+static struct dmm *plat_data;
+static int pdata;
+
+#ifdef CONFIG_ARCH_OMAP4
+static struct dmm omap4_plat_data[] = {
+ {
+ .oh_name = "dmm",
+ },
+};
+#define NUM_PDATA ARRAY_SIZE(omap4_plat_data)
+#else
+#define omap4_plat_data NULL
+#define NUM_PDATA 0
+#endif
+
+static struct omap_device_pm_latency omap_dmm_latency[] = {
+ [0] = {
+ .deactivate_func = omap_device_idle_hwmods,
+ .activate_func = omap_device_enable_hwmods,
+ .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST,
+ },
+};
+
+static s32 __init dmm_omap_init(void)
+{
+ struct omap_hwmod *oh = NULL;
+ struct omap_device *od = NULL;
+ struct omap_device_pm_latency *ohl = NULL;
+ int ohlc = 0, i = 0;
+
+ plat_data = omap4_plat_data;
+ pdata = NUM_PDATA;
+
+ for (i = 0; i < pdata; i++) {
+ struct dmm *data = &plat_data[i];
+
+ oh = omap_hwmod_lookup(data->oh_name);
+ if (!oh)
+ goto error;
+
+ data->base = oh->_mpu_rt_va;
+ ohl = omap_dmm_latency;
+ ohlc = ARRAY_SIZE(omap_dmm_latency);
+
+ od = omap_device_build(data->oh_name, i, oh, data,
+ sizeof(*data), ohl, ohlc, false);
+ if (IS_ERR(od))
+ goto error;
+ }
+ return 0;
+error:
+ return -ENODEV;
+}
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("David Sin <[email protected]>");
+MODULE_AUTHOR("Lajos Molnar <[email protected]>");
+device_initcall(dmm_omap_init);
diff --git a/arch/arm/mach-omap2/include/mach/dmm.h b/arch/arm/mach-omap2/include/mach/dmm.h
new file mode 100644
index 0000000..33a1215
--- /dev/null
+++ b/arch/arm/mach-omap2/include/mach/dmm.h
@@ -0,0 +1,92 @@
+/*
+ * Dynamic Memory Manager (DMM) driver support functions for
+ * TI DMM-TILER hardware block.
+ *
+ * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef DMM_H
+#define DMM_H
+
+#define DMM_TILER_OR__0 0x220
+#define DMM_TILER_OR__1 0x224
+#define DMM_PAT_VIEW__0 0x420
+#define DMM_PAT_VIEW__1 0x424
+#define DMM_PAT_VIEW_MAP__0 0x440
+#define DMM_PAT_VIEW_MAP_BASE 0x460
+#define DMM_PAT_IRQSTATUS_RAW 0x480
+#define DMM_PAT_IRQSTATUS 0x490
+#define DMM_PAT_STATUS__0 0x4C0
+#define DMM_PAT_DESCR__0 0x500
+#define DMM_PAT_AREA__0 0x504
+#define DMM_PAT_CTRL__0 0x508
+#define DMM_PAT_DATA__0 0x50C
+
+/*
+ * Physical Address Translator (PAT) refill programming mode
+ */
+enum pat_mode {
+ MANUAL,
+ AUTO
+};
+
+/*
+ * Area definition for DMM physical address translator
+ */
+struct pat_area {
+ s8 x0:8;
+ s8 y0:8;
+ s8 x1:8;
+ s8 y1:8;
+};
+
+/*
+ * DMM physical address translator control
+ */
+struct pat_ctrl {
+ s32 start:4;
+ s32 dir:4;
+ s32 lut_id:8;
+ s32 sync:12;
+ s32 ini:4;
+};
+
+/*
+ * Physical Address Translator (PAT) descriptor
+ */
+struct pat {
+ struct pat *next;
+ struct pat_area area;
+ struct pat_ctrl ctrl;
+ u32 data;
+};
+
+/*
+ * DMM device data
+ */
+struct dmm {
+ const char *oh_name;
+ void __iomem *base;
+ int irq;
+};
+
+/*
+ * Create and initialize the physical address translator
+ */
+struct dmm *dmm_pat_init(u32 id);
+
+/*
+ * Program the physical address translator
+ */
+int dmm_pat_refill(struct dmm *dmm, struct pat *desc, enum pat_mode mode);
+
+#endif
diff --git a/drivers/misc/tiler/dmm-main.c b/drivers/misc/tiler/dmm-main.c
new file mode 100644
index 0000000..412f592
--- /dev/null
+++ b/drivers/misc/tiler/dmm-main.c
@@ -0,0 +1,187 @@
+/*
+ * DMM driver support functions for TI OMAP processors.
+ *
+ * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+
+#include <mach/dmm.h>
+
+#define MASK(msb, lsb) (((1 << ((msb) + 1 - (lsb))) - 1) << (lsb))
+#define SET_FLD(reg, msb, lsb, val) \
+(((reg) & ~MASK((msb), (lsb))) | (((val) << (lsb)) & MASK((msb), (lsb))))
+#define MAX_RETRY_MS 1000
+
+static struct dmm *dmm;
+
+static int dmm_probe(struct platform_device *dev)
+{
+ if (dev)
+ dmm = dev->dev.platform_data;
+
+ if (dmm && dmm->base) {
+ writel(0x88888888, dmm->base + DMM_TILER_OR__0);
+ writel(0x88888888, dmm->base + DMM_TILER_OR__1);
+ return 0;
+ }
+ return -EFAULT;
+}
+
+static int dmm_remove(struct platform_device *dev)
+{
+ return 0;
+}
+
+static struct platform_driver dmm_driver = {
+ .probe = dmm_probe,
+ .remove = dmm_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "dmm",
+ },
+};
+
+int dmm_pat_refill(struct dmm *dmm, struct pat *pd, enum pat_mode mode)
+{
+ void __iomem *r;
+ u32 v, i;
+
+ if (!dmm || !dmm->base || !pd)
+ return -EFAULT;
+
+ /* Only manual refill supported */
+ if (mode != MANUAL)
+ return -EFAULT;
+
+ /* Check that the DMM_PAT_STATUS register has not reported an error */
+ r = dmm->base + DMM_PAT_STATUS__0;
+ v = readl(r);
+ if (WARN(v & 0xFC00, KERN_ERR "dmm_pat_refill() error.\n"))
+ return -EIO;
+
+ /* Set "next" register to NULL */
+ r = dmm->base + DMM_PAT_DESCR__0;
+ v = readl(r);
+ v = SET_FLD(v, 31, 4, (u32) NULL);
+ writel(v, r);
+
+ /* Set area to be refilled */
+ r = dmm->base + DMM_PAT_AREA__0;
+ v = readl(r);
+ v = SET_FLD(v, 30, 24, pd->area.y1);
+ v = SET_FLD(v, 23, 16, pd->area.x1);
+ v = SET_FLD(v, 14, 8, pd->area.y0);
+ v = SET_FLD(v, 7, 0, pd->area.x0);
+ writel(v, r);
+
+ /* First, clear the DMM_PAT_IRQSTATUS register */
+ writel(0xFFFFFFFF, dmm->base + DMM_PAT_IRQSTATUS);
+
+ i = 1000;
+ while (readl(dmm->base + DMM_PAT_IRQSTATUS_RAW) != 0) {
+ if (--i == 0)
+ return -EFAULT;
+ udelay(1);
+ }
+
+ /* Fill data register */
+ v = readl(dmm->base + DMM_PAT_DATA__0);
+
+ v = SET_FLD(v, 31, 4, pd->data >> 4);
+ writel(v, r);
+
+ /* Read back PAT_DATA__0 to see if write was successful */
+ i = 1000;
+ while (readl(r) != pd->data) {
+ if (--i == 0)
+ return -EFAULT;
+ udelay(1);
+ }
+
+ v = readl(dmm->base + DMM_PAT_CTRL__0);
+ v = SET_FLD(v, 31, 28, pd->ctrl.ini);
+ v = SET_FLD(v, 16, 16, pd->ctrl.sync);
+ v = SET_FLD(v, 9, 8, pd->ctrl.lut_id);
+ v = SET_FLD(v, 6, 4, pd->ctrl.dir);
+ v = SET_FLD(v, 0, 0, pd->ctrl.start);
+ writel(v, r);
+
+ /* Check if PAT_IRQSTATUS_RAW is set after the PAT has been refilled */
+ i = 1000;
+ while ((readl(dmm->base + DMM_PAT_IRQSTATUS_RAW) & 0x3) != 0x3) {
+ if (--i == 0)
+ return -EFAULT;
+ udelay(1);
+ }
+
+ /* Again, clear the DMM_PAT_IRQSTATUS register */
+ writel(0xFFFFFFFF, dmm->base + DMM_PAT_IRQSTATUS);
+
+ i = 1000;
+ while (readl(dmm->base + DMM_PAT_IRQSTATUS_RAW) != 0) {
+ if (--i == 0)
+ return -EFAULT;
+ udelay(1);
+ }
+
+ /* Again, set "next" register to NULL to clear any PAT STATUS errors */
+ v = readl(dmm->base + DMM_PAT_DESCR__0);
+ v = SET_FLD(v, 31, 4, (u32) NULL);
+ writel(v, r);
+
+ /*
+ * Now, check that the DMM_PAT_STATUS register
+ * has not reported an error before exiting.
+ */
+ v = readl(dmm->base + DMM_PAT_STATUS__0);
+ if (WARN(v & 0xFC00, KERN_ERR "dmm_pat_refill() error.\n"))
+ return -EIO;
+
+ return 0;
+}
+EXPORT_SYMBOL(dmm_pat_refill);
+
+struct dmm *dmm_pat_init(u32 id)
+{
+ if (dmm && dmm->base) {
+ writel(0x88888888, dmm->base + DMM_PAT_VIEW__0);
+ writel(0x88888888, dmm->base + DMM_PAT_VIEW__1);
+ writel(0x80808080, dmm->base + DMM_PAT_VIEW_MAP__0);
+ writel(0x80000000, dmm->base + DMM_PAT_VIEW_MAP_BASE);
+ }
+
+ return dmm;
+}
+EXPORT_SYMBOL(dmm_pat_init);
+
+static s32 __init dmm_init(void)
+{
+ return platform_driver_register(&dmm_driver);
+}
+
+static void __exit dmm_exit(void)
+{
+ platform_driver_unregister(&dmm_driver);
+}
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("David Sin <[email protected]>");
+MODULE_AUTHOR("Lajos Molnar <[email protected]>");
+module_init(dmm_init);
+module_exit(dmm_exit);
--
1.7.0.4
From: Lajos Molnar <[email protected]>
This patch defined the TILER Container Manager (TCM) interface and
provides utility methods for implementing a TCM.
Signed-off-by: Lajos Molnar <[email protected]>
Signed-off-by: David Sin <[email protected]>
Signed-off-by: Ravi Ramachandra <[email protected]>
---
drivers/misc/tiler/tcm.h | 171 ++++++++++++++++++++++++++++++++++++
drivers/misc/tiler/tcm/tcm-utils.h | 51 +++++++++++
2 files changed, 222 insertions(+), 0 deletions(-)
create mode 100644 drivers/misc/tiler/tcm.h
create mode 100644 drivers/misc/tiler/tcm/tcm-utils.h
diff --git a/drivers/misc/tiler/tcm.h b/drivers/misc/tiler/tcm.h
new file mode 100644
index 0000000..8968108
--- /dev/null
+++ b/drivers/misc/tiler/tcm.h
@@ -0,0 +1,171 @@
+/*
+ * TILER container manager specification and support functions for TI
+ * TILER driver.
+ *
+ * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef TCM_H
+#define TCM_H
+
+struct tcm;
+
+/* point */
+struct tcm_pt {
+ u16 x;
+ u16 y;
+};
+
+/* 2d area */
+struct tcm_area {
+ struct tcm *tcm; /* parent */
+ struct tcm_pt p0;
+ struct tcm_pt p1;
+};
+
+struct tcm {
+ u16 width, height; /* container dimensions */
+
+ /*
+ * 'pvt' structure shall contain any tcm details (attr) along with
+ * linked list of allocated areas and mutex for mutually exclusive
+ * access to the list. It may also contain copies of width and height
+ * to notice any changes to the publicly available width and height
+ * fields.
+ */
+ void *pvt;
+
+ /* function table */
+ s32 (*reserve_2d)(struct tcm *tcm, u16 height, u16 width, u8 align,
+ struct tcm_area *area);
+ s32 (*free) (struct tcm *tcm, struct tcm_area *area);
+ void (*deinit) (struct tcm *tcm);
+};
+
+/*
+ * Since some basic parameter checking is done outside the TCM algorithms,
+ * TCM implementation do NOT have to check the following:
+ *
+ * area pointer is NULL
+ * width and height fits within container
+ * number of pages is more than the size of the container
+ */
+
+/*
+ * Template for <ALGO_NAME>_tcm_init method. Define as:
+ * TCM_INIT(<ALGO_NAME>_tcm_init)
+ *
+ * Allocates and initializes a tiler container manager.
+ *
+ * Pointer to the allocated and initialized container manager.
+ * NULL on failure. DO NOT leak any memory on failure!
+ */
+#define TCM_INIT(name, attr_t) \
+struct tcm *name(u16 width, u16 height, typeof(attr_t) *attr);
+
+/*
+ * Deinitialize tiler container manager.
+ *
+ * The call should free as much memory as possible and meaningful
+ * even on failure. Some error codes: -ENODEV: invalid manager.
+ */
+static inline void tcm_deinit(struct tcm *tcm)
+{
+ if (tcm)
+ tcm->deinit(tcm);
+}
+
+/*
+ * Reserves a 2D area in the container.
+ *
+ * The tcm field of the area will be set to NULL on failure.
+ * Some error codes: -ENODEV: invalid manager, -EINVAL:
+ * invalid area, -ENOMEM: not enough space for allocation.
+ */
+static inline s32 tcm_reserve_2d(struct tcm *tcm, u16 width, u16 height,
+ u16 align, struct tcm_area *area)
+{
+ /* perform rudimentary error checking */
+ s32 res = (tcm == NULL ? -ENODEV :
+ (area == NULL || width == 0 || height == 0 ||
+ /* align must be a 2 power */
+ align & (align - 1)) ? -EINVAL :
+ (height > tcm->height || width > tcm->width) ? -ENOMEM :
+ tcm->reserve_2d(tcm, height, width, align, area));
+
+ if (area)
+ area->tcm = res ? NULL : tcm;
+
+ return res;
+}
+
+/*
+ * Free a previously reserved area from the container.
+ *
+ * The tcm field of the area is set to NULL on success
+ * to avoid subsequent freeing. This call will succeed
+ * even if supplying the area from a failed reserved call.
+ */
+static inline s32 tcm_free(struct tcm_area *area)
+{
+ s32 res = 0; /* free succeeds by default */
+
+ if (area && area->tcm) {
+ res = area->tcm->free(area->tcm, area);
+ if (res == 0)
+ area->tcm = NULL;
+ }
+
+ return res;
+}
+
+/* Verify if a tcm area is logically valid */
+static inline bool tcm_area_is_valid(struct tcm_area *area)
+{
+ return area && area->tcm &&
+ /* coordinate bounds */
+ area->p1.x < area->tcm->width &&
+ area->p1.y < area->tcm->height &&
+ area->p0.y <= area->p1.y &&
+ area->p0.x <= area->p1.x;
+}
+
+/* see if a coordinate is within an area */
+static inline bool __tcm_is_in(struct tcm_pt *p, struct tcm_area *a)
+{
+ return p->x >= a->p0.x && p->x <= a->p1.x &&
+ p->y >= a->p0.y && p->y <= a->p1.y;
+}
+
+/* calculate area width */
+static inline u16 __tcm_area_width(struct tcm_area *area)
+{
+ return area->p1.x - area->p0.x + 1;
+}
+
+/* calculate area height */
+static inline u16 __tcm_area_height(struct tcm_area *area)
+{
+ return area->p1.y - area->p0.y + 1;
+}
+
+/* calculate number of slots in an area */
+static inline u16 __tcm_sizeof(struct tcm_area *area)
+{
+ return __tcm_area_width(area) * __tcm_area_height(area);
+}
+#define tcm_sizeof(area) __tcm_sizeof(&(area))
+#define tcm_awidth(area) __tcm_area_width(&(area))
+#define tcm_aheight(area) __tcm_area_height(&(area))
+#define tcm_is_in(pt, area) __tcm_is_in(&(pt), &(area))
+
+#endif
diff --git a/drivers/misc/tiler/tcm/tcm-utils.h b/drivers/misc/tiler/tcm/tcm-utils.h
new file mode 100644
index 0000000..400c2fe
--- /dev/null
+++ b/drivers/misc/tiler/tcm/tcm-utils.h
@@ -0,0 +1,51 @@
+/*
+ * Utility functions for implementing TILER container managers.
+ *
+ * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef TCM_UTILS_H
+#define TCM_UTILS_H
+
+#include "../tcm.h"
+
+/* TCM_ALG_NAME must be defined to use the debug methods */
+
+#ifdef DEBUG
+#define IFDEBUG(x) x
+#else
+/* compile-check debug statements even if not DEBUG */
+#define IFDEBUG(x) do { if (0) x; } while (0)
+#endif
+
+#define P(level, fmt, ...) \
+ IFDEBUG(printk(level TCM_ALG_NAME ":%d:%s()" fmt "\n", \
+ __LINE__, __func__, ##__VA_ARGS__))
+
+#define P1(fmt, ...) P(KERN_NOTICE, fmt, ##__VA_ARGS__)
+#define P2(fmt, ...) P(KERN_INFO, fmt, ##__VA_ARGS__)
+#define P3(fmt, ...) P(KERN_DEBUG, fmt, ##__VA_ARGS__)
+
+#define PA(level, msg, p_area) P##level(msg " (%03d %03d)-(%03d %03d)\n", \
+ (p_area)->p0.x, (p_area)->p0.y, (p_area)->p1.x, (p_area)->p1.y)
+
+/* assign coordinates to area */
+static inline
+void assign(struct tcm_area *a, u16 x0, u16 y0, u16 x1, u16 y1)
+{
+ a->p0.x = x0;
+ a->p0.y = y0;
+ a->p1.x = x1;
+ a->p1.y = y1;
+}
+
+#endif
--
1.7.0.4
On Tue, 30 Nov 2010 13:58:58 -0600 David Sin wrote:
> From: Lajos Molnar <[email protected]>
>
> This patch contains the TILER driver and implementation of the TILER
> block manipulation and mapping functions.
>
> It also contains the makefile and config file for the TILER driver.
>
> Signed-off-by: Lajos Molnar <[email protected]>
> Signed-off-by: David Sin <[email protected]>
> ---
> arch/arm/mach-omap2/Makefile | 1 +
> drivers/misc/tiler/Kconfig | 72 +++++++
> drivers/misc/tiler/Makefile | 7 +
> drivers/misc/tiler/tiler-iface.c | 66 ++++++
> drivers/misc/tiler/tiler-main.c | 405 ++++++++++++++++++++++++++++++++++++++
> 5 files changed, 551 insertions(+), 0 deletions(-)
> create mode 100644 drivers/misc/tiler/Kconfig
> create mode 100644 drivers/misc/tiler/Makefile
> create mode 100644 drivers/misc/tiler/tiler-iface.c
> create mode 100644 drivers/misc/tiler/tiler-main.c
> diff --git a/drivers/misc/tiler/Kconfig b/drivers/misc/tiler/Kconfig
> new file mode 100644
> index 0000000..9b8bfed
> --- /dev/null
> +++ b/drivers/misc/tiler/Kconfig
> @@ -0,0 +1,72 @@
> +config HAVE_TI_DMM
> + bool
> + default y
> + depends on ARCH_OMAP4
> +
> +menuconfig TI_DMM
> + tristate "TI DMM support"
> + default y
> + depends on HAVE_TI_DMM
> + help
> + DMM driver for TI chips.
> +
> +menuconfig TI_TILER
> + tristate "TI TILER support"
> + default y
> + depends on TI_DMM
> + help
> + TILER driver for TI chips. The TI TILER device
> + enables video rotation on certain TI chips such as OMAP4 or
> + TI816x. Video rotation will be limited without TILER support.
> +
> +config TILER_GRANULARITY
> + int "Allocation granularity (2^n)"
Having (2^n) in the prompt makes me think that the value set here is "n",
but that's not the case. I suggest removing (2^n) here...
> + range 1 4096
> + default 128
> + depends on TI_TILER
> + help
> + This option sets the default TILER allocation granularity. It can
> + be overriden by the tiler.grain boot argument.
> +
> + The allocation granularity is the smallest TILER block size (in
> + bytes) managed distinctly by the TILER driver. TILER blocks of any
> + size are managed in chunks of at least this size.
> +
> + Must be a 2^n in the range of 1 to 4096; however, the TILER driver
and changing 2^n here to just say:
Must be a power of 2 in the range of 1 to 4096; however, ...
and then same 2 comments again repeated below.
> + may use a larger supported granularity.
> +
> + Supported values are: 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024,
> + 2048, 4096.
> +
> +config TILER_ALIGNMENT
> + int "Allocation alignment (2^n)"
> + range 1 4096
> + default 4096
> + depends on TI_TILER
> + help
> + This option sets the default TILER allocation alignment. It can
> + be overriden by the tiler.align boot argument.
> +
> + Must be a 2^n in the range of 1 to 4096; however, it is naturally
> + aligned to the TILER granularity.
> +
> + Supported values are: 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024,
> + 2048, 4096.
---
~Randy
*** Remember to use Documentation/SubmitChecklist when testing your code ***
On Tue, Nov 30, 2010 at 01:58:59PM -0600, David Sin wrote:
> From: Lajos Molnar <[email protected]>
>
> This patch links the TILER driver into the Linux kernel build
> and config system.
>
> Signed-off-by: Lajos Molnar <[email protected]>
> Signed-off-by: David Sin <[email protected]>
> ---
> drivers/misc/Kconfig | 5 +++++
> drivers/misc/Makefile | 1 +
> 2 files changed, 6 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
> index ac6d6ac..fff7927 100644
> --- a/drivers/misc/Kconfig
> +++ b/drivers/misc/Kconfig
> @@ -378,4 +378,9 @@ source "drivers/misc/eeprom/Kconfig"
> source "drivers/misc/cb710/Kconfig"
> source "drivers/misc/iwmc3200top/Kconfig"
>
> +#
> +# TI TILER driver support
> +#
Comments not needed.
thanks,
greg k-h
On Tue, Nov 30, 2010 at 01:58:56PM -0600, David Sin wrote:
> From: Lajos Molnar <[email protected]>
>
> This patch contains the TILER interface file and the documentation.
>
> Signed-off-by: Lajos Molnar <[email protected]>
> Signed-off-by: David Sin <[email protected]>
> ---
> Documentation/arm/OMAP/TILER | 126 ++++++++++++++++++++++
> arch/arm/mach-omap2/include/mach/tiler.h | 173 ++++++++++++++++++++++++++++++
Shouldn't this .h file be in include/linux/ instead? Why is it arch
specific?
thanks,
greg k-h
On Tue, Nov 30, 2010 at 01:58:57PM -0600, David Sin wrote:
> From: Lajos Molnar <[email protected]>
>
> This patch contains information on TILER geometry, as well as
> tiler_view_t object manipulation functions.
>
> It also contains an internal TILER header file to share geometric
> information with other TILER files.
>
> Signed-off-by: Lajos Molnar <[email protected]>
> Signed-off-by: David Sin <[email protected]>
> ---
> drivers/misc/tiler/_tiler.h | 48 +++++
Ick, no, just name it "tiler.h" please. There should not be any need to
put _ in front of a .h file.
> +u32 tiler_bpp(const struct tiler_block_t *b)
> +{
> + enum tiler_fmt fmt = tiler_fmt(b->phys);
> + BUG_ON(fmt == TILFMT_INVALID || fmt == TILFMT_PAGE);
Don't cause the kernel to crash within a driver for no good reason like
this. Please fix these to WARN_ON if it's really something that can
happen.
If not, then just remove it.
> +
> + return geom[fmt].bpp;
> +}
> +EXPORT_SYMBOL(tiler_bpp);
EXPORT_SYMBOL_GPL() perhaps for all of these?
thanks,
greg k-h
David,
On Wed, Dec 1, 2010 at 01:28, David Sin <[email protected]> wrote:
> This patch adds support for DMM-PAT initialization and programming.
>
> Signed-off-by: David Sin <[email protected]>
> Signed-off-by: Lajos Molnar <[email protected]>
> ---
> ?arch/arm/mach-omap2/dmm-omap44xx.c ? ? | ? 81 ++++++++++++++
> ?arch/arm/mach-omap2/include/mach/dmm.h | ? 92 ++++++++++++++++
> ?drivers/misc/tiler/dmm-main.c ? ? ? ? ?| ?187 ++++++++++++++++++++++++++++++++
> ?3 files changed, 360 insertions(+), 0 deletions(-)
> ?create mode 100644 arch/arm/mach-omap2/dmm-omap44xx.c
> ?create mode 100644 arch/arm/mach-omap2/include/mach/dmm.h
> ?create mode 100644 drivers/misc/tiler/dmm-main.c
>
> diff --git a/arch/arm/mach-omap2/dmm-omap44xx.c b/arch/arm/mach-omap2/dmm-omap44xx.c
> new file mode 100644
> index 0000000..2919d8e
> --- /dev/null
> +++ b/arch/arm/mach-omap2/dmm-omap44xx.c
> @@ -0,0 +1,81 @@
> +/*
> + * DMM driver support functions for TI OMAP processors.
> + *
> + * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
> + *
> + * 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 version 2.
> + *
> + * This program is distributed "as is" WITHOUT ANY WARRANTY of any
> + * kind, whether express or implied; without even the implied warranty
> + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ?See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <mach/dmm.h>
> +#include <plat/omap_device.h>
> +#include <plat/omap_hwmod.h>
> +#include <linux/errno.h>
> +#include <linux/err.h>
> +
> +static struct dmm *plat_data;
> +static int pdata;
> +
> +#ifdef CONFIG_ARCH_OMAP4
Do not use these #ifdefs as it would not work as intended in multi-omap build.
This driver is making use of omap_hwmod fw. Try to take advantage of hwmod_fw
and avoid these checks.
> +static struct dmm omap4_plat_data[] = {
> + ? ? ? {
> + ? ? ? ? ? ? ? .oh_name = "dmm",
Do not use "oh_name" as it is confusing.
> + ? ? ? },
> +};
> +#define NUM_PDATA ARRAY_SIZE(omap4_plat_data)
> +#else
> +#define omap4_plat_data NULL
> +#define NUM_PDATA 0
> +#endif
> +
> +static struct omap_device_pm_latency omap_dmm_latency[] = {
> + ? ? ? [0] = {
> + ? ? ? ? ? ? ? .deactivate_func = omap_device_idle_hwmods,
> + ? ? ? ? ? ? ? .activate_func = omap_device_enable_hwmods,
> + ? ? ? ? ? ? ? .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST,
> + ? ? ? },
> +};
> +
> +static s32 __init dmm_omap_init(void)
> +{
> + ? ? ? struct omap_hwmod *oh = NULL;
> + ? ? ? struct omap_device *od = NULL;
> + ? ? ? struct omap_device_pm_latency *ohl = NULL;
Any specific reson for not assigning it directly to omap_dmm_latency?
I think this is redundant and omap_dmm_latency can be directly passed
to omap_device_build()
> + ? ? ? int ohlc = 0, i = 0;
> +
> + ? ? ? plat_data = omap4_plat_data;
> + ? ? ? pdata = NUM_PDATA;
name "pdata" is confusing. Also no need to iterate over the list of
devices using
NUM_PDATA. If you have multiple devices, make use of hwmod class.
> +
> + ? ? ? for (i = 0; i < pdata; i++) {
> + ? ? ? ? ? ? ? struct dmm *data = &plat_data[i];
> +
> + ? ? ? ? ? ? ? oh = omap_hwmod_lookup(data->oh_name)
I do not find any other devices sharing same name for the device name
and oh->name.
Normally the device's name is preferred to be "omap_devname.id" to be
consistent across all drivers
and the oh->name is given as "devname(id)"
example: McSPI's device name could be "omap_mcspi" and it's hwmod name
could be "mcspi"
> + ? ? ? ? ? ? ? if (!oh)
> + ? ? ? ? ? ? ? ? ? ? ? goto error;
> +
> + ? ? ? ? ? ? ? data->base = oh->_mpu_rt_va;
not required. Make use of platform_get APIs in probe to extract the
base, dma and irq info using pdev.
> + ? ? ? ? ? ? ? ohl = omap_dmm_latency;
> + ? ? ? ? ? ? ? ohlc = ARRAY_SIZE(omap_dmm_latency);
> +
> + ? ? ? ? ? ? ? od = omap_device_build(data->oh_name, i, oh, data,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?sizeof(*data), ohl, ohlc, false);
> + ? ? ? ? ? ? ? if (IS_ERR(od))
> + ? ? ? ? ? ? ? ? ? ? ? goto error;
> + ? ? ? }
> + ? ? ? return 0;
> +error:
> + ? ? ? return -ENODEV;
print the error message.
> +}
> +
> +MODULE_LICENSE("GPL v2");
> +MODULE_AUTHOR("David Sin <[email protected]>");
> +MODULE_AUTHOR("Lajos Molnar <[email protected]>");
> +device_initcall(dmm_omap_init);
<<snip>>
On Wed, Dec 1, 2010 at 01:28, David Sin <[email protected]> wrote:
> Tiling and Isometric Lightweight Engine for Rotation (TILER) driver
>
> Dynamic Memory Manager (DMM) is a hardware block made by Texas Instruments.
> Within the DMM exists at least one TILER hardware component. ?Its purpose is to
> organize video/image memory in a 2-dimensional fashion to limit memory
> bandwidth and facilitate 0 effort rotation and mirroring. ?The TILER driver
> facilitates allocating, freeing, as well as mapping 2D blocks (areas) in the
> TILER container(s). ?It also facilitates rotating and mirroring the allocated
> blocks or its rectangular subsections.
>
> TERMINOLOGY
>
> "slot"
>
> The basic TILER driver operates on blocks of slots. ?A slot is the granularity
> of the TILER hardware device. ?For all current uses it is 4K, but could also be
> 16 or 64K. ?The DMM-TILER TRM refers to this as "page" but we want to separate
> this concept from the MMU pages.
>
> "page"
>
> The granularity of the MMU, used by the kernel. ?This is 4K.
>
> "block"
>
> The TILER hardware component supports 1D and 2D blocks. ?A 2D block is a
> rectangular arrangement of slots with arbitrary width and height in a 2D
> container. ?A 1D block is a linear arrangement of slots with arbitrary length
> ?in a 1D container. ?This TILER driver only supports 2D blocks.
>
> "container"
>
> The TILER driver supports an arbitrary TILER container size. ?However, for
> all current implementations it is 256 by 128 slots. ?The container currently can
> only be used as a 2D container.
>
> "reserved area"
>
> Each block resides within a reserved area in the container. ?This area may
> be larger than the actual set of slots that a block occupies. ?The reason for
> this is to protect access from one block into another. ?Since TILER container is
> mmap-ped into user space as individual pages, all slots that are spanned by
> that page become visible to the user. ?The tiler driver allows restricting the
> granularity of the reserved area (default alignment) as well as the mapped
> area (granularity).
>
> Changes made from RFC v1: http://www.spinics.net/lists/linux-omap/msg33867.html
>
> Santosh Shilimkar:
> 1) Correct documentation location
> 2) Remove ioremap of RAM
> 3) Implement probe function and hwmod
> 4) Correct commenting style
> 5) Reduce use of barrier instances
>
> Linus Walleij:
> 1) Define TCM acryonym
>
> Russell King:
> 1) Implement probe function
> 2) Fix spelling mistake
> 3) Remove GFP_ATOMIC flag when calling dma_alloc_coherent for PAT array mem
> 4) Replace alloc_page and flush range calls with dma_alloc_coherent
>
> Nishanth Menon:
> 1) Address infinite while loop when reading dmm register
>
> Benoit Cousson:
> 1) Fix source file headers
> 2) Correct logical errors in device file
>
> Kevin Hilman:
> 1) Move DMM/TILER source code into driver/misc/tiler until a recommendation
> is made as to where it should go
>
> List of pending items in proposed order:
>
> * Determine driver source code location
> ?(Currently, resides in drivers/misc/tiler)
> * Add area packing support (multiple blocks can reside in the same band/area)
> ?to optimize area use
> * Add group-ID support (to specify which blocks can reside together in the
> ?same area)
> * Add multiple search directions to TCM-SiTA
> * Add 1D block support (including adding 1D search algo to TCM-SiTA)
> * Optimize mutex handling (don.t hold mutex during memory
> ?allocation/mapping/cache flushing)
> * Add block reference counting, support for sharing blocks
> * Move all kernel-API-s to tiler-iface.c
> * Support orphaned block support (in preparation for process cleanup support)
> * Change block identification from physical address to key-ID pair
> ?(in preparation for user space support, and process security)
> * Add support for process security (blocks from separate processes never
> ?reside in the same band)
> * Support file interface (ioctl and mmap)
> * Support for buffers (ordered list of blocks that are mapped to userspace
> ?together, such as YUV420sp)
> * Support 1D user buffer mapping into TILER container
> * Support for block pre-reservation (to further optimize area use)
>
> David Sin (1):
> ?TILER-DMM: DMM-PAT driver for TI TILER
>
> Lajos Molnar (6):
> ?TILER-DMM: Container manager interface and utility definitons
> ?TILER-DMM: TILER Memory Manager interface and implementation
> ?TILER-DMM: TILER interface file and documentation
> ?TILER-DMM: Geometry and view manipulation functions
> ?TILER-DMM: Main TILER driver implementation
> ?TILER-DMM: Linking TILER driver into the Linux kernel build
>
> Ravi Ramachandra (1):
> ?TILER-DMM: Sample TCM implementation: Simple TILER Allocator (SiTA)
>
> ?Documentation/arm/OMAP/TILER ? ? ? ? ? ? | ?126 +++++++++
> ?arch/arm/mach-omap2/Makefile ? ? ? ? ? ? | ? ?1 +
> ?arch/arm/mach-omap2/dmm-omap44xx.c ? ? ? | ? 81 ++++++
> ?arch/arm/mach-omap2/include/mach/dmm.h ? | ? 92 +++++++
> ?arch/arm/mach-omap2/include/mach/tiler.h | ?173 ++++++++++++
> ?drivers/misc/Kconfig ? ? ? ? ? ? ? ? ? ? | ? ?5 +
> ?drivers/misc/Makefile ? ? ? ? ? ? ? ? ? ?| ? ?1 +
> ?drivers/misc/tiler/Kconfig ? ? ? ? ? ? ? | ? 72 +++++
> ?drivers/misc/tiler/Makefile ? ? ? ? ? ? ?| ? ?7 +
> ?drivers/misc/tiler/_tiler.h ? ? ? ? ? ? ?| ? 48 ++++
> ?drivers/misc/tiler/dmm-main.c ? ? ? ? ? ?| ?187 +++++++++++++
> ?drivers/misc/tiler/tcm.h ? ? ? ? ? ? ? ? | ?171 ++++++++++++
> ?drivers/misc/tiler/tcm/Makefile ? ? ? ? ?| ? ?1 +
> ?drivers/misc/tiler/tcm/_tcm-sita.h ? ? ? | ? 61 +++++
> ?drivers/misc/tiler/tcm/tcm-sita.c ? ? ? ?| ?422 ++++++++++++++++++++++++++++++
> ?drivers/misc/tiler/tcm/tcm-sita.h ? ? ? ?| ? 28 ++
> ?drivers/misc/tiler/tcm/tcm-utils.h ? ? ? | ? 51 ++++
> ?drivers/misc/tiler/tiler-geom.c ? ? ? ? ?| ?362 +++++++++++++++++++++++++
> ?drivers/misc/tiler/tiler-iface.c ? ? ? ? | ? 66 +++++
> ?drivers/misc/tiler/tiler-main.c ? ? ? ? ?| ?405 ++++++++++++++++++++++++++++
> ?drivers/misc/tiler/tmm-pat.c ? ? ? ? ? ? | ?266 +++++++++++++++++++
> ?drivers/misc/tiler/tmm.h ? ? ? ? ? ? ? ? | ?103 ++++++++
> ?22 files changed, 2729 insertions(+), 0 deletions(-)
> ?create mode 100644 Documentation/arm/OMAP/TILER
> ?create mode 100644 arch/arm/mach-omap2/dmm-omap44xx.c
> ?create mode 100644 arch/arm/mach-omap2/include/mach/dmm.h
> ?create mode 100644 arch/arm/mach-omap2/include/mach/tiler.h
> ?create mode 100644 drivers/misc/tiler/Kconfig
> ?create mode 100644 drivers/misc/tiler/Makefile
> ?create mode 100644 drivers/misc/tiler/_tiler.h
> ?create mode 100644 drivers/misc/tiler/dmm-main.c
> ?create mode 100644 drivers/misc/tiler/tcm.h
> ?create mode 100644 drivers/misc/tiler/tcm/Makefile
> ?create mode 100644 drivers/misc/tiler/tcm/_tcm-sita.h
> ?create mode 100644 drivers/misc/tiler/tcm/tcm-sita.c
> ?create mode 100644 drivers/misc/tiler/tcm/tcm-sita.h
> ?create mode 100644 drivers/misc/tiler/tcm/tcm-utils.h
> ?create mode 100644 drivers/misc/tiler/tiler-geom.c
> ?create mode 100644 drivers/misc/tiler/tiler-iface.c
> ?create mode 100644 drivers/misc/tiler/tiler-main.c
> ?create mode 100644 drivers/misc/tiler/tmm-pat.c
> ?create mode 100644 drivers/misc/tiler/tmm.h
The dmm driver is making use of omap_hwmod fw. But I could not see a patch
to add dmm hwmod data to omap4 hwmod base in this series. Is this patch series
tested?
On Wed, Dec 1, 2010 at 12:04 AM, Varadarajan, Charulatha <[email protected]> wrote:
> David,
>
>> + ? ? ? ? ? ? ? if (!oh)
>> + ? ? ? ? ? ? ? ? ? ? ? goto error;
>> +
>> + ? ? ? ? ? ? ? data->base = oh->_mpu_rt_va;
>
> not required. Make use of platform_get APIs in probe to extract the
> base, dma and irq info using pdev.
Not sure about using platform_get APIs. I think one has to use
omap_hwmod_get_mpu_rt_va to get the address, which internally returns
oh-<_mpu_rt_va.
omap_hwmod_get_mpu_rt_va was added so that the individual drivers can
avoid doing the ioremap.
check the discussion regarding this.
http://www.spinics.net/lists/linux-omap/msg33048.html
Thank you,
Best regards,
Hari Kanigeri
On Wed, Dec 1, 2010 at 8:10 PM, Kanigeri, Hari <[email protected]> wrote:
> On Wed, Dec 1, 2010 at 12:04 AM, Varadarajan, Charulatha <[email protected]> wrote:
>> David,
>
>>
>>> + ? ? ? ? ? ? ? if (!oh)
>>> + ? ? ? ? ? ? ? ? ? ? ? goto error;
>>> +
>>> + ? ? ? ? ? ? ? data->base = oh->_mpu_rt_va;
>>
>> not required. Make use of platform_get APIs in probe to extract the
>> base, dma and irq info using pdev.
>
> Not sure about using platform_get APIs. I think one has to use
> omap_hwmod_get_mpu_rt_va to get the address, which internally returns
> oh-<_mpu_rt_va.
small correction... omap_device_get_rt_va and not omap_hwmod_get_mpu_rt_va.
Thank you,
Best regards,
Hari Kanigeri
On Thu, Dec 2, 2010 at 07:57, Kanigeri, Hari <[email protected]> wrote:
> On Wed, Dec 1, 2010 at 8:10 PM, Kanigeri, Hari <[email protected]> wrote:
>> On Wed, Dec 1, 2010 at 12:04 AM, Varadarajan, Charulatha <[email protected]> wrote:
>>> David,
>>
>>>
>>>> + ? ? ? ? ? ? ? if (!oh)
>>>> + ? ? ? ? ? ? ? ? ? ? ? goto error;
>>>> +
>>>> + ? ? ? ? ? ? ? data->base = oh->_mpu_rt_va;
>>>
>>> not required. Make use of platform_get APIs in probe to extract the
>>> base, dma and irq info using pdev.
>>
>> Not sure about using platform_get APIs. I think one has to use
>> omap_hwmod_get_mpu_rt_va to get the address, which internally returns
>> oh-<_mpu_rt_va.
> small correction... omap_device_get_rt_va and not omap_hwmod_get_mpu_rt_va.
To get the base address & irq, you need not have to use
omap_device_get_rt_va and pass it as
pdata and then use it during probe. Instead in probe, you may do
something like the following:
static int __devinit dev_probe (*pdev) {
struct resource *res;
void __iomem *base;
u16 irq;
....
....
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (unlikely(!res)) {
....
return -ENODEV;
}
base = ioremap(res->start, resource_size(res));
if (base) {
....
return -ENOMEM;
}
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (unlikely(!res)) {
....
return -ENODEV;
}
irq = res->start;
....
....
}
-V Charulatha
On Wed, Dec 1, 2010 at 11:16 PM, Varadarajan, Charulatha <[email protected]> wrote:
> On Thu, Dec 2, 2010 at 07:57, Kanigeri, Hari <[email protected]> wrote:
>> On Wed, Dec 1, 2010 at 8:10 PM, Kanigeri, Hari <[email protected]> wrote:
>>> On Wed, Dec 1, 2010 at 12:04 AM, Varadarajan, Charulatha <[email protected]> wrote:
>>>> David,
>>>
>>>>
>>>>> + ? ? ? ? ? ? ? if (!oh)
>>>>> + ? ? ? ? ? ? ? ? ? ? ? goto error;
>>>>> +
>>>>> + ? ? ? ? ? ? ? data->base = oh->_mpu_rt_va;
>>>>
>>>> not required. Make use of platform_get APIs in probe to extract the
>>>> base, dma and irq info using pdev.
>>>
>>> Not sure about using platform_get APIs. I think one has to use
>>> omap_hwmod_get_mpu_rt_va to get the address, which internally returns
>>> oh-<_mpu_rt_va.
>> small correction... omap_device_get_rt_va and not omap_hwmod_get_mpu_rt_va.
>
> To get the base address & irq, you need not have to use
> omap_device_get_rt_va and pass it as
> pdata and then use it during probe. Instead in probe, you may do
> something like the following:
If hwmod framework is already doing the ioremap on device address,
then it is better to use it rather than duplicating the ioremap part
again in probe function.
>From what I understand regarding omap_device_get_rt_va() function, it
is added so that Driver's can avoid doing ioremap.
check Santosh's comment on this API
http://www.spinics.net/lists/arm-kernel/msg92260.html
>
> static int __devinit ?dev_probe (*pdev) {
> ? struct resource *res;
> ? void __iomem *base;
> ? u16 irq;
> ? ....
> ? ....
> ? res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> ? if (unlikely(!res)) {
> ? ? ? ? ? ? ?....
> ? ? ? ? ? ? ?return -ENODEV;
> ? }
>
> ? base = ioremap(res->start, resource_size(res));
> ? if (base) {
> ? ? ? ? ? ? ? ....
> ? ? ? ? ? ? ? return -ENOMEM;
> ? }
>
> ? res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
> ? if (unlikely(!res)) {
> ? ? ? ? ? ? ? ....
> ? ? ? ? ? ? ? return -ENODEV;
> ? }
> ? irq = res->start;
> ? ....
> ? ....
> }
>
> -V Charulatha
> --
> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> the body of a message to [email protected]
> More majordomo info at ?http://vger.kernel.org/majordomo-info.html
>
On Thu, Dec 2, 2010 at 15:53, Hari Kanigeri <[email protected]> wrote:
> On Wed, Dec 1, 2010 at 11:16 PM, Varadarajan, Charulatha <[email protected]> wrote:
>> On Thu, Dec 2, 2010 at 07:57, Kanigeri, Hari <[email protected]> wrote:
>>> On Wed, Dec 1, 2010 at 8:10 PM, Kanigeri, Hari <[email protected]> wrote:
>>>> On Wed, Dec 1, 2010 at 12:04 AM, Varadarajan, Charulatha <[email protected]> wrote:
>>>>> David,
>>>>
>>>>>
>>>>>> + ? ? ? ? ? ? ? if (!oh)
>>>>>> + ? ? ? ? ? ? ? ? ? ? ? goto error;
>>>>>> +
>>>>>> + ? ? ? ? ? ? ? data->base = oh->_mpu_rt_va;
>>>>>
>>>>> not required. Make use of platform_get APIs in probe to extract the
>>>>> base, dma and irq info using pdev.
>>>>
>>>> Not sure about using platform_get APIs. I think one has to use
>>>> omap_hwmod_get_mpu_rt_va to get the address, which internally returns
>>>> oh-<_mpu_rt_va.
>>> small correction... omap_device_get_rt_va and not omap_hwmod_get_mpu_rt_va.
>>
>> To get the base address & irq, you need not have to use
>> omap_device_get_rt_va and pass it as
>> pdata and then use it during probe. Instead in probe, you may do
>> something like the following:
>
> If hwmod framework is already doing the ioremap on device address,
> then it is better to use it rather than duplicating the ioremap part
> again in probe function.
> From what I understand regarding omap_device_get_rt_va() function, it
> is added so that Driver's can avoid doing ioremap.
> check Santosh's comment on this API
> http://www.spinics.net/lists/arm-kernel/msg92260.html
Okay. For base address, I agree, as it avoids redoing ioremap in drivers.
For "irq" & "DMA", it is still required to use platform_get*() APIs.
>
>>
>> static int __devinit ?dev_probe (*pdev) {
>> ? struct resource *res;
>> ? void __iomem *base;
>> ? u16 irq;
>> ? ....
>> ? ....
>> ? res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> ? if (unlikely(!res)) {
>> ? ? ? ? ? ? ?....
>> ? ? ? ? ? ? ?return -ENODEV;
>> ? }
>>
>> ? base = ioremap(res->start, resource_size(res));
>> ? if (base) {
>> ? ? ? ? ? ? ? ....
>> ? ? ? ? ? ? ? return -ENOMEM;
>> ? }
>>
>> ? res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
>> ? if (unlikely(!res)) {
>> ? ? ? ? ? ? ? ....
>> ? ? ? ? ? ? ? return -ENODEV;
>> ? }
>> ? irq = res->start;
>> ? ....
>> ? ....
>> }
>>
>> -V Charulatha
On Tue, Nov 30, 2010 at 04:56:47PM -0800, Greg KH wrote:
> On Tue, Nov 30, 2010 at 01:58:59PM -0600, David Sin wrote:
> > From: Lajos Molnar <[email protected]>
> >
> > This patch links the TILER driver into the Linux kernel build
> > and config system.
> >
> > Signed-off-by: Lajos Molnar <[email protected]>
> > Signed-off-by: David Sin <[email protected]>
> > ---
> > drivers/misc/Kconfig | 5 +++++
> > drivers/misc/Makefile | 1 +
> > 2 files changed, 6 insertions(+), 0 deletions(-)
> >
> > diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
> > index ac6d6ac..fff7927 100644
> > --- a/drivers/misc/Kconfig
> > +++ b/drivers/misc/Kconfig
> > @@ -378,4 +378,9 @@ source "drivers/misc/eeprom/Kconfig"
> > source "drivers/misc/cb710/Kconfig"
> > source "drivers/misc/iwmc3200top/Kconfig"
> >
> > +#
> > +# TI TILER driver support
> > +#
>
> Comments not needed.
>
> thanks,
>
> greg k-h
thanks, Greg, for the comments. I will make all of these changes
in the next revision.
--
David Sin
On Wed, Dec 01, 2010 at 12:17:22PM +0530, Varadarajan, Charulatha wrote:
> On Wed, Dec 1, 2010 at 01:28, David Sin <[email protected]> wrote:
>
> The dmm driver is making use of omap_hwmod fw. But I could not see a patch
> to add dmm hwmod data to omap4 hwmod base in this series. Is this patch series
> tested?
yes -- this code has been tested against the omap_hwmod fw. I will send
out a patch in the next rev. Thanks for your comments.
--
David Sin