| #include<linux/module.h> |
| #include<linux/kernel.h> |
| #include<linux/errno.h> |
| #include<linux/string.h> |
| #include<linux/mm.h> |
| #include<linux/slab.h> |
| #include<linux/delay.h> |
| #include<linux/fb.h> |
| #include<linux/ioport.h> |
| #include<linux/init.h> |
| #include<linux/pci.h> |
| #include<linux/vmalloc.h> |
| #include<linux/pagemap.h> |
| #include <linux/console.h> |
| #include<linux/platform_device.h> |
| #include<linux/screen_info.h> |
| |
| #include "sm750.h" |
| #include "sm750_accel.h" |
| #include "sm750_help.h" |
| static inline void write_dpr(struct lynx_accel *accel, int offset, u32 regValue) |
| { |
| writel(regValue, accel->dprBase + offset); |
| } |
| |
| static inline u32 read_dpr(struct lynx_accel *accel, int offset) |
| { |
| return readl(accel->dprBase + offset); |
| } |
| |
| static inline void write_dpPort(struct lynx_accel *accel, u32 data) |
| { |
| writel(data, accel->dpPortBase); |
| } |
| |
| void hw_de_init(struct lynx_accel *accel) |
| { |
| /* setup 2d engine registers */ |
| u32 reg, clr; |
| |
| write_dpr(accel, DE_MASKS, 0xFFFFFFFF); |
| |
| /* dpr1c */ |
| reg = 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, ADDRESSING, XY)| |
| FIELD_VALUE(0, DE_STRETCH_FORMAT, SOURCE_HEIGHT, 3); |
| |
| clr = FIELD_CLEAR(DE_STRETCH_FORMAT, PATTERN_XY)& |
| FIELD_CLEAR(DE_STRETCH_FORMAT, PATTERN_Y)& |
| FIELD_CLEAR(DE_STRETCH_FORMAT, PATTERN_X)& |
| FIELD_CLEAR(DE_STRETCH_FORMAT, ADDRESSING)& |
| FIELD_CLEAR(DE_STRETCH_FORMAT, SOURCE_HEIGHT); |
| |
| /* DE_STRETCH bpp format need be initilized in setMode routine */ |
| write_dpr(accel, DE_STRETCH_FORMAT, (read_dpr(accel, DE_STRETCH_FORMAT) & clr) | reg); |
| |
| /* disable clipping and transparent */ |
| write_dpr(accel, DE_CLIP_TL, 0); /* dpr2c */ |
| write_dpr(accel, DE_CLIP_BR, 0); /* dpr30 */ |
| |
| write_dpr(accel, DE_COLOR_COMPARE_MASK, 0); /* dpr24 */ |
| write_dpr(accel, DE_COLOR_COMPARE, 0); |
| |
| reg = FIELD_SET(0, DE_CONTROL, TRANSPARENCY, DISABLE)| |
| FIELD_SET(0, DE_CONTROL, TRANSPARENCY_MATCH, OPAQUE)| |
| FIELD_SET(0, DE_CONTROL, TRANSPARENCY_SELECT, SOURCE); |
| |
| clr = FIELD_CLEAR(DE_CONTROL, TRANSPARENCY)& |
| FIELD_CLEAR(DE_CONTROL, TRANSPARENCY_MATCH)& |
| FIELD_CLEAR(DE_CONTROL, TRANSPARENCY_SELECT); |
| |
| /* dpr0c */ |
| write_dpr(accel, DE_CONTROL, (read_dpr(accel, DE_CONTROL)&clr)|reg); |
| } |
| |
| /* set2dformat only be called from setmode functions |
| * but if you need dual framebuffer driver,need call set2dformat |
| * every time you use 2d function */ |
| |
| void hw_set2dformat(struct lynx_accel *accel, int fmt) |
| { |
| u32 reg; |
| |
| /* fmt=0,1,2 for 8,16,32,bpp on sm718/750/502 */ |
| reg = read_dpr(accel, DE_STRETCH_FORMAT); |
| reg = FIELD_VALUE(reg, DE_STRETCH_FORMAT, PIXEL_FORMAT, fmt); |
| write_dpr(accel, DE_STRETCH_FORMAT, reg); |
| } |
| |
| int hw_fillrect(struct lynx_accel *accel, |
| u32 base, u32 pitch, u32 Bpp, |
| u32 x, u32 y, u32 width, u32 height, |
| u32 color, u32 rop) |
| { |
| u32 deCtrl; |
| |
| if(accel->de_wait() != 0) |
| { |
| /* int time wait and always busy,seems hardware |
| * got something error */ |
| pr_debug("%s:De engine always bussy\n", __func__); |
| return -1; |
| } |
| |
| write_dpr(accel, DE_WINDOW_DESTINATION_BASE, base); /* dpr40 */ |
| write_dpr(accel, DE_PITCH, |
| FIELD_VALUE(0, DE_PITCH, DESTINATION, pitch/Bpp)| |
| FIELD_VALUE(0, DE_PITCH, SOURCE, pitch/Bpp)); /* dpr10 */ |
| |
| write_dpr(accel, DE_WINDOW_WIDTH, |
| FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, pitch/Bpp)| |
| FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE, pitch/Bpp)); /* dpr44 */ |
| |
| write_dpr(accel, DE_FOREGROUND, color); /* DPR14 */ |
| |
| write_dpr(accel, DE_DESTINATION, |
| FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE)| |
| FIELD_VALUE(0, DE_DESTINATION, X, x)| |
| FIELD_VALUE(0, DE_DESTINATION, Y, y)); /* dpr4 */ |
| |
| write_dpr(accel, DE_DIMENSION, |
| FIELD_VALUE(0, DE_DIMENSION, X, width)| |
| FIELD_VALUE(0, DE_DIMENSION, Y_ET, height)); /* dpr8 */ |
| |
| deCtrl = |
| FIELD_SET(0, DE_CONTROL, STATUS, START)| |
| FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT)| |
| FIELD_SET(0, DE_CONTROL, LAST_PIXEL, ON)| |
| FIELD_SET(0, DE_CONTROL, COMMAND, RECTANGLE_FILL)| |
| FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2)| |
| FIELD_VALUE(0, DE_CONTROL, ROP, rop); /* dpr0xc */ |
| |
| write_dpr(accel, DE_CONTROL, deCtrl); |
| return 0; |
| } |
| |
| int hw_copyarea( |
| struct lynx_accel *accel, |
| unsigned int sBase, /* Address of source: offset in frame buffer */ |
| unsigned int sPitch, /* Pitch value of source surface in BYTE */ |
| unsigned int sx, |
| unsigned int sy, /* Starting coordinate of source surface */ |
| unsigned int dBase, /* Address of destination: offset in frame buffer */ |
| unsigned int dPitch, /* Pitch value of destination surface in BYTE */ |
| unsigned int Bpp, /* Color depth of destination surface */ |
| unsigned int dx, |
| unsigned int dy, /* Starting coordinate of destination surface */ |
| unsigned int width, |
| unsigned int height, /* width and height of rectangle in pixel value */ |
| unsigned int rop2) /* ROP value */ |
| { |
| unsigned int nDirection, de_ctrl; |
| int opSign; |
| nDirection = LEFT_TO_RIGHT; |
| /* Direction of ROP2 operation: 1 = Left to Right, (-1) = Right to Left */ |
| opSign = 1; |
| de_ctrl = 0; |
| |
| /* If source and destination are the same surface, need to check for overlay cases */ |
| if (sBase == dBase && sPitch == dPitch) |
| { |
| /* Determine direction of operation */ |
| if (sy < dy) |
| { |
| /* +----------+ |
| |S | |
| | +----------+ |
| | | | | |
| | | | | |
| +---|------+ | |
| | D| |
| +----------+ */ |
| |
| nDirection = BOTTOM_TO_TOP; |
| } |
| else if (sy > dy) |
| { |
| /* +----------+ |
| |D | |
| | +----------+ |
| | | | | |
| | | | | |
| +---|------+ | |
| | S| |
| +----------+ */ |
| |
| nDirection = TOP_TO_BOTTOM; |
| } |
| else |
| { |
| /* sy == dy */ |
| |
| if (sx <= dx) |
| { |
| /* +------+---+------+ |
| |S | | D| |
| | | | | |
| | | | | |
| | | | | |
| +------+---+------+ */ |
| |
| nDirection = RIGHT_TO_LEFT; |
| } |
| else |
| { |
| /* sx > dx */ |
| |
| /* +------+---+------+ |
| |D | | S| |
| | | | | |
| | | | | |
| | | | | |
| +------+---+------+ */ |
| |
| nDirection = LEFT_TO_RIGHT; |
| } |
| } |
| } |
| |
| if ((nDirection == BOTTOM_TO_TOP) || (nDirection == RIGHT_TO_LEFT)) |
| { |
| sx += width - 1; |
| sy += height - 1; |
| dx += width - 1; |
| dy += height - 1; |
| opSign = (-1); |
| } |
| |
| /* Note: |
| DE_FOREGROUND are DE_BACKGROUND are don't care. |
| DE_COLOR_COMPARE and DE_COLOR_COMPARE_MAKS are set by set deSetTransparency(). |
| */ |
| |
| /* 2D Source Base. |
| It is an address offset (128 bit aligned) from the beginning of frame buffer. |
| */ |
| write_dpr(accel, DE_WINDOW_SOURCE_BASE, sBase); /* dpr40 */ |
| |
| /* 2D Destination Base. |
| It is an address offset (128 bit aligned) from the beginning of frame buffer. |
| */ |
| write_dpr(accel, DE_WINDOW_DESTINATION_BASE, dBase); /* dpr44 */ |
| |
| #if 0 |
| /* 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 conversion. |
| */ |
| if(Bpp == 3){ |
| sx *= 3; |
| dx *= 3; |
| width *= 3; |
| write_dpr(accel, DE_PITCH, |
| FIELD_VALUE(0, DE_PITCH, DESTINATION, dPitch) | |
| FIELD_VALUE(0, DE_PITCH, SOURCE, sPitch)); /* dpr10 */ |
| } |
| else |
| #endif |
| { |
| write_dpr(accel, DE_PITCH, |
| FIELD_VALUE(0, DE_PITCH, DESTINATION, (dPitch/Bpp)) | |
| FIELD_VALUE(0, DE_PITCH, SOURCE, (sPitch/Bpp))); /* dpr10 */ |
| } |
| |
| /* Screen Window width in Pixels. |
| 2D engine uses this value to calculate the linear address in frame buffer for a given point. |
| */ |
| write_dpr(accel, DE_WINDOW_WIDTH, |
| FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, (dPitch/Bpp)) | |
| FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE, (sPitch/Bpp))); /* dpr3c */ |
| |
| if (accel->de_wait() != 0){ |
| return -1; |
| } |
| |
| { |
| |
| write_dpr(accel, DE_SOURCE, |
| FIELD_SET (0, DE_SOURCE, WRAP, DISABLE) | |
| FIELD_VALUE(0, DE_SOURCE, X_K1, sx) | |
| FIELD_VALUE(0, DE_SOURCE, Y_K2, sy)); /* dpr0 */ |
| write_dpr(accel, DE_DESTINATION, |
| FIELD_SET (0, DE_DESTINATION, WRAP, DISABLE) | |
| FIELD_VALUE(0, DE_DESTINATION, X, dx) | |
| FIELD_VALUE(0, DE_DESTINATION, Y, dy)); /* dpr04 */ |
| write_dpr(accel, DE_DIMENSION, |
| FIELD_VALUE(0, DE_DIMENSION, X, width) | |
| FIELD_VALUE(0, DE_DIMENSION, Y_ET, height)); /* dpr08 */ |
| |
| de_ctrl = |
| FIELD_VALUE(0, DE_CONTROL, ROP, rop2) | |
| FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) | |
| FIELD_SET(0, DE_CONTROL, COMMAND, BITBLT) | |
| ((nDirection == RIGHT_TO_LEFT) ? |
| 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); |
| write_dpr(accel, DE_CONTROL, de_ctrl); /* dpr0c */ |
| } |
| |
| return 0; |
| } |
| |
| static unsigned int deGetTransparency(struct lynx_accel *accel) |
| { |
| unsigned int de_ctrl; |
| |
| de_ctrl = read_dpr(accel, DE_CONTROL); |
| |
| de_ctrl &= |
| FIELD_MASK(DE_CONTROL_TRANSPARENCY_MATCH) | |
| FIELD_MASK(DE_CONTROL_TRANSPARENCY_SELECT)| |
| FIELD_MASK(DE_CONTROL_TRANSPARENCY); |
| |
| return de_ctrl; |
| } |
| |
| int hw_imageblit(struct lynx_accel *accel, |
| const char *pSrcbuf, /* pointer to start of source buffer in system memory */ |
| u32 srcDelta, /* Pitch value (in bytes) of the source buffer, +ive means top down and -ive mean button up */ |
| u32 startBit, /* Mono data can start at any bit in a byte, this value should be 0 to 7 */ |
| u32 dBase, /* Address of destination: offset in frame buffer */ |
| u32 dPitch, /* Pitch value of destination surface in BYTE */ |
| u32 bytePerPixel, /* Color depth of destination surface */ |
| u32 dx, |
| u32 dy, /* Starting coordinate of destination surface */ |
| u32 width, |
| u32 height, /* width and height of rectange in pixel value */ |
| u32 fColor, /* Foreground color (corresponding to a 1 in the monochrome data */ |
| u32 bColor, /* Background color (corresponding to a 0 in the monochrome data */ |
| u32 rop2) /* ROP value */ |
| { |
| unsigned int ulBytesPerScan; |
| unsigned int ul4BytesPerScan; |
| unsigned int ulBytesRemain; |
| unsigned int de_ctrl = 0; |
| unsigned char ajRemain[4]; |
| int i, j; |
| |
| startBit &= 7; /* Just make sure the start bit is within legal range */ |
| ulBytesPerScan = (width + startBit + 7) / 8; |
| ul4BytesPerScan = ulBytesPerScan & ~3; |
| ulBytesRemain = ulBytesPerScan & 3; |
| |
| if(accel->de_wait() != 0) |
| { |
| return -1; |
| } |
| |
| /* 2D Source Base. |
| Use 0 for HOST Blt. |
| */ |
| write_dpr(accel, DE_WINDOW_SOURCE_BASE, 0); |
| |
| /* 2D Destination Base. |
| It is an address offset (128 bit aligned) from the beginning of frame buffer. |
| */ |
| write_dpr(accel, DE_WINDOW_DESTINATION_BASE, dBase); |
| #if 0 |
| /* 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 conversion. |
| */ |
| if(bytePerPixel == 3 ){ |
| dx *= 3; |
| width *= 3; |
| startBit *= 3; |
| write_dpr(accel, DE_PITCH, |
| FIELD_VALUE(0, DE_PITCH, DESTINATION, dPitch) | |
| FIELD_VALUE(0, DE_PITCH, SOURCE, dPitch)); /* dpr10 */ |
| |
| } |
| else |
| #endif |
| { |
| write_dpr(accel, DE_PITCH, |
| FIELD_VALUE(0, DE_PITCH, DESTINATION, dPitch/bytePerPixel) | |
| FIELD_VALUE(0, DE_PITCH, SOURCE, dPitch/bytePerPixel)); /* dpr10 */ |
| } |
| |
| /* Screen Window width in Pixels. |
| 2D engine uses this value to calculate the linear address in frame buffer for a given point. |
| */ |
| write_dpr(accel, 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_MONO field is needed, and Y_K2 field is not used. |
| For mono bitmap, use startBit for X_K1. */ |
| write_dpr(accel, DE_SOURCE, |
| FIELD_SET (0, DE_SOURCE, WRAP, DISABLE) | |
| FIELD_VALUE(0, DE_SOURCE, X_K1_MONO, startBit)); /* dpr00 */ |
| |
| write_dpr(accel, DE_DESTINATION, |
| FIELD_SET (0, DE_DESTINATION, WRAP, DISABLE) | |
| FIELD_VALUE(0, DE_DESTINATION, X, dx) | |
| FIELD_VALUE(0, DE_DESTINATION, Y, dy)); /* dpr04 */ |
| |
| write_dpr(accel, DE_DIMENSION, |
| FIELD_VALUE(0, DE_DIMENSION, X, width) | |
| FIELD_VALUE(0, DE_DIMENSION, Y_ET, height)); /* dpr08 */ |
| |
| write_dpr(accel, DE_FOREGROUND, fColor); |
| write_dpr(accel, DE_BACKGROUND, bColor); |
| |
| 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); |
| |
| write_dpr(accel, DE_CONTROL, de_ctrl | deGetTransparency(accel)); |
| |
| /* 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++) |
| { |
| write_dpPort(accel, *(unsigned int *)(pSrcbuf + (j * 4))); |
| } |
| |
| if (ulBytesRemain) |
| { |
| memcpy(ajRemain, pSrcbuf+ul4BytesPerScan, ulBytesRemain); |
| write_dpPort(accel, *(unsigned int *)ajRemain); |
| } |
| |
| pSrcbuf += srcDelta; |
| } |
| |
| return 0; |
| } |
| |