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