1#include <linux/module.h> 2#include <linux/kernel.h> 3#include <linux/errno.h> 4#include <linux/string.h> 5#include <linux/mm.h> 6#include <linux/slab.h> 7#include <linux/delay.h> 8#include <linux/fb.h> 9#include <linux/ioport.h> 10#include <linux/init.h> 11#include <linux/pci.h> 12#include <linux/vmalloc.h> 13#include <linux/pagemap.h> 14#include <linux/console.h> 15#include <linux/platform_device.h> 16#include <linux/screen_info.h> 17 18#include "sm750.h" 19#include "sm750_accel.h" 20#include "sm750_help.h" 21static inline void write_dpr(struct lynx_accel *accel, int offset, u32 regValue) 22{ 23 writel(regValue, accel->dprBase + offset); 24} 25 26static inline u32 read_dpr(struct lynx_accel *accel, int offset) 27{ 28 return readl(accel->dprBase + offset); 29} 30 31static inline void write_dpPort(struct lynx_accel *accel, u32 data) 32{ 33 writel(data, accel->dpPortBase); 34} 35 36void hw_de_init(struct lynx_accel *accel) 37{ 38 /* setup 2d engine registers */ 39 u32 reg, clr; 40 41 write_dpr(accel, DE_MASKS, 0xFFFFFFFF); 42 43 /* dpr1c */ 44 reg = FIELD_SET(0, DE_STRETCH_FORMAT, PATTERN_XY, NORMAL)| 45 FIELD_VALUE(0, DE_STRETCH_FORMAT, PATTERN_Y, 0)| 46 FIELD_VALUE(0, DE_STRETCH_FORMAT, PATTERN_X, 0)| 47 FIELD_SET(0, DE_STRETCH_FORMAT, ADDRESSING, XY)| 48 FIELD_VALUE(0, DE_STRETCH_FORMAT, SOURCE_HEIGHT, 3); 49 50 clr = FIELD_CLEAR(DE_STRETCH_FORMAT, PATTERN_XY)& 51 FIELD_CLEAR(DE_STRETCH_FORMAT, PATTERN_Y)& 52 FIELD_CLEAR(DE_STRETCH_FORMAT, PATTERN_X)& 53 FIELD_CLEAR(DE_STRETCH_FORMAT, ADDRESSING)& 54 FIELD_CLEAR(DE_STRETCH_FORMAT, SOURCE_HEIGHT); 55 56 /* DE_STRETCH bpp format need be initilized in setMode routine */ 57 write_dpr(accel, DE_STRETCH_FORMAT, (read_dpr(accel, DE_STRETCH_FORMAT) & clr) | reg); 58 59 /* disable clipping and transparent */ 60 write_dpr(accel, DE_CLIP_TL, 0); /* dpr2c */ 61 write_dpr(accel, DE_CLIP_BR, 0); /* dpr30 */ 62 63 write_dpr(accel, DE_COLOR_COMPARE_MASK, 0); /* dpr24 */ 64 write_dpr(accel, DE_COLOR_COMPARE, 0); 65 66 reg = FIELD_SET(0, DE_CONTROL, TRANSPARENCY, DISABLE)| 67 FIELD_SET(0, DE_CONTROL, TRANSPARENCY_MATCH, OPAQUE)| 68 FIELD_SET(0, DE_CONTROL, TRANSPARENCY_SELECT, SOURCE); 69 70 clr = FIELD_CLEAR(DE_CONTROL, TRANSPARENCY)& 71 FIELD_CLEAR(DE_CONTROL, TRANSPARENCY_MATCH)& 72 FIELD_CLEAR(DE_CONTROL, TRANSPARENCY_SELECT); 73 74 /* dpr0c */ 75 write_dpr(accel, DE_CONTROL, (read_dpr(accel, DE_CONTROL)&clr)|reg); 76} 77 78/* set2dformat only be called from setmode functions 79 * but if you need dual framebuffer driver,need call set2dformat 80 * every time you use 2d function */ 81 82void hw_set2dformat(struct lynx_accel *accel, int fmt) 83{ 84 u32 reg; 85 86 /* fmt=0,1,2 for 8,16,32,bpp on sm718/750/502 */ 87 reg = read_dpr(accel, DE_STRETCH_FORMAT); 88 reg = FIELD_VALUE(reg, DE_STRETCH_FORMAT, PIXEL_FORMAT, fmt); 89 write_dpr(accel, DE_STRETCH_FORMAT, reg); 90} 91 92int hw_fillrect(struct lynx_accel *accel, 93 u32 base, u32 pitch, u32 Bpp, 94 u32 x, u32 y, u32 width, u32 height, 95 u32 color, u32 rop) 96{ 97 u32 deCtrl; 98 99 if (accel->de_wait() != 0) { 100 /* int time wait and always busy,seems hardware 101 * got something error */ 102 pr_debug("De engine always busy\n"); 103 return -1; 104 } 105 106 write_dpr(accel, DE_WINDOW_DESTINATION_BASE, base); /* dpr40 */ 107 write_dpr(accel, DE_PITCH, 108 FIELD_VALUE(0, DE_PITCH, DESTINATION, pitch/Bpp)| 109 FIELD_VALUE(0, DE_PITCH, SOURCE, pitch/Bpp)); /* dpr10 */ 110 111 write_dpr(accel, DE_WINDOW_WIDTH, 112 FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, pitch/Bpp)| 113 FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE, pitch/Bpp)); /* dpr44 */ 114 115 write_dpr(accel, DE_FOREGROUND, color); /* DPR14 */ 116 117 write_dpr(accel, DE_DESTINATION, 118 FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE)| 119 FIELD_VALUE(0, DE_DESTINATION, X, x)| 120 FIELD_VALUE(0, DE_DESTINATION, Y, y)); /* dpr4 */ 121 122 write_dpr(accel, DE_DIMENSION, 123 FIELD_VALUE(0, DE_DIMENSION, X, width)| 124 FIELD_VALUE(0, DE_DIMENSION, Y_ET, height)); /* dpr8 */ 125 126 deCtrl = 127 FIELD_SET(0, DE_CONTROL, STATUS, START)| 128 FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT)| 129 FIELD_SET(0, DE_CONTROL, LAST_PIXEL, ON)| 130 FIELD_SET(0, DE_CONTROL, COMMAND, RECTANGLE_FILL)| 131 FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2)| 132 FIELD_VALUE(0, DE_CONTROL, ROP, rop); /* dpr0xc */ 133 134 write_dpr(accel, DE_CONTROL, deCtrl); 135 return 0; 136} 137 138int hw_copyarea( 139struct lynx_accel *accel, 140unsigned int sBase, /* Address of source: offset in frame buffer */ 141unsigned int sPitch, /* Pitch value of source surface in BYTE */ 142unsigned int sx, 143unsigned int sy, /* Starting coordinate of source surface */ 144unsigned int dBase, /* Address of destination: offset in frame buffer */ 145unsigned int dPitch, /* Pitch value of destination surface in BYTE */ 146unsigned int Bpp, /* Color depth of destination surface */ 147unsigned int dx, 148unsigned int dy, /* Starting coordinate of destination surface */ 149unsigned int width, 150unsigned int height, /* width and height of rectangle in pixel value */ 151unsigned int rop2) /* ROP value */ 152{ 153 unsigned int nDirection, de_ctrl; 154 int opSign; 155 156 nDirection = LEFT_TO_RIGHT; 157 /* Direction of ROP2 operation: 1 = Left to Right, (-1) = Right to Left */ 158 opSign = 1; 159 de_ctrl = 0; 160 161 /* If source and destination are the same surface, need to check for overlay cases */ 162 if (sBase == dBase && sPitch == dPitch) { 163 /* Determine direction of operation */ 164 if (sy < dy) { 165 /* +----------+ 166 |S | 167 | +----------+ 168 | | | | 169 | | | | 170 +---|------+ | 171 | D| 172 +----------+ */ 173 174 nDirection = BOTTOM_TO_TOP; 175 } else if (sy > dy) { 176 /* +----------+ 177 |D | 178 | +----------+ 179 | | | | 180 | | | | 181 +---|------+ | 182 | S| 183 +----------+ */ 184 185 nDirection = TOP_TO_BOTTOM; 186 } else { 187 /* sy == dy */ 188 189 if (sx <= dx) { 190 /* +------+---+------+ 191 |S | | D| 192 | | | | 193 | | | | 194 | | | | 195 +------+---+------+ */ 196 197 nDirection = RIGHT_TO_LEFT; 198 } else { 199 /* sx > dx */ 200 201 /* +------+---+------+ 202 |D | | S| 203 | | | | 204 | | | | 205 | | | | 206 +------+---+------+ */ 207 208 nDirection = LEFT_TO_RIGHT; 209 } 210 } 211 } 212 213 if ((nDirection == BOTTOM_TO_TOP) || (nDirection == RIGHT_TO_LEFT)) { 214 sx += width - 1; 215 sy += height - 1; 216 dx += width - 1; 217 dy += height - 1; 218 opSign = (-1); 219 } 220 221 /* Note: 222 DE_FOREGROUND are DE_BACKGROUND are don't care. 223 DE_COLOR_COMPARE and DE_COLOR_COMPARE_MAKS are set by set deSetTransparency(). 224 */ 225 226 /* 2D Source Base. 227 It is an address offset (128 bit aligned) from the beginning of frame buffer. 228 */ 229 write_dpr(accel, DE_WINDOW_SOURCE_BASE, sBase); /* dpr40 */ 230 231 /* 2D Destination Base. 232 It is an address offset (128 bit aligned) from the beginning of frame buffer. 233 */ 234 write_dpr(accel, DE_WINDOW_DESTINATION_BASE, dBase); /* dpr44 */ 235 236 /* Program pitch (distance between the 1st points of two adjacent lines). 237 Note that input pitch is BYTE value, but the 2D Pitch register uses 238 pixel values. Need Byte to pixel conversion. 239 */ 240 { 241 write_dpr(accel, DE_PITCH, 242 FIELD_VALUE(0, DE_PITCH, DESTINATION, (dPitch/Bpp)) | 243 FIELD_VALUE(0, DE_PITCH, SOURCE, (sPitch/Bpp))); /* dpr10 */ 244 } 245 246 /* Screen Window width in Pixels. 247 2D engine uses this value to calculate the linear address in frame buffer for a given point. 248 */ 249 write_dpr(accel, DE_WINDOW_WIDTH, 250 FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, (dPitch/Bpp)) | 251 FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE, (sPitch/Bpp))); /* dpr3c */ 252 253 if (accel->de_wait() != 0) 254 return -1; 255 256 { 257 258 write_dpr(accel, DE_SOURCE, 259 FIELD_SET(0, DE_SOURCE, WRAP, DISABLE) | 260 FIELD_VALUE(0, DE_SOURCE, X_K1, sx) | 261 FIELD_VALUE(0, DE_SOURCE, Y_K2, sy)); /* dpr0 */ 262 write_dpr(accel, DE_DESTINATION, 263 FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) | 264 FIELD_VALUE(0, DE_DESTINATION, X, dx) | 265 FIELD_VALUE(0, DE_DESTINATION, Y, dy)); /* dpr04 */ 266 write_dpr(accel, DE_DIMENSION, 267 FIELD_VALUE(0, DE_DIMENSION, X, width) | 268 FIELD_VALUE(0, DE_DIMENSION, Y_ET, height)); /* dpr08 */ 269 270 de_ctrl = FIELD_VALUE(0, DE_CONTROL, ROP, rop2) | 271 FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) | 272 FIELD_SET(0, DE_CONTROL, COMMAND, BITBLT) | 273 ((nDirection == RIGHT_TO_LEFT) ? 274 FIELD_SET(0, DE_CONTROL, DIRECTION, RIGHT_TO_LEFT) 275 : FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT)) | 276 FIELD_SET(0, DE_CONTROL, STATUS, START); 277 write_dpr(accel, DE_CONTROL, de_ctrl); /* dpr0c */ 278 279 } 280 281 return 0; 282} 283 284static unsigned int deGetTransparency(struct lynx_accel *accel) 285{ 286 unsigned int de_ctrl; 287 288 de_ctrl = read_dpr(accel, DE_CONTROL); 289 290 de_ctrl &= 291 FIELD_MASK(DE_CONTROL_TRANSPARENCY_MATCH) | 292 FIELD_MASK(DE_CONTROL_TRANSPARENCY_SELECT)| 293 FIELD_MASK(DE_CONTROL_TRANSPARENCY); 294 295 return de_ctrl; 296} 297 298int hw_imageblit(struct lynx_accel *accel, 299 const char *pSrcbuf, /* pointer to start of source buffer in system memory */ 300 u32 srcDelta, /* Pitch value (in bytes) of the source buffer, +ive means top down and -ive mean button up */ 301 u32 startBit, /* Mono data can start at any bit in a byte, this value should be 0 to 7 */ 302 u32 dBase, /* Address of destination: offset in frame buffer */ 303 u32 dPitch, /* Pitch value of destination surface in BYTE */ 304 u32 bytePerPixel, /* Color depth of destination surface */ 305 u32 dx, 306 u32 dy, /* Starting coordinate of destination surface */ 307 u32 width, 308 u32 height, /* width and height of rectange in pixel value */ 309 u32 fColor, /* Foreground color (corresponding to a 1 in the monochrome data */ 310 u32 bColor, /* Background color (corresponding to a 0 in the monochrome data */ 311 u32 rop2) /* ROP value */ 312{ 313 unsigned int ulBytesPerScan; 314 unsigned int ul4BytesPerScan; 315 unsigned int ulBytesRemain; 316 unsigned int de_ctrl = 0; 317 unsigned char ajRemain[4]; 318 int i, j; 319 320 startBit &= 7; /* Just make sure the start bit is within legal range */ 321 ulBytesPerScan = (width + startBit + 7) / 8; 322 ul4BytesPerScan = ulBytesPerScan & ~3; 323 ulBytesRemain = ulBytesPerScan & 3; 324 325 if (accel->de_wait() != 0) 326 return -1; 327 328 /* 2D Source Base. 329 Use 0 for HOST Blt. 330 */ 331 write_dpr(accel, DE_WINDOW_SOURCE_BASE, 0); 332 333 /* 2D Destination Base. 334 It is an address offset (128 bit aligned) from the beginning of frame buffer. 335 */ 336 write_dpr(accel, DE_WINDOW_DESTINATION_BASE, dBase); 337 /* Program pitch (distance between the 1st points of two adjacent lines). 338 Note that input pitch is BYTE value, but the 2D Pitch register uses 339 pixel values. Need Byte to pixel conversion. 340 */ 341 { 342 write_dpr(accel, DE_PITCH, 343 FIELD_VALUE(0, DE_PITCH, DESTINATION, dPitch/bytePerPixel) | 344 FIELD_VALUE(0, DE_PITCH, SOURCE, dPitch/bytePerPixel)); /* dpr10 */ 345 } 346 347 /* Screen Window width in Pixels. 348 2D engine uses this value to calculate the linear address in frame buffer for a given point. 349 */ 350 write_dpr(accel, DE_WINDOW_WIDTH, 351 FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, (dPitch/bytePerPixel)) | 352 FIELD_VALUE(0, DE_WINDOW_WIDTH, SOURCE, (dPitch/bytePerPixel))); 353 354 /* Note: For 2D Source in Host Write, only X_K1_MONO field is needed, and Y_K2 field is not used. 355 For mono bitmap, use startBit for X_K1. */ 356 write_dpr(accel, DE_SOURCE, 357 FIELD_SET(0, DE_SOURCE, WRAP, DISABLE) | 358 FIELD_VALUE(0, DE_SOURCE, X_K1_MONO, startBit)); /* dpr00 */ 359 360 write_dpr(accel, DE_DESTINATION, 361 FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) | 362 FIELD_VALUE(0, DE_DESTINATION, X, dx) | 363 FIELD_VALUE(0, DE_DESTINATION, Y, dy)); /* dpr04 */ 364 365 write_dpr(accel, DE_DIMENSION, 366 FIELD_VALUE(0, DE_DIMENSION, X, width) | 367 FIELD_VALUE(0, DE_DIMENSION, Y_ET, height)); /* dpr08 */ 368 369 write_dpr(accel, DE_FOREGROUND, fColor); 370 write_dpr(accel, DE_BACKGROUND, bColor); 371 372 de_ctrl = FIELD_VALUE(0, DE_CONTROL, ROP, rop2) | 373 FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) | 374 FIELD_SET(0, DE_CONTROL, COMMAND, HOST_WRITE) | 375 FIELD_SET(0, DE_CONTROL, HOST, MONO) | 376 FIELD_SET(0, DE_CONTROL, STATUS, START); 377 378 write_dpr(accel, DE_CONTROL, de_ctrl | deGetTransparency(accel)); 379 380 /* Write MONO data (line by line) to 2D Engine data port */ 381 for (i = 0; i < height; i++) { 382 /* For each line, send the data in chunks of 4 bytes */ 383 for (j = 0; j < (ul4BytesPerScan/4); j++) 384 write_dpPort(accel, *(unsigned int *)(pSrcbuf + (j * 4))); 385 386 if (ulBytesRemain) { 387 memcpy(ajRemain, pSrcbuf+ul4BytesPerScan, ulBytesRemain); 388 write_dpPort(accel, *(unsigned int *)ajRemain); 389 } 390 391 pSrcbuf += srcDelta; 392 } 393 394 return 0; 395} 396 397