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