blob: f377a29ec97a6c9fc8a7188b5a9ac1ce29bd7c98 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001 /***************************************************************************\
2|* *|
3|* Copyright 1993-2003 NVIDIA, Corporation. All rights reserved. *|
4|* *|
5|* NOTICE TO USER: The source code is copyrighted under U.S. and *|
6|* international laws. Users and possessors of this source code are *|
7|* hereby granted a nonexclusive, royalty-free copyright license to *|
8|* use this code in individual and commercial software. *|
9|* *|
10|* Any use of this source code must include, in the user documenta- *|
11|* tion and internal comments to the code, notices to the end user *|
12|* as follows: *|
13|* *|
14|* Copyright 1993-2003 NVIDIA, Corporation. All rights reserved. *|
15|* *|
16|* NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY *|
17|* OF THIS SOURCE CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" *|
18|* WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. NVIDIA, CORPOR- *|
19|* ATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOURCE CODE, *|
20|* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE- *|
21|* MENT, AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL *|
22|* NVIDIA, CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT, INCI- *|
23|* DENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RE- *|
24|* SULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION *|
25|* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *|
26|* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE. *|
27|* *|
28|* U.S. Government End Users. This source code is a "commercial *|
29|* item," as that term is defined at 48 C.F.R. 2.101 (OCT 1995), *|
30|* consisting of "commercial computer software" and "commercial *|
31|* computer software documentation," as such terms are used in *|
32|* 48 C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Govern- *|
33|* ment only as a commercial end item. Consistent with 48 C.F.R. *|
34|* 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), *|
35|* all U.S. Government End Users acquire the source code with only *|
36|* those rights set forth herein. *|
37|* *|
38 \***************************************************************************/
39
40/*
41 * GPL Licensing Note - According to Mark Vojkovich, author of the Xorg/
42 * XFree86 'nv' driver, this source code is provided under MIT-style licensing
43 * where the source code is provided "as is" without warranty of any kind.
44 * The only usage restriction is for the copyright notices to be retained
45 * whenever code is used.
46 *
47 * Antonino Daplas <adaplas@pol.net> 2005-03-11
48 */
49
50#include <linux/fb.h>
51#include "nv_type.h"
52#include "nv_proto.h"
53#include "nv_dma.h"
54#include "nv_local.h"
55
56/* There is a HW race condition with videoram command buffers.
57 You can't jump to the location of your put offset. We write put
58 at the jump offset + SKIPS dwords with noop padding in between
59 to solve this problem */
60#define SKIPS 8
61
62static const int NVCopyROP[16] = {
63 0xCC, /* copy */
64 0x55 /* invert */
65};
66
67static const int NVCopyROP_PM[16] = {
68 0xCA, /* copy */
69 0x5A, /* invert */
70};
71
72static inline void NVFlush(struct nvidia_par *par)
73{
74 int count = 1000000000;
75
76 while (--count && READ_GET(par) != par->dmaPut) ;
77
78 if (!count) {
79 printk("nvidiafb: DMA Flush lockup\n");
80 par->lockup = 1;
81 }
82}
83
84static inline void NVSync(struct nvidia_par *par)
85{
86 int count = 1000000000;
87
88 while (--count && NV_RD32(par->PGRAPH, 0x0700)) ;
89
90 if (!count) {
91 printk("nvidiafb: DMA Sync lockup\n");
92 par->lockup = 1;
93 }
94}
95
96static void NVDmaKickoff(struct nvidia_par *par)
97{
98 if (par->dmaCurrent != par->dmaPut) {
99 par->dmaPut = par->dmaCurrent;
100 WRITE_PUT(par, par->dmaPut);
101 }
102}
103
104static void NVDmaWait(struct nvidia_par *par, int size)
105{
106 int dmaGet;
107 int count = 1000000000, cnt;
108 size++;
109
110 while (par->dmaFree < size && --count && !par->lockup) {
111 dmaGet = READ_GET(par);
112
113 if (par->dmaPut >= dmaGet) {
114 par->dmaFree = par->dmaMax - par->dmaCurrent;
115 if (par->dmaFree < size) {
116 NVDmaNext(par, 0x20000000);
117 if (dmaGet <= SKIPS) {
118 if (par->dmaPut <= SKIPS)
119 WRITE_PUT(par, SKIPS + 1);
120 cnt = 1000000000;
121 do {
122 dmaGet = READ_GET(par);
123 } while (--cnt && dmaGet <= SKIPS);
124 if (!cnt) {
125 printk("DMA Get lockup\n");
126 par->lockup = 1;
127 }
128 }
129 WRITE_PUT(par, SKIPS);
130 par->dmaCurrent = par->dmaPut = SKIPS;
131 par->dmaFree = dmaGet - (SKIPS + 1);
132 }
133 } else
134 par->dmaFree = dmaGet - par->dmaCurrent - 1;
135 }
136
137 if (!count) {
138 printk("DMA Wait Lockup\n");
139 par->lockup = 1;
140 }
141}
142
143static void NVSetPattern(struct nvidia_par *par, u32 clr0, u32 clr1,
144 u32 pat0, u32 pat1)
145{
146 NVDmaStart(par, PATTERN_COLOR_0, 4);
147 NVDmaNext(par, clr0);
148 NVDmaNext(par, clr1);
149 NVDmaNext(par, pat0);
150 NVDmaNext(par, pat1);
151}
152
153static void NVSetRopSolid(struct nvidia_par *par, u32 rop, u32 planemask)
154{
155 if (planemask != ~0) {
156 NVSetPattern(par, 0, planemask, ~0, ~0);
157 if (par->currentRop != (rop + 32)) {
158 NVDmaStart(par, ROP_SET, 1);
159 NVDmaNext(par, NVCopyROP_PM[rop]);
160 par->currentRop = rop + 32;
161 }
162 } else if (par->currentRop != rop) {
163 if (par->currentRop >= 16)
164 NVSetPattern(par, ~0, ~0, ~0, ~0);
165 NVDmaStart(par, ROP_SET, 1);
166 NVDmaNext(par, NVCopyROP[rop]);
167 par->currentRop = rop;
168 }
169}
170
171static void NVSetClippingRectangle(struct fb_info *info, int x1, int y1,
172 int x2, int y2)
173{
174 struct nvidia_par *par = info->par;
175 int h = y2 - y1 + 1;
176 int w = x2 - x1 + 1;
177
178 NVDmaStart(par, CLIP_POINT, 2);
179 NVDmaNext(par, (y1 << 16) | x1);
180 NVDmaNext(par, (h << 16) | w);
181}
182
183void NVResetGraphics(struct fb_info *info)
184{
185 struct nvidia_par *par = info->par;
186 u32 surfaceFormat, patternFormat, rectFormat, lineFormat;
187 int pitch, i;
188
189 pitch = info->fix.line_length;
190
191 par->dmaBase = (u32 __iomem *) (&par->FbStart[par->FbUsableSize]);
192
193 for (i = 0; i < SKIPS; i++)
194 NV_WR32(&par->dmaBase[i], 0, 0x00000000);
195
196 NV_WR32(&par->dmaBase[0x0 + SKIPS], 0, 0x00040000);
197 NV_WR32(&par->dmaBase[0x1 + SKIPS], 0, 0x80000010);
198 NV_WR32(&par->dmaBase[0x2 + SKIPS], 0, 0x00042000);
199 NV_WR32(&par->dmaBase[0x3 + SKIPS], 0, 0x80000011);
200 NV_WR32(&par->dmaBase[0x4 + SKIPS], 0, 0x00044000);
201 NV_WR32(&par->dmaBase[0x5 + SKIPS], 0, 0x80000012);
202 NV_WR32(&par->dmaBase[0x6 + SKIPS], 0, 0x00046000);
203 NV_WR32(&par->dmaBase[0x7 + SKIPS], 0, 0x80000013);
204 NV_WR32(&par->dmaBase[0x8 + SKIPS], 0, 0x00048000);
205 NV_WR32(&par->dmaBase[0x9 + SKIPS], 0, 0x80000014);
206 NV_WR32(&par->dmaBase[0xA + SKIPS], 0, 0x0004A000);
207 NV_WR32(&par->dmaBase[0xB + SKIPS], 0, 0x80000015);
208 NV_WR32(&par->dmaBase[0xC + SKIPS], 0, 0x0004C000);
209 NV_WR32(&par->dmaBase[0xD + SKIPS], 0, 0x80000016);
210 NV_WR32(&par->dmaBase[0xE + SKIPS], 0, 0x0004E000);
211 NV_WR32(&par->dmaBase[0xF + SKIPS], 0, 0x80000017);
212
213 par->dmaPut = 0;
214 par->dmaCurrent = 16 + SKIPS;
215 par->dmaMax = 8191;
216 par->dmaFree = par->dmaMax - par->dmaCurrent;
217
218 switch (info->var.bits_per_pixel) {
219 case 32:
220 case 24:
221 surfaceFormat = SURFACE_FORMAT_DEPTH24;
222 patternFormat = PATTERN_FORMAT_DEPTH24;
223 rectFormat = RECT_FORMAT_DEPTH24;
224 lineFormat = LINE_FORMAT_DEPTH24;
225 break;
226 case 16:
227 surfaceFormat = SURFACE_FORMAT_DEPTH16;
228 patternFormat = PATTERN_FORMAT_DEPTH16;
229 rectFormat = RECT_FORMAT_DEPTH16;
230 lineFormat = LINE_FORMAT_DEPTH16;
231 break;
232 default:
233 surfaceFormat = SURFACE_FORMAT_DEPTH8;
234 patternFormat = PATTERN_FORMAT_DEPTH8;
235 rectFormat = RECT_FORMAT_DEPTH8;
236 lineFormat = LINE_FORMAT_DEPTH8;
237 break;
238 }
239
240 NVDmaStart(par, SURFACE_FORMAT, 4);
241 NVDmaNext(par, surfaceFormat);
242 NVDmaNext(par, pitch | (pitch << 16));
243 NVDmaNext(par, 0);
244 NVDmaNext(par, 0);
245
246 NVDmaStart(par, PATTERN_FORMAT, 1);
247 NVDmaNext(par, patternFormat);
248
249 NVDmaStart(par, RECT_FORMAT, 1);
250 NVDmaNext(par, rectFormat);
251
252 NVDmaStart(par, LINE_FORMAT, 1);
253 NVDmaNext(par, lineFormat);
254
255 par->currentRop = ~0; /* set to something invalid */
256 NVSetRopSolid(par, ROP_COPY, ~0);
257
258 NVSetClippingRectangle(info, 0, 0, info->var.xres_virtual,
259 info->var.yres_virtual);
260
261 NVDmaKickoff(par);
262}
263
264u8 byte_rev[256] = {
265 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
266 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
267 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
268 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
269 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
270 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
271 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
272 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
273 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
274 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
275 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
276 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
277 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
278 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
279 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
280 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
281 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
282 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
283 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
284 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
285 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
286 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
287 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
288 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
289 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
290 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
291 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
292 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
293 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
294 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
295 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
296 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
297};
298
299int nvidiafb_sync(struct fb_info *info)
300{
301 struct nvidia_par *par = info->par;
302
303 if (!par->lockup)
304 NVFlush(par);
305
306 if (!par->lockup)
307 NVSync(par);
308
309 return 0;
310}
311
312void nvidiafb_copyarea(struct fb_info *info, const struct fb_copyarea *region)
313{
314 struct nvidia_par *par = info->par;
315
316 if (par->lockup)
317 return cfb_copyarea(info, region);
318
319 NVDmaStart(par, BLIT_POINT_SRC, 3);
320 NVDmaNext(par, (region->sy << 16) | region->sx);
321 NVDmaNext(par, (region->dy << 16) | region->dx);
322 NVDmaNext(par, (region->height << 16) | region->width);
323
324 NVDmaKickoff(par);
325}
326
327void nvidiafb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
328{
329 struct nvidia_par *par = info->par;
330 u32 color;
331
332 if (par->lockup)
333 return cfb_fillrect(info, rect);
334
335 if (info->var.bits_per_pixel == 8)
336 color = rect->color;
337 else
338 color = ((u32 *) info->pseudo_palette)[rect->color];
339
340 if (rect->rop != ROP_COPY)
341 NVSetRopSolid(par, rect->rop, ~0);
342
343 NVDmaStart(par, RECT_SOLID_COLOR, 1);
344 NVDmaNext(par, color);
345
346 NVDmaStart(par, RECT_SOLID_RECTS(0), 2);
347 NVDmaNext(par, (rect->dx << 16) | rect->dy);
348 NVDmaNext(par, (rect->width << 16) | rect->height);
349
350 NVDmaKickoff(par);
351
352 if (rect->rop != ROP_COPY)
353 NVSetRopSolid(par, ROP_COPY, ~0);
354}
355
356static void nvidiafb_mono_color_expand(struct fb_info *info,
357 const struct fb_image *image)
358{
359 struct nvidia_par *par = info->par;
360 u32 fg, bg, mask = ~(~0 >> (32 - info->var.bits_per_pixel));
361 u32 dsize, width, *data = (u32 *) image->data, tmp;
362 int j, k = 0;
363
364 width = (image->width + 31) & ~31;
365 dsize = (width * image->height) >> 5;
366
367 if (info->var.bits_per_pixel == 8) {
368 fg = image->fg_color | mask;
369 bg = image->bg_color | mask;
370 } else {
371 fg = ((u32 *) info->pseudo_palette)[image->fg_color] | mask;
372 bg = ((u32 *) info->pseudo_palette)[image->bg_color] | mask;
373 }
374
375 NVDmaStart(par, RECT_EXPAND_TWO_COLOR_CLIP, 7);
376 NVDmaNext(par, (image->dy << 16) | (image->dx & 0xffff));
377 NVDmaNext(par, ((image->dy + image->height) << 16) |
378 ((image->dx + image->width) & 0xffff));
379 NVDmaNext(par, bg);
380 NVDmaNext(par, fg);
381 NVDmaNext(par, (image->height << 16) | width);
382 NVDmaNext(par, (image->height << 16) | width);
383 NVDmaNext(par, (image->dy << 16) | (image->dx & 0xffff));
384
385 while (dsize >= RECT_EXPAND_TWO_COLOR_DATA_MAX_DWORDS) {
386 NVDmaStart(par, RECT_EXPAND_TWO_COLOR_DATA(0),
387 RECT_EXPAND_TWO_COLOR_DATA_MAX_DWORDS);
388
389 for (j = RECT_EXPAND_TWO_COLOR_DATA_MAX_DWORDS; j--;) {
390 tmp = data[k++];
391 reverse_order(&tmp);
392 NVDmaNext(par, tmp);
393 }
394
395 dsize -= RECT_EXPAND_TWO_COLOR_DATA_MAX_DWORDS;
396 }
397
398 if (dsize) {
399 NVDmaStart(par, RECT_EXPAND_TWO_COLOR_DATA(0), dsize);
400
401 for (j = dsize; j--;) {
402 tmp = data[k++];
403 reverse_order(&tmp);
404 NVDmaNext(par, tmp);
405 }
406 }
407
408 NVDmaKickoff(par);
409}
410
411void nvidiafb_imageblit(struct fb_info *info, const struct fb_image *image)
412{
413 struct nvidia_par *par = info->par;
414
415 if (image->depth == 1 && !par->lockup)
416 nvidiafb_mono_color_expand(info, image);
417 else
418 cfb_imageblit(info, image);
419}