d7edf47947
Yeeloong netbook has a sm712 video card, need this driver, but it is not ready to upstream yet, so, go to drivers/staing at first. This source code is originally from Silicon Motion Technology Corp, and maintained at http://dev.lemote.com/code/linux_loongson for YeeLoong netbook. I have done a lot of cleanups for it and merged it into my git repository at http://dev.lemote.com/code/rt4ls. Thanks to Simon for testing it on a little-endian x86 platform. Thanks to Olivier Croset <olivier.croset@actis-computer.com> for reporting the problem about __BIG_ENDIAN compiling problem and send a relative patch. The suspend/resume and blank support are contributed by Jason from Silicon Motion Technology. Tested-by: Simon Braunschmidt <sbraun@emlix.com> Signed-off-by: Wu Zhangjin <wuzhangjin@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
980 lines
25 KiB
C
980 lines
25 KiB
C
/*
|
|
* 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;
|
|
}
|