diff mbox

[RFC,6/8] TILER-DMM: Geometry and view manipulation functions.

Message ID 1279927348-21750-7-git-send-email-davidsin@ti.com (mailing list archive)
State New, archived
Headers show

Commit Message

David Sin July 23, 2010, 11:22 p.m. UTC
None
diff mbox

Patch

diff --git a/drivers/media/video/tiler/_tiler.h b/drivers/media/video/tiler/_tiler.h
new file mode 100644
index 0000000..38fff3b
--- /dev/null
+++ b/drivers/media/video/tiler/_tiler.h
@@ -0,0 +1,51 @@ 
+/*
+ * _tiler.h
+ *
+ * TI TILER driver internal shared definitions.
+ *
+ * Author: Lajos Molnar <molnar@ti.com>
+ *
+ * Copyright (C) 2009-2010 Texas Instruments, Inc.
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef _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/media/video/tiler/tiler-geom.c b/drivers/media/video/tiler/tiler-geom.c
new file mode 100644
index 0000000..619413f
--- /dev/null
+++ b/drivers/media/video/tiler/tiler-geom.c
@@ -0,0 +1,360 @@ 
+/*
+ * tiler-geom.c
+ *
+ * TILER geometry functions for TI TILER hardware block.
+ *
+ * Author: Lajos Molnar <molnar@ti.com>
+ *
+ * Copyright (C) 2009-2010 Texas Instruments, Inc.
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <linux/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) {
+		orient ^= MASK_X_INVERT;
+		view->tsptr += (view->width - 1) * view->h_inc;
+	}
+	if (flip_y) {
+		orient ^= MASK_Y_INVERT;
+		view->tsptr += (view->height - 1) * view->v_inc;
+	}
+
+	/* 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);
+	}
+}