aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/sm7xx/smtc2d.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/sm7xx/smtc2d.c')
-rw-r--r--drivers/staging/sm7xx/smtc2d.c979
1 files changed, 979 insertions, 0 deletions
diff --git a/drivers/staging/sm7xx/smtc2d.c b/drivers/staging/sm7xx/smtc2d.c
new file mode 100644
index 0000000..133b86c
--- /dev/null
+++ b/drivers/staging/sm7xx/smtc2d.c
@@ -0,0 +1,979 @@
+/*
+ * Silicon Motion SM7XX 2D drawing engine functions.
+ *
+ * Copyright (C) 2006 Silicon Motion Technology Corp.
+ * Author: Boyod boyod.yang@siliconmotion.com.cn
+ *
+ * Copyright (C) 2009 Lemote, Inc.
+ * Author: Wu Zhangjin, wuzj@lemote.com
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ *
+ * Version 0.10.26192.21.01
+ * - Add PowerPC support
+ * - Add 2D support for Lynx -
+ * Verified on 2.6.19.2
+ * Boyod.yang <boyod.yang@siliconmotion.com.cn>
+ */
+
+unsigned char smtc_de_busy;
+
+void SMTC_write2Dreg(unsigned long nOffset, unsigned long nData)
+{
+ writel(nData, smtc_2DBaseAddress + nOffset);
+}
+
+unsigned long SMTC_read2Dreg(unsigned long nOffset)
+{
+ return readl(smtc_2DBaseAddress + nOffset);
+}
+
+void SMTC_write2Ddataport(unsigned long nOffset, unsigned long nData)
+{
+ writel(nData, smtc_2Ddataport + nOffset);
+}
+
+/**********************************************************************
+ *
+ * deInit
+ *
+ * Purpose
+ * Drawing engine initialization.
+ *
+ **********************************************************************/
+
+void deInit(unsigned int nModeWidth, unsigned int nModeHeight,
+ unsigned int bpp)
+{
+ /* Get current power configuration. */
+ unsigned char clock;
+ clock = smtc_seqr(0x21);
+
+ /* initialize global 'mutex lock' variable */
+ smtc_de_busy = 0;
+
+ /* Enable 2D Drawing Engine */
+ smtc_seqw(0x21, clock & 0xF8);
+
+ SMTC_write2Dreg(DE_CLIP_TL,
+ FIELD_VALUE(0, DE_CLIP_TL, TOP, 0) |
+ FIELD_SET(0, DE_CLIP_TL, STATUS, DISABLE) |
+ FIELD_SET(0, DE_CLIP_TL, INHIBIT, OUTSIDE) |
+ FIELD_VALUE(0, DE_CLIP_TL, LEFT, 0));
+
+ if (bpp >= 24) {
+ SMTC_write2Dreg(DE_PITCH,
+ FIELD_VALUE(0, DE_PITCH, DESTINATION,
+ nModeWidth * 3) | FIELD_VALUE(0,
+ DE_PITCH,
+ SOURCE,
+ nModeWidth
+ * 3));
+ } else {
+ SMTC_write2Dreg(DE_PITCH,
+ FIELD_VALUE(0, DE_PITCH, DESTINATION,
+ nModeWidth) | FIELD_VALUE(0,
+ DE_PITCH,
+ SOURCE,
+ nModeWidth));
+ }
+
+ SMTC_write2Dreg(DE_WINDOW_WIDTH,
+ FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION,
+ nModeWidth) | FIELD_VALUE(0,
+ DE_WINDOW_WIDTH,
+ SOURCE,
+ nModeWidth));
+
+ switch (bpp) {
+ case 8:
+ SMTC_write2Dreg(DE_STRETCH_FORMAT,
+ FIELD_SET(0, DE_STRETCH_FORMAT, PATTERN_XY,
+ NORMAL) | FIELD_VALUE(0,
+ DE_STRETCH_FORMAT,
+ PATTERN_Y,
+ 0) |
+ FIELD_VALUE(0, DE_STRETCH_FORMAT, PATTERN_X,
+ 0) | FIELD_SET(0, DE_STRETCH_FORMAT,
+ PIXEL_FORMAT,
+ 8) | FIELD_SET(0,
+ DE_STRETCH_FORMAT,
+ ADDRESSING,
+ XY) |
+ FIELD_VALUE(0, DE_STRETCH_FORMAT,
+ SOURCE_HEIGHT, 3));
+ break;
+ case 24:
+ SMTC_write2Dreg(DE_STRETCH_FORMAT,
+ FIELD_SET(0, DE_STRETCH_FORMAT, PATTERN_XY,
+ NORMAL) | FIELD_VALUE(0,
+ DE_STRETCH_FORMAT,
+ PATTERN_Y,
+ 0) |
+ FIELD_VALUE(0, DE_STRETCH_FORMAT, PATTERN_X,
+ 0) | FIELD_SET(0, DE_STRETCH_FORMAT,
+ PIXEL_FORMAT,
+ 24) | FIELD_SET(0,
+ DE_STRETCH_FORMAT,
+ ADDRESSING,
+ XY) |
+ FIELD_VALUE(0, DE_STRETCH_FORMAT,
+ SOURCE_HEIGHT, 3));
+ break;
+ case 16:
+ default:
+ SMTC_write2Dreg(DE_STRETCH_FORMAT,
+ FIELD_SET(0, DE_STRETCH_FORMAT, PATTERN_XY,
+ NORMAL) | FIELD_VALUE(0,
+ DE_STRETCH_FORMAT,
+ PATTERN_Y,
+ 0) |
+ FIELD_VALUE(0, DE_STRETCH_FORMAT, PATTERN_X,
+ 0) | FIELD_SET(0, DE_STRETCH_FORMAT,
+ PIXEL_FORMAT,
+ 16) | FIELD_SET(0,
+ DE_STRETCH_FORMAT,
+ ADDRESSING,
+ XY) |
+ FIELD_VALUE(0, DE_STRETCH_FORMAT,
+ SOURCE_HEIGHT, 3));
+ break;
+ }
+
+ SMTC_write2Dreg(DE_MASKS,
+ FIELD_VALUE(0, DE_MASKS, BYTE_MASK, 0xFFFF) |
+ FIELD_VALUE(0, DE_MASKS, BIT_MASK, 0xFFFF));
+ SMTC_write2Dreg(DE_COLOR_COMPARE_MASK,
+ FIELD_VALUE(0, DE_COLOR_COMPARE_MASK, MASKS, \
+ 0xFFFFFF));
+ SMTC_write2Dreg(DE_COLOR_COMPARE,
+ FIELD_VALUE(0, DE_COLOR_COMPARE, COLOR, 0xFFFFFF));
+}
+
+void deVerticalLine(unsigned long dst_base,
+ unsigned long dst_pitch,
+ unsigned long nX,
+ unsigned long nY,
+ unsigned long dst_height, unsigned long nColor)
+{
+ deWaitForNotBusy();
+
+ SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE,
+ FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE, ADDRESS,
+ dst_base));
+
+ SMTC_write2Dreg(DE_PITCH,
+ FIELD_VALUE(0, DE_PITCH, DESTINATION, dst_pitch) |
+ FIELD_VALUE(0, DE_PITCH, SOURCE, dst_pitch));
+
+ SMTC_write2Dreg(DE_WINDOW_WIDTH,
+ FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION,
+ dst_pitch) | FIELD_VALUE(0, DE_WINDOW_WIDTH,
+ SOURCE,
+ dst_pitch));
+
+ SMTC_write2Dreg(DE_FOREGROUND,
+ FIELD_VALUE(0, DE_FOREGROUND, COLOR, nColor));
+
+ SMTC_write2Dreg(DE_DESTINATION,
+ FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) |
+ FIELD_VALUE(0, DE_DESTINATION, X, nX) |
+ FIELD_VALUE(0, DE_DESTINATION, Y, nY));
+
+ SMTC_write2Dreg(DE_DIMENSION,
+ FIELD_VALUE(0, DE_DIMENSION, X, 1) |
+ FIELD_VALUE(0, DE_DIMENSION, Y_ET, dst_height));
+
+ SMTC_write2Dreg(DE_CONTROL,
+ FIELD_SET(0, DE_CONTROL, STATUS, START) |
+ FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT) |
+ FIELD_SET(0, DE_CONTROL, MAJOR, Y) |
+ FIELD_SET(0, DE_CONTROL, STEP_X, NEGATIVE) |
+ FIELD_SET(0, DE_CONTROL, STEP_Y, POSITIVE) |
+ FIELD_SET(0, DE_CONTROL, LAST_PIXEL, OFF) |
+ FIELD_SET(0, DE_CONTROL, COMMAND, SHORT_STROKE) |
+ FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) |
+ FIELD_VALUE(0, DE_CONTROL, ROP, 0x0C));
+
+ smtc_de_busy = 1;
+}
+
+void deHorizontalLine(unsigned long dst_base,
+ unsigned long dst_pitch,
+ unsigned long nX,
+ unsigned long nY,
+ unsigned long dst_width, unsigned long nColor)
+{
+ deWaitForNotBusy();
+
+ SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE,
+ FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE, ADDRESS,
+ dst_base));
+
+ SMTC_write2Dreg(DE_PITCH,
+ FIELD_VALUE(0, DE_PITCH, DESTINATION, dst_pitch) |
+ FIELD_VALUE(0, DE_PITCH, SOURCE, dst_pitch));
+
+ SMTC_write2Dreg(DE_WINDOW_WIDTH,
+ FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION,
+ dst_pitch) | FIELD_VALUE(0, DE_WINDOW_WIDTH,
+ SOURCE,
+ dst_pitch));
+ SMTC_write2Dreg(DE_FOREGROUND,
+ FIELD_VALUE(0, DE_FOREGROUND, COLOR, nColor));
+ SMTC_write2Dreg(DE_DESTINATION,
+ FIELD_SET(0, DE_DESTINATION, WRAP,
+ DISABLE) | FIELD_VALUE(0, DE_DESTINATION, X,
+ nX) | FIELD_VALUE(0,
+ DE_DESTINATION,
+ Y,
+ nY));
+ SMTC_write2Dreg(DE_DIMENSION,
+ FIELD_VALUE(0, DE_DIMENSION, X,
+ dst_width) | FIELD_VALUE(0, DE_DIMENSION,
+ Y_ET, 1));
+ SMTC_write2Dreg(DE_CONTROL,
+ FIELD_SET(0, DE_CONTROL, STATUS, START) | FIELD_SET(0,
+ DE_CONTROL,
+ DIRECTION,
+ RIGHT_TO_LEFT)
+ | FIELD_SET(0, DE_CONTROL, MAJOR, X) | FIELD_SET(0,
+ DE_CONTROL,
+ STEP_X,
+ POSITIVE)
+ | FIELD_SET(0, DE_CONTROL, STEP_Y,
+ NEGATIVE) | FIELD_SET(0, DE_CONTROL,
+ LAST_PIXEL,
+ OFF) | FIELD_SET(0,
+ DE_CONTROL,
+ COMMAND,
+ SHORT_STROKE)
+ | FIELD_SET(0, DE_CONTROL, ROP_SELECT,
+ ROP2) | FIELD_VALUE(0, DE_CONTROL, ROP,
+ 0x0C));
+
+ smtc_de_busy = 1;
+}
+
+void deLine(unsigned long dst_base,
+ unsigned long dst_pitch,
+ unsigned long nX1,
+ unsigned long nY1,
+ unsigned long nX2, unsigned long nY2, unsigned long nColor)
+{
+ unsigned long nCommand =
+ FIELD_SET(0, DE_CONTROL, STATUS, START) |
+ FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT) |
+ FIELD_SET(0, DE_CONTROL, MAJOR, X) |
+ FIELD_SET(0, DE_CONTROL, STEP_X, POSITIVE) |
+ FIELD_SET(0, DE_CONTROL, STEP_Y, POSITIVE) |
+ FIELD_SET(0, DE_CONTROL, LAST_PIXEL, OFF) |
+ FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) |
+ FIELD_VALUE(0, DE_CONTROL, ROP, 0x0C);
+ unsigned long DeltaX;
+ unsigned long DeltaY;
+
+ /* Calculate delta X */
+ if (nX1 <= nX2)
+ DeltaX = nX2 - nX1;
+ else {
+ DeltaX = nX1 - nX2;
+ nCommand = FIELD_SET(nCommand, DE_CONTROL, STEP_X, NEGATIVE);
+ }
+
+ /* Calculate delta Y */
+ if (nY1 <= nY2)
+ DeltaY = nY2 - nY1;
+ else {
+ DeltaY = nY1 - nY2;
+ nCommand = FIELD_SET(nCommand, DE_CONTROL, STEP_Y, NEGATIVE);
+ }
+
+ /* Determine the major axis */
+ if (DeltaX < DeltaY)
+ nCommand = FIELD_SET(nCommand, DE_CONTROL, MAJOR, Y);
+
+ /* Vertical line? */
+ if (nX1 == nX2)
+ deVerticalLine(dst_base, dst_pitch, nX1, nY1, DeltaY, nColor);
+
+ /* Horizontal line? */
+ else if (nY1 == nY2)
+ deHorizontalLine(dst_base, dst_pitch, nX1, nY1, \
+ DeltaX, nColor);
+
+ /* Diagonal line? */
+ else if (DeltaX == DeltaY) {
+ deWaitForNotBusy();
+
+ SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE,
+ FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE,
+ ADDRESS, dst_base));
+
+ SMTC_write2Dreg(DE_PITCH,
+ FIELD_VALUE(0, DE_PITCH, DESTINATION,
+ dst_pitch) | FIELD_VALUE(0,
+ DE_PITCH,
+ SOURCE,
+ dst_pitch));
+
+ SMTC_write2Dreg(DE_WINDOW_WIDTH,
+ FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION,
+ dst_pitch) | FIELD_VALUE(0,
+ DE_WINDOW_WIDTH,
+ SOURCE,
+ dst_pitch));
+
+ SMTC_write2Dreg(DE_FOREGROUND,
+ FIELD_VALUE(0, DE_FOREGROUND, COLOR, nColor));
+
+ SMTC_write2Dreg(DE_DESTINATION,
+ FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) |
+ FIELD_VALUE(0, DE_DESTINATION, X, 1) |
+ FIELD_VALUE(0, DE_DESTINATION, Y, nY1));
+
+ SMTC_write2Dreg(DE_DIMENSION,
+ FIELD_VALUE(0, DE_DIMENSION, X, 1) |
+ FIELD_VALUE(0, DE_DIMENSION, Y_ET, DeltaX));
+
+ SMTC_write2Dreg(DE_CONTROL,
+ FIELD_SET(nCommand, DE_CONTROL, COMMAND,
+ SHORT_STROKE));
+ }
+
+ /* Generic line */
+ else {
+ unsigned int k1, k2, et, w;
+ if (DeltaX < DeltaY) {
+ k1 = 2 * DeltaX;
+ et = k1 - DeltaY;
+ k2 = et - DeltaY;
+ w = DeltaY + 1;
+ } else {
+ k1 = 2 * DeltaY;
+ et = k1 - DeltaX;
+ k2 = et - DeltaX;
+ w = DeltaX + 1;
+ }
+
+ deWaitForNotBusy();
+
+ SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE,
+ FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE,
+ ADDRESS, dst_base));
+
+ SMTC_write2Dreg(DE_PITCH,
+ FIELD_VALUE(0, DE_PITCH, DESTINATION,
+ dst_pitch) | FIELD_VALUE(0,
+ DE_PITCH,
+ SOURCE,
+ dst_pitch));
+
+ SMTC_write2Dreg(DE_WINDOW_WIDTH,
+ FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION,
+ dst_pitch) | FIELD_VALUE(0,
+ DE_WINDOW_WIDTH,
+ SOURCE,
+ dst_pitch));
+
+ SMTC_write2Dreg(DE_FOREGROUND,
+ FIELD_VALUE(0, DE_FOREGROUND, COLOR, nColor));
+
+ SMTC_write2Dreg(DE_SOURCE,
+ FIELD_SET(0, DE_SOURCE, WRAP, DISABLE) |
+ FIELD_VALUE(0, DE_SOURCE, X_K1, k1) |
+ FIELD_VALUE(0, DE_SOURCE, Y_K2, k2));
+
+ SMTC_write2Dreg(DE_DESTINATION,
+ FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) |
+ FIELD_VALUE(0, DE_DESTINATION, X, nX1) |
+ FIELD_VALUE(0, DE_DESTINATION, Y, nY1));
+
+ SMTC_write2Dreg(DE_DIMENSION,
+ FIELD_VALUE(0, DE_DIMENSION, X, w) |
+ FIELD_VALUE(0, DE_DIMENSION, Y_ET, et));
+
+ SMTC_write2Dreg(DE_CONTROL,
+ FIELD_SET(nCommand, DE_CONTROL, COMMAND,
+ LINE_DRAW));
+ }
+
+ smtc_de_busy = 1;
+}
+
+void deFillRect(unsigned long dst_base,
+ unsigned long dst_pitch,
+ unsigned long dst_X,
+ unsigned long dst_Y,
+ unsigned long dst_width,
+ unsigned long dst_height, unsigned long nColor)
+{
+ deWaitForNotBusy();
+
+ SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE,
+ FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE, ADDRESS,
+ dst_base));
+
+ if (dst_pitch) {
+ SMTC_write2Dreg(DE_PITCH,
+ FIELD_VALUE(0, DE_PITCH, DESTINATION,
+ dst_pitch) | FIELD_VALUE(0,
+ DE_PITCH,
+ SOURCE,
+ dst_pitch));
+
+ SMTC_write2Dreg(DE_WINDOW_WIDTH,
+ FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION,
+ dst_pitch) | FIELD_VALUE(0,
+ DE_WINDOW_WIDTH,
+ SOURCE,
+ dst_pitch));
+ }
+
+ SMTC_write2Dreg(DE_FOREGROUND,
+ FIELD_VALUE(0, DE_FOREGROUND, COLOR, nColor));
+
+ SMTC_write2Dreg(DE_DESTINATION,
+ FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) |
+ FIELD_VALUE(0, DE_DESTINATION, X, dst_X) |
+ FIELD_VALUE(0, DE_DESTINATION, Y, dst_Y));
+
+ SMTC_write2Dreg(DE_DIMENSION,
+ FIELD_VALUE(0, DE_DIMENSION, X, dst_width) |
+ FIELD_VALUE(0, DE_DIMENSION, Y_ET, dst_height));
+
+ SMTC_write2Dreg(DE_CONTROL,
+ FIELD_SET(0, DE_CONTROL, STATUS, START) |
+ FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT) |
+ FIELD_SET(0, DE_CONTROL, LAST_PIXEL, OFF) |
+ FIELD_SET(0, DE_CONTROL, COMMAND, RECTANGLE_FILL) |
+ FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) |
+ FIELD_VALUE(0, DE_CONTROL, ROP, 0x0C));
+
+ smtc_de_busy = 1;
+}
+
+/**********************************************************************
+ *
+ * deRotatePattern
+ *
+ * Purpose
+ * Rotate the given pattern if necessary
+ *
+ * Parameters
+ * [in]
+ * pPattern - Pointer to DE_SURFACE structure containing
+ * pattern attributes
+ * patternX - X position (0-7) of pattern origin
+ * patternY - Y position (0-7) of pattern origin
+ *
+ * [out]
+ * pattern_dstaddr - Pointer to pre-allocated buffer containing
+ * rotated pattern
+ *
+ **********************************************************************/
+void deRotatePattern(unsigned char *pattern_dstaddr,
+ unsigned long pattern_src_addr,
+ unsigned long pattern_BPP,
+ unsigned long pattern_stride, int patternX, int patternY)
+{
+ unsigned int i;
+ unsigned long pattern[PATTERN_WIDTH * PATTERN_HEIGHT];
+ unsigned int x, y;
+ unsigned char *pjPatByte;
+
+ if (pattern_dstaddr != NULL) {
+ deWaitForNotBusy();
+
+ if (patternX || patternY) {
+ /* Rotate pattern */
+ pjPatByte = (unsigned char *)pattern;
+
+ switch (pattern_BPP) {
+ case 8:
+ {
+ for (y = 0; y < 8; y++) {
+ unsigned char *pjBuffer =
+ pattern_dstaddr +
+ ((patternY + y) & 7) * 8;
+ for (x = 0; x < 8; x++) {
+ pjBuffer[(patternX +
+ x) & 7] =
+ pjPatByte[x];
+ }
+ pjPatByte += pattern_stride;
+ }
+ break;
+ }
+
+ case 16:
+ {
+ for (y = 0; y < 8; y++) {
+ unsigned short *pjBuffer =
+ (unsigned short *)
+ pattern_dstaddr +
+ ((patternY + y) & 7) * 8;
+ for (x = 0; x < 8; x++) {
+ pjBuffer[(patternX +
+ x) & 7] =
+ ((unsigned short *)
+ pjPatByte)[x];
+ }
+ pjPatByte += pattern_stride;
+ }
+ break;
+ }
+
+ case 32:
+ {
+ for (y = 0; y < 8; y++) {
+ unsigned long *pjBuffer =
+ (unsigned long *)
+ pattern_dstaddr +
+ ((patternY + y) & 7) * 8;
+ for (x = 0; x < 8; x++) {
+ pjBuffer[(patternX +
+ x) & 7] =
+ ((unsigned long *)
+ pjPatByte)[x];
+ }
+ pjPatByte += pattern_stride;
+ }
+ break;
+ }
+ }
+ } else {
+ /*Don't rotate,just copy pattern into pattern_dstaddr*/
+ for (i = 0; i < (pattern_BPP * 2); i++) {
+ ((unsigned long *)pattern_dstaddr)[i] =
+ pattern[i];
+ }
+ }
+
+ }
+}
+
+/**********************************************************************
+ *
+ * deCopy
+ *
+ * Purpose
+ * Copy a rectangular area of the source surface to a destination surface
+ *
+ * Remarks
+ * Source bitmap must have the same color depth (BPP) as the destination
+ * bitmap.
+ *
+**********************************************************************/
+void deCopy(unsigned long dst_base,
+ unsigned long dst_pitch,
+ unsigned long dst_BPP,
+ unsigned long dst_X,
+ unsigned long dst_Y,
+ unsigned long dst_width,
+ unsigned long dst_height,
+ unsigned long src_base,
+ unsigned long src_pitch,
+ unsigned long src_X,
+ unsigned long src_Y, pTransparent pTransp, unsigned char nROP2)
+{
+ unsigned long nDirection = 0;
+ unsigned long nTransparent = 0;
+ /* Direction of ROP2 operation:
+ * 1 = Left to Right,
+ * (-1) = Right to Left
+ */
+ unsigned long opSign = 1;
+ /* xWidth is in pixels */
+ unsigned long xWidth = 192 / (dst_BPP / 8);
+ unsigned long de_ctrl = 0;
+
+ deWaitForNotBusy();
+
+ SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE,
+ FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE, ADDRESS,
+ dst_base));
+
+ SMTC_write2Dreg(DE_WINDOW_SOURCE_BASE,
+ FIELD_VALUE(0, DE_WINDOW_SOURCE_BASE, ADDRESS,
+ src_base));
+
+ if (dst_pitch && src_pitch) {
+ SMTC_write2Dreg(DE_PITCH,
+ FIELD_VALUE(0, DE_PITCH, DESTINATION,
+ dst_pitch) | FIELD_VALUE(0,
+ DE_PITCH,
+ SOURCE,
+ src_pitch));
+
+ SMTC_write2Dreg(DE_WINDOW_WIDTH,
+ FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION,
+ dst_pitch) | FIELD_VALUE(0,
+ DE_WINDOW_WIDTH,
+ SOURCE,
+ src_pitch));
+ }
+
+ /* Set transparent bits if necessary */
+ if (pTransp != NULL) {
+ nTransparent =
+ pTransp->match | pTransp->select | pTransp->control;
+
+ /* Set color compare register */
+ SMTC_write2Dreg(DE_COLOR_COMPARE,
+ FIELD_VALUE(0, DE_COLOR_COMPARE, COLOR,
+ pTransp->color));
+ }
+
+ /* Determine direction of operation */
+ if (src_Y < dst_Y) {
+ /* +----------+
+ |S |
+ | +----------+
+ | | | |
+ | | | |
+ +---|------+ |
+ | D |
+ +----------+ */
+
+ nDirection = BOTTOM_TO_TOP;
+ } else if (src_Y > dst_Y) {
+ /* +----------+
+ |D |
+ | +----------+
+ | | | |
+ | | | |
+ +---|------+ |
+ | S |
+ +----------+ */
+
+ nDirection = TOP_TO_BOTTOM;
+ } else {
+ /* src_Y == dst_Y */
+
+ if (src_X <= dst_X) {
+ /* +------+---+------+
+ |S | | D|
+ | | | |
+ | | | |
+ | | | |
+ +------+---+------+ */
+
+ nDirection = RIGHT_TO_LEFT;
+ } else {
+ /* src_X > dst_X */
+
+ /* +------+---+------+
+ |D | | S|
+ | | | |
+ | | | |
+ | | | |
+ +------+---+------+ */
+
+ nDirection = LEFT_TO_RIGHT;
+ }
+ }
+
+ if ((nDirection == BOTTOM_TO_TOP) || (nDirection == RIGHT_TO_LEFT)) {
+ src_X += dst_width - 1;
+ src_Y += dst_height - 1;
+ dst_X += dst_width - 1;
+ dst_Y += dst_height - 1;
+ opSign = (-1);
+ }
+
+ if (dst_BPP >= 24) {
+ src_X *= 3;
+ src_Y *= 3;
+ dst_X *= 3;
+ dst_Y *= 3;
+ dst_width *= 3;
+ if ((nDirection == BOTTOM_TO_TOP)
+ || (nDirection == RIGHT_TO_LEFT)) {
+ src_X += 2;
+ dst_X += 2;
+ }
+ }
+
+ /* Workaround for 192 byte hw bug */
+ if ((nROP2 != 0x0C) && ((dst_width * (dst_BPP / 8)) >= 192)) {
+ /*
+ * Perform the ROP2 operation in chunks of (xWidth *
+ * dst_height)
+ */
+ while (1) {
+ deWaitForNotBusy();
+
+ SMTC_write2Dreg(DE_SOURCE,
+ FIELD_SET(0, DE_SOURCE, WRAP, DISABLE) |
+ FIELD_VALUE(0, DE_SOURCE, X_K1, src_X) |
+ FIELD_VALUE(0, DE_SOURCE, Y_K2, src_Y));
+
+ SMTC_write2Dreg(DE_DESTINATION,
+ FIELD_SET(0, DE_DESTINATION, WRAP,
+ DISABLE) | FIELD_VALUE(0,
+ DE_DESTINATION,
+ X,
+ dst_X)
+ | FIELD_VALUE(0, DE_DESTINATION, Y,
+ dst_Y));
+
+ SMTC_write2Dreg(DE_DIMENSION,
+ FIELD_VALUE(0, DE_DIMENSION, X,
+ xWidth) | FIELD_VALUE(0,
+ DE_DIMENSION,
+ Y_ET,
+ dst_height));
+
+ de_ctrl =
+ FIELD_VALUE(0, DE_CONTROL, ROP,
+ nROP2) | nTransparent | FIELD_SET(0,
+ DE_CONTROL,
+ ROP_SELECT,
+ ROP2)
+ | FIELD_SET(0, DE_CONTROL, COMMAND,
+ BITBLT) | ((nDirection ==
+ 1) ? FIELD_SET(0,
+ DE_CONTROL,
+ DIRECTION,
+ RIGHT_TO_LEFT)
+ : FIELD_SET(0, DE_CONTROL,
+ DIRECTION,
+ LEFT_TO_RIGHT)) |
+ FIELD_SET(0, DE_CONTROL, STATUS, START);
+
+ SMTC_write2Dreg(DE_CONTROL, de_ctrl);
+
+ src_X += (opSign * xWidth);
+ dst_X += (opSign * xWidth);
+ dst_width -= xWidth;
+
+ if (dst_width <= 0) {
+ /* ROP2 operation is complete */
+ break;
+ }
+
+ if (xWidth > dst_width)
+ xWidth = dst_width;
+ }
+ } else {
+ deWaitForNotBusy();
+ SMTC_write2Dreg(DE_SOURCE,
+ FIELD_SET(0, DE_SOURCE, WRAP, DISABLE) |
+ FIELD_VALUE(0, DE_SOURCE, X_K1, src_X) |
+ FIELD_VALUE(0, DE_SOURCE, Y_K2, src_Y));
+
+ SMTC_write2Dreg(DE_DESTINATION,
+ FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) |
+ FIELD_VALUE(0, DE_DESTINATION, X, dst_X) |
+ FIELD_VALUE(0, DE_DESTINATION, Y, dst_Y));
+
+ SMTC_write2Dreg(DE_DIMENSION,
+ FIELD_VALUE(0, DE_DIMENSION, X, dst_width) |
+ FIELD_VALUE(0, DE_DIMENSION, Y_ET, dst_height));
+
+ de_ctrl = FIELD_VALUE(0, DE_CONTROL, ROP, nROP2) |
+ nTransparent |
+ FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) |
+ FIELD_SET(0, DE_CONTROL, COMMAND, BITBLT) |
+ ((nDirection == 1) ? FIELD_SET(0, DE_CONTROL, DIRECTION,
+ RIGHT_TO_LEFT)
+ : FIELD_SET(0, DE_CONTROL, DIRECTION,
+ LEFT_TO_RIGHT)) | FIELD_SET(0, DE_CONTROL,
+ STATUS, START);
+ SMTC_write2Dreg(DE_CONTROL, de_ctrl);
+ }
+
+ smtc_de_busy = 1;
+}
+
+/*
+ * This function sets the pixel format that will apply to the 2D Engine.
+ */
+void deSetPixelFormat(unsigned long bpp)
+{
+ unsigned long de_format;
+
+ de_format = SMTC_read2Dreg(DE_STRETCH_FORMAT);
+
+ switch (bpp) {
+ case 8:
+ de_format =
+ FIELD_SET(de_format, DE_STRETCH_FORMAT, PIXEL_FORMAT, 8);
+ break;
+ default:
+ case 16:
+ de_format =
+ FIELD_SET(de_format, DE_STRETCH_FORMAT, PIXEL_FORMAT, 16);
+ break;
+ case 32:
+ de_format =
+ FIELD_SET(de_format, DE_STRETCH_FORMAT, PIXEL_FORMAT, 32);
+ break;
+ }
+
+ SMTC_write2Dreg(DE_STRETCH_FORMAT, de_format);
+}
+
+/*
+ * System memory to Video memory monochrome expansion.
+ *
+ * Source is monochrome image in system memory. This function expands the
+ * monochrome data to color image in video memory.
+ */
+
+long deSystemMem2VideoMemMonoBlt(const char *pSrcbuf,
+ long srcDelta,
+ unsigned long startBit,
+ unsigned long dBase,
+ unsigned long dPitch,
+ unsigned long bpp,
+ unsigned long dx, unsigned long dy,
+ unsigned long width, unsigned long height,
+ unsigned long fColor,
+ unsigned long bColor,
+ unsigned long rop2) {
+ unsigned long bytePerPixel;
+ unsigned long ulBytesPerScan;
+ unsigned long ul4BytesPerScan;
+ unsigned long ulBytesRemain;
+ unsigned long de_ctrl = 0;
+ unsigned char ajRemain[4];
+ long i, j;
+
+ bytePerPixel = bpp / 8;
+
+ /* Just make sure the start bit is within legal range */
+ startBit &= 7;
+
+ ulBytesPerScan = (width + startBit + 7) / 8;
+ ul4BytesPerScan = ulBytesPerScan & ~3;
+ ulBytesRemain = ulBytesPerScan & 3;
+
+ if (smtc_de_busy)
+ deWaitForNotBusy();
+
+ /*
+ * 2D Source Base. Use 0 for HOST Blt.
+ */
+
+ SMTC_write2Dreg(DE_WINDOW_SOURCE_BASE, 0);
+
+ /*
+ * 2D Destination Base.
+ *
+ * It is an address offset (128 bit aligned) from the beginning of
+ * frame buffer.
+ */
+
+ SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE, dBase);
+
+ if (dPitch) {
+
+ /*
+ * Program pitch (distance between the 1st points of two
+ * adjacent lines).
+ *
+ * Note that input pitch is BYTE value, but the 2D Pitch
+ * register uses pixel values. Need Byte to pixel convertion.
+ */
+
+ SMTC_write2Dreg(DE_PITCH,
+ FIELD_VALUE(0, DE_PITCH, DESTINATION,
+ dPitch /
+ bytePerPixel) | FIELD_VALUE(0,
+ DE_PITCH,
+ SOURCE,
+ dPitch /
+ bytePerPixel));
+
+ /* Screen Window width in Pixels.
+ *
+ * 2D engine uses this value to calculate the linear address in
+ * frame buffer for a given point.
+ */
+
+ SMTC_write2Dreg(DE_WINDOW_WIDTH,
+ FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION,
+ (dPitch /
+ bytePerPixel)) | FIELD_VALUE(0,
+ DE_WINDOW_WIDTH,
+ SOURCE,
+ (dPitch
+ /
+ bytePerPixel)));
+ }
+ /* Note: For 2D Source in Host Write, only X_K1 field is needed, and
+ * Y_K2 field is not used. For mono bitmap, use startBit for X_K1.
+ */
+
+ SMTC_write2Dreg(DE_SOURCE,
+ FIELD_SET(0, DE_SOURCE, WRAP, DISABLE) |
+ FIELD_VALUE(0, DE_SOURCE, X_K1, startBit) |
+ FIELD_VALUE(0, DE_SOURCE, Y_K2, 0));
+
+ SMTC_write2Dreg(DE_DESTINATION,
+ FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) |
+ FIELD_VALUE(0, DE_DESTINATION, X, dx) |
+ FIELD_VALUE(0, DE_DESTINATION, Y, dy));
+
+ SMTC_write2Dreg(DE_DIMENSION,
+ FIELD_VALUE(0, DE_DIMENSION, X, width) |
+ FIELD_VALUE(0, DE_DIMENSION, Y_ET, height));
+
+ SMTC_write2Dreg(DE_FOREGROUND, fColor);
+ SMTC_write2Dreg(DE_BACKGROUND, bColor);
+
+ if (bpp)
+ deSetPixelFormat(bpp);
+ /* Set the pixel format of the destination */
+
+ de_ctrl = FIELD_VALUE(0, DE_CONTROL, ROP, rop2) |
+ FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) |
+ FIELD_SET(0, DE_CONTROL, COMMAND, HOST_WRITE) |
+ FIELD_SET(0, DE_CONTROL, HOST, MONO) |
+ FIELD_SET(0, DE_CONTROL, STATUS, START);
+
+ SMTC_write2Dreg(DE_CONTROL, de_ctrl | deGetTransparency());
+
+ /* Write MONO data (line by line) to 2D Engine data port */
+ for (i = 0; i < height; i++) {
+ /* For each line, send the data in chunks of 4 bytes */
+ for (j = 0; j < (ul4BytesPerScan / 4); j++)
+ SMTC_write2Ddataport(0,
+ *(unsigned long *)(pSrcbuf +
+ (j * 4)));
+
+ if (ulBytesRemain) {
+ memcpy(ajRemain, pSrcbuf + ul4BytesPerScan,
+ ulBytesRemain);
+ SMTC_write2Ddataport(0, *(unsigned long *)ajRemain);
+ }
+
+ pSrcbuf += srcDelta;
+ }
+ smtc_de_busy = 1;
+
+ return 0;
+}
+
+/*
+ * This function gets the transparency status from DE_CONTROL register.
+ * It returns a double word with the transparent fields properly set,
+ * while other fields are 0.
+ */
+unsigned long deGetTransparency(void)
+{
+ unsigned long de_ctrl;
+
+ de_ctrl = SMTC_read2Dreg(DE_CONTROL);
+
+ de_ctrl &=
+ FIELD_MASK(DE_CONTROL_TRANSPARENCY_MATCH) |
+ FIELD_MASK(DE_CONTROL_TRANSPARENCY_SELECT) |
+ FIELD_MASK(DE_CONTROL_TRANSPARENCY);
+
+ return de_ctrl;
+}