blob: 2a6bfcdc3039806bf1438535581950220e7e1715 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/drivers/video/tgafb.c -- DEC 21030 TGA frame buffer device
3 *
4 * Copyright (C) 1995 Jay Estabrook
5 * Copyright (C) 1997 Geert Uytterhoeven
6 * Copyright (C) 1999,2000 Martin Lucina, Tom Zerucha
7 * Copyright (C) 2002 Richard Henderson
8 *
9 * This file is subject to the terms and conditions of the GNU General Public
10 * License. See the file COPYING in the main directory of this archive for
11 * more details.
12 */
13
14#include <linux/module.h>
15#include <linux/kernel.h>
16#include <linux/sched.h>
17#include <linux/errno.h>
18#include <linux/string.h>
19#include <linux/mm.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070020#include <linux/slab.h>
21#include <linux/delay.h>
22#include <linux/init.h>
23#include <linux/fb.h>
24#include <linux/pci.h>
25#include <linux/selection.h>
Akinobu Mita1c667682006-12-08 02:36:26 -080026#include <linux/bitrev.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070027#include <asm/io.h>
28#include <video/tgafb.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
30/*
31 * Local functions.
32 */
33
34static int tgafb_check_var(struct fb_var_screeninfo *, struct fb_info *);
35static int tgafb_set_par(struct fb_info *);
36static void tgafb_set_pll(struct tga_par *, int);
37static int tgafb_setcolreg(unsigned, unsigned, unsigned, unsigned,
38 unsigned, struct fb_info *);
39static int tgafb_blank(int, struct fb_info *);
40static void tgafb_init_fix(struct fb_info *);
41
42static void tgafb_imageblit(struct fb_info *, const struct fb_image *);
43static void tgafb_fillrect(struct fb_info *, const struct fb_fillrect *);
44static void tgafb_copyarea(struct fb_info *, const struct fb_copyarea *);
45
Maciej W. Rozycki1b2f2fe2007-02-12 00:54:56 -080046static int __devinit tgafb_pci_register(struct pci_dev *,
47 const struct pci_device_id *);
48static void __devexit tgafb_pci_unregister(struct pci_dev *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070049
50static const char *mode_option = "640x480@60";
51
52
53/*
54 * Frame buffer operations
55 */
56
57static struct fb_ops tgafb_ops = {
58 .owner = THIS_MODULE,
59 .fb_check_var = tgafb_check_var,
60 .fb_set_par = tgafb_set_par,
61 .fb_setcolreg = tgafb_setcolreg,
62 .fb_blank = tgafb_blank,
63 .fb_fillrect = tgafb_fillrect,
64 .fb_copyarea = tgafb_copyarea,
65 .fb_imageblit = tgafb_imageblit,
Linus Torvalds1da177e2005-04-16 15:20:36 -070066};
67
68
69/*
70 * PCI registration operations
71 */
72
73static struct pci_device_id const tgafb_pci_table[] = {
74 { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TGA, PCI_ANY_ID, PCI_ANY_ID,
75 0, 0, 0 }
76};
77
78static struct pci_driver tgafb_driver = {
79 .name = "tgafb",
80 .id_table = tgafb_pci_table,
81 .probe = tgafb_pci_register,
82 .remove = __devexit_p(tgafb_pci_unregister),
83};
84
85
86/**
87 * tgafb_check_var - Optional function. Validates a var passed in.
88 * @var: frame buffer variable screen structure
89 * @info: frame buffer structure that represents a single frame buffer
90 */
91static int
92tgafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
93{
94 struct tga_par *par = (struct tga_par *)info->par;
95
96 if (par->tga_type == TGA_TYPE_8PLANE) {
97 if (var->bits_per_pixel != 8)
98 return -EINVAL;
99 } else {
100 if (var->bits_per_pixel != 32)
101 return -EINVAL;
102 }
Maciej W. Rozyckibe601182007-02-12 00:54:54 -0800103 var->red.length = var->green.length = var->blue.length = 8;
104 if (var->bits_per_pixel == 32) {
105 var->red.offset = 16;
106 var->green.offset = 8;
107 var->blue.offset = 0;
108 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109
110 if (var->xres_virtual != var->xres || var->yres_virtual != var->yres)
111 return -EINVAL;
112 if (var->nonstd)
113 return -EINVAL;
114 if (1000000000 / var->pixclock > TGA_PLL_MAX_FREQ)
115 return -EINVAL;
116 if ((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
117 return -EINVAL;
118
119 /* Some of the acceleration routines assume the line width is
120 a multiple of 64 bytes. */
121 if (var->xres * (par->tga_type == TGA_TYPE_8PLANE ? 1 : 4) % 64)
122 return -EINVAL;
123
124 return 0;
125}
126
127/**
128 * tgafb_set_par - Optional function. Alters the hardware state.
129 * @info: frame buffer structure that represents a single frame buffer
130 */
131static int
132tgafb_set_par(struct fb_info *info)
133{
134 static unsigned int const deep_presets[4] = {
135 0x00014000,
136 0x0001440d,
137 0xffffffff,
138 0x0001441d
139 };
140 static unsigned int const rasterop_presets[4] = {
141 0x00000003,
142 0x00000303,
143 0xffffffff,
144 0x00000303
145 };
146 static unsigned int const mode_presets[4] = {
Maciej W. Rozyckic7488ce2007-02-12 00:54:55 -0800147 0x00000000,
148 0x00000300,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149 0xffffffff,
Maciej W. Rozyckic7488ce2007-02-12 00:54:55 -0800150 0x00000300
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151 };
152 static unsigned int const base_addr_presets[4] = {
153 0x00000000,
154 0x00000001,
155 0xffffffff,
156 0x00000001
157 };
158
159 struct tga_par *par = (struct tga_par *) info->par;
160 u32 htimings, vtimings, pll_freq;
161 u8 tga_type;
Maciej W. Rozyckibe601182007-02-12 00:54:54 -0800162 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163
164 /* Encode video timings. */
165 htimings = (((info->var.xres/4) & TGA_HORIZ_ACT_LSB)
166 | (((info->var.xres/4) & 0x600 << 19) & TGA_HORIZ_ACT_MSB));
167 vtimings = (info->var.yres & TGA_VERT_ACTIVE);
168 htimings |= ((info->var.right_margin/4) << 9) & TGA_HORIZ_FP;
169 vtimings |= (info->var.lower_margin << 11) & TGA_VERT_FP;
170 htimings |= ((info->var.hsync_len/4) << 14) & TGA_HORIZ_SYNC;
171 vtimings |= (info->var.vsync_len << 16) & TGA_VERT_SYNC;
172 htimings |= ((info->var.left_margin/4) << 21) & TGA_HORIZ_BP;
173 vtimings |= (info->var.upper_margin << 22) & TGA_VERT_BP;
174
175 if (info->var.sync & FB_SYNC_HOR_HIGH_ACT)
176 htimings |= TGA_HORIZ_POLARITY;
177 if (info->var.sync & FB_SYNC_VERT_HIGH_ACT)
178 vtimings |= TGA_VERT_POLARITY;
179
180 par->htimings = htimings;
181 par->vtimings = vtimings;
182
183 par->sync_on_green = !!(info->var.sync & FB_SYNC_ON_GREEN);
184
185 /* Store other useful values in par. */
186 par->xres = info->var.xres;
187 par->yres = info->var.yres;
188 par->pll_freq = pll_freq = 1000000000 / info->var.pixclock;
189 par->bits_per_pixel = info->var.bits_per_pixel;
190
191 tga_type = par->tga_type;
192
193 /* First, disable video. */
194 TGA_WRITE_REG(par, TGA_VALID_VIDEO | TGA_VALID_BLANK, TGA_VALID_REG);
195
196 /* Write the DEEP register. */
197 while (TGA_READ_REG(par, TGA_CMD_STAT_REG) & 1) /* wait for not busy */
198 continue;
199 mb();
200 TGA_WRITE_REG(par, deep_presets[tga_type], TGA_DEEP_REG);
201 while (TGA_READ_REG(par, TGA_CMD_STAT_REG) & 1) /* wait for not busy */
202 continue;
203 mb();
204
205 /* Write some more registers. */
206 TGA_WRITE_REG(par, rasterop_presets[tga_type], TGA_RASTEROP_REG);
207 TGA_WRITE_REG(par, mode_presets[tga_type], TGA_MODE_REG);
208 TGA_WRITE_REG(par, base_addr_presets[tga_type], TGA_BASE_ADDR_REG);
209
210 /* Calculate & write the PLL. */
211 tgafb_set_pll(par, pll_freq);
212
213 /* Write some more registers. */
214 TGA_WRITE_REG(par, 0xffffffff, TGA_PLANEMASK_REG);
215 TGA_WRITE_REG(par, 0xffffffff, TGA_PIXELMASK_REG);
216
217 /* Init video timing regs. */
218 TGA_WRITE_REG(par, htimings, TGA_HORIZ_REG);
219 TGA_WRITE_REG(par, vtimings, TGA_VERT_REG);
220
221 /* Initalise RAMDAC. */
222 if (tga_type == TGA_TYPE_8PLANE) {
223
224 /* Init BT485 RAMDAC registers. */
225 BT485_WRITE(par, 0xa2 | (par->sync_on_green ? 0x8 : 0x0),
226 BT485_CMD_0);
227 BT485_WRITE(par, 0x01, BT485_ADDR_PAL_WRITE);
228 BT485_WRITE(par, 0x14, BT485_CMD_3); /* cursor 64x64 */
229 BT485_WRITE(par, 0x40, BT485_CMD_1);
230 BT485_WRITE(par, 0x20, BT485_CMD_2); /* cursor off, for now */
231 BT485_WRITE(par, 0xff, BT485_PIXEL_MASK);
232
233 /* Fill palette registers. */
234 BT485_WRITE(par, 0x00, BT485_ADDR_PAL_WRITE);
235 TGA_WRITE_REG(par, BT485_DATA_PAL, TGA_RAMDAC_SETUP_REG);
236
Maciej W. Rozyckibe601182007-02-12 00:54:54 -0800237#ifdef CONFIG_HW_CONSOLE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 for (i = 0; i < 16; i++) {
Maciej W. Rozyckibe601182007-02-12 00:54:54 -0800239 int j = color_table[i];
240
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 TGA_WRITE_REG(par, default_red[j]|(BT485_DATA_PAL<<8),
242 TGA_RAMDAC_REG);
243 TGA_WRITE_REG(par, default_grn[j]|(BT485_DATA_PAL<<8),
244 TGA_RAMDAC_REG);
245 TGA_WRITE_REG(par, default_blu[j]|(BT485_DATA_PAL<<8),
246 TGA_RAMDAC_REG);
247 }
Maciej W. Rozyckibe601182007-02-12 00:54:54 -0800248 for (i = 0; i < 240 * 3; i += 4) {
249#else
250 for (i = 0; i < 256 * 3; i += 4) {
251#endif
252 TGA_WRITE_REG(par, 0x55 | (BT485_DATA_PAL << 8),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 TGA_RAMDAC_REG);
Maciej W. Rozyckibe601182007-02-12 00:54:54 -0800254 TGA_WRITE_REG(par, 0x00 | (BT485_DATA_PAL << 8),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 TGA_RAMDAC_REG);
Maciej W. Rozyckibe601182007-02-12 00:54:54 -0800256 TGA_WRITE_REG(par, 0x00 | (BT485_DATA_PAL << 8),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 TGA_RAMDAC_REG);
Maciej W. Rozyckibe601182007-02-12 00:54:54 -0800258 TGA_WRITE_REG(par, 0x00 | (BT485_DATA_PAL << 8),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 TGA_RAMDAC_REG);
260 }
261
262 } else { /* 24-plane or 24plusZ */
263
264 /* Init BT463 registers. */
265 BT463_WRITE(par, BT463_REG_ACC, BT463_CMD_REG_0, 0x40);
266 BT463_WRITE(par, BT463_REG_ACC, BT463_CMD_REG_1, 0x08);
267 BT463_WRITE(par, BT463_REG_ACC, BT463_CMD_REG_2,
268 (par->sync_on_green ? 0x80 : 0x40));
269
270 BT463_WRITE(par, BT463_REG_ACC, BT463_READ_MASK_0, 0xff);
271 BT463_WRITE(par, BT463_REG_ACC, BT463_READ_MASK_1, 0xff);
272 BT463_WRITE(par, BT463_REG_ACC, BT463_READ_MASK_2, 0xff);
273 BT463_WRITE(par, BT463_REG_ACC, BT463_READ_MASK_3, 0x0f);
274
275 BT463_WRITE(par, BT463_REG_ACC, BT463_BLINK_MASK_0, 0x00);
276 BT463_WRITE(par, BT463_REG_ACC, BT463_BLINK_MASK_1, 0x00);
277 BT463_WRITE(par, BT463_REG_ACC, BT463_BLINK_MASK_2, 0x00);
278 BT463_WRITE(par, BT463_REG_ACC, BT463_BLINK_MASK_3, 0x00);
279
280 /* Fill the palette. */
281 BT463_LOAD_ADDR(par, 0x0000);
Maciej W. Rozyckibe601182007-02-12 00:54:54 -0800282 TGA_WRITE_REG(par, BT463_PALETTE << 2, TGA_RAMDAC_SETUP_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283
Maciej W. Rozyckibe601182007-02-12 00:54:54 -0800284#ifdef CONFIG_HW_CONSOLE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 for (i = 0; i < 16; i++) {
Maciej W. Rozyckibe601182007-02-12 00:54:54 -0800286 int j = color_table[i];
287
288 TGA_WRITE_REG(par, default_red[j], TGA_RAMDAC_REG);
289 TGA_WRITE_REG(par, default_grn[j], TGA_RAMDAC_REG);
290 TGA_WRITE_REG(par, default_blu[j], TGA_RAMDAC_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 }
Maciej W. Rozyckibe601182007-02-12 00:54:54 -0800292 for (i = 0; i < 512 * 3; i += 4) {
293#else
294 for (i = 0; i < 528 * 3; i += 4) {
295#endif
296 TGA_WRITE_REG(par, 0x55, TGA_RAMDAC_REG);
297 TGA_WRITE_REG(par, 0x00, TGA_RAMDAC_REG);
298 TGA_WRITE_REG(par, 0x00, TGA_RAMDAC_REG);
299 TGA_WRITE_REG(par, 0x00, TGA_RAMDAC_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 }
301
302 /* Fill window type table after start of vertical retrace. */
303 while (!(TGA_READ_REG(par, TGA_INTR_STAT_REG) & 0x01))
304 continue;
305 TGA_WRITE_REG(par, 0x01, TGA_INTR_STAT_REG);
306 mb();
307 while (!(TGA_READ_REG(par, TGA_INTR_STAT_REG) & 0x01))
308 continue;
309 TGA_WRITE_REG(par, 0x01, TGA_INTR_STAT_REG);
310
311 BT463_LOAD_ADDR(par, BT463_WINDOW_TYPE_BASE);
Maciej W. Rozyckibe601182007-02-12 00:54:54 -0800312 TGA_WRITE_REG(par, BT463_REG_ACC << 2, TGA_RAMDAC_SETUP_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313
314 for (i = 0; i < 16; i++) {
Maciej W. Rozyckibe601182007-02-12 00:54:54 -0800315 TGA_WRITE_REG(par, 0x00, TGA_RAMDAC_REG);
316 TGA_WRITE_REG(par, 0x01, TGA_RAMDAC_REG);
317 TGA_WRITE_REG(par, 0x00, TGA_RAMDAC_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 }
319
320 }
321
322 /* Finally, enable video scan (and pray for the monitor... :-) */
323 TGA_WRITE_REG(par, TGA_VALID_VIDEO, TGA_VALID_REG);
324
325 return 0;
326}
327
328#define DIFFCHECK(X) \
329do { \
330 if (m <= 0x3f) { \
331 int delta = f - (TGA_PLL_BASE_FREQ * (X)) / (r << shift); \
332 if (delta < 0) \
333 delta = -delta; \
334 if (delta < min_diff) \
335 min_diff = delta, vm = m, va = a, vr = r; \
336 } \
337} while (0)
338
339static void
340tgafb_set_pll(struct tga_par *par, int f)
341{
342 int n, shift, base, min_diff, target;
343 int r,a,m,vm = 34, va = 1, vr = 30;
344
345 for (r = 0 ; r < 12 ; r++)
346 TGA_WRITE_REG(par, !r, TGA_CLOCK_REG);
347
348 if (f > TGA_PLL_MAX_FREQ)
349 f = TGA_PLL_MAX_FREQ;
350
351 if (f >= TGA_PLL_MAX_FREQ / 2)
352 shift = 0;
353 else if (f >= TGA_PLL_MAX_FREQ / 4)
354 shift = 1;
355 else
356 shift = 2;
357
358 TGA_WRITE_REG(par, shift & 1, TGA_CLOCK_REG);
359 TGA_WRITE_REG(par, shift >> 1, TGA_CLOCK_REG);
360
361 for (r = 0 ; r < 10 ; r++)
362 TGA_WRITE_REG(par, 0, TGA_CLOCK_REG);
363
364 if (f <= 120000) {
365 TGA_WRITE_REG(par, 0, TGA_CLOCK_REG);
366 TGA_WRITE_REG(par, 0, TGA_CLOCK_REG);
367 }
368 else if (f <= 200000) {
369 TGA_WRITE_REG(par, 1, TGA_CLOCK_REG);
370 TGA_WRITE_REG(par, 0, TGA_CLOCK_REG);
371 }
372 else {
373 TGA_WRITE_REG(par, 0, TGA_CLOCK_REG);
374 TGA_WRITE_REG(par, 1, TGA_CLOCK_REG);
375 }
376
377 TGA_WRITE_REG(par, 1, TGA_CLOCK_REG);
378 TGA_WRITE_REG(par, 0, TGA_CLOCK_REG);
379 TGA_WRITE_REG(par, 0, TGA_CLOCK_REG);
380 TGA_WRITE_REG(par, 1, TGA_CLOCK_REG);
381 TGA_WRITE_REG(par, 0, TGA_CLOCK_REG);
382 TGA_WRITE_REG(par, 1, TGA_CLOCK_REG);
383
384 target = (f << shift) / TGA_PLL_BASE_FREQ;
385 min_diff = TGA_PLL_MAX_FREQ;
386
387 r = 7 / target;
388 if (!r) r = 1;
389
390 base = target * r;
391 while (base < 449) {
392 for (n = base < 7 ? 7 : base; n < base + target && n < 449; n++) {
393 m = ((n + 3) / 7) - 1;
394 a = 0;
395 DIFFCHECK((m + 1) * 7);
396 m++;
397 DIFFCHECK((m + 1) * 7);
398 m = (n / 6) - 1;
399 if ((a = n % 6))
400 DIFFCHECK(n);
401 }
402 r++;
403 base += target;
404 }
405
406 vr--;
407
408 for (r = 0; r < 8; r++)
409 TGA_WRITE_REG(par, (vm >> r) & 1, TGA_CLOCK_REG);
410 for (r = 0; r < 8 ; r++)
411 TGA_WRITE_REG(par, (va >> r) & 1, TGA_CLOCK_REG);
412 for (r = 0; r < 7 ; r++)
413 TGA_WRITE_REG(par, (vr >> r) & 1, TGA_CLOCK_REG);
414 TGA_WRITE_REG(par, ((vr >> 7) & 1)|2, TGA_CLOCK_REG);
415}
416
417
418/**
419 * tgafb_setcolreg - Optional function. Sets a color register.
420 * @regno: boolean, 0 copy local, 1 get_user() function
421 * @red: frame buffer colormap structure
422 * @green: The green value which can be up to 16 bits wide
423 * @blue: The blue value which can be up to 16 bits wide.
424 * @transp: If supported the alpha value which can be up to 16 bits wide.
425 * @info: frame buffer info structure
426 */
427static int
428tgafb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
429 unsigned transp, struct fb_info *info)
430{
431 struct tga_par *par = (struct tga_par *) info->par;
432
433 if (regno > 255)
434 return 1;
435 red >>= 8;
436 green >>= 8;
437 blue >>= 8;
438
439 if (par->tga_type == TGA_TYPE_8PLANE) {
440 BT485_WRITE(par, regno, BT485_ADDR_PAL_WRITE);
441 TGA_WRITE_REG(par, BT485_DATA_PAL, TGA_RAMDAC_SETUP_REG);
442 TGA_WRITE_REG(par, red|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG);
443 TGA_WRITE_REG(par, green|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG);
444 TGA_WRITE_REG(par, blue|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG);
Maciej W. Rozyckibe601182007-02-12 00:54:54 -0800445 } else {
446 if (regno < 16) {
447 u32 value = (regno << 16) | (regno << 8) | regno;
448 ((u32 *)info->pseudo_palette)[regno] = value;
449 }
450 BT463_LOAD_ADDR(par, regno);
451 TGA_WRITE_REG(par, BT463_PALETTE << 2, TGA_RAMDAC_SETUP_REG);
452 TGA_WRITE_REG(par, red, TGA_RAMDAC_REG);
453 TGA_WRITE_REG(par, green, TGA_RAMDAC_REG);
454 TGA_WRITE_REG(par, blue, TGA_RAMDAC_REG);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 }
456
457 return 0;
458}
459
460
461/**
462 * tgafb_blank - Optional function. Blanks the display.
463 * @blank_mode: the blank mode we want.
464 * @info: frame buffer structure that represents a single frame buffer
465 */
466static int
467tgafb_blank(int blank, struct fb_info *info)
468{
469 struct tga_par *par = (struct tga_par *) info->par;
470 u32 vhcr, vvcr, vvvr;
471 unsigned long flags;
472
473 local_irq_save(flags);
474
475 vhcr = TGA_READ_REG(par, TGA_HORIZ_REG);
476 vvcr = TGA_READ_REG(par, TGA_VERT_REG);
477 vvvr = TGA_READ_REG(par, TGA_VALID_REG);
478 vvvr &= ~(TGA_VALID_VIDEO | TGA_VALID_BLANK);
479
480 switch (blank) {
481 case FB_BLANK_UNBLANK: /* Unblanking */
482 if (par->vesa_blanked) {
483 TGA_WRITE_REG(par, vhcr & 0xbfffffff, TGA_HORIZ_REG);
484 TGA_WRITE_REG(par, vvcr & 0xbfffffff, TGA_VERT_REG);
485 par->vesa_blanked = 0;
486 }
487 TGA_WRITE_REG(par, vvvr | TGA_VALID_VIDEO, TGA_VALID_REG);
488 break;
489
490 case FB_BLANK_NORMAL: /* Normal blanking */
491 TGA_WRITE_REG(par, vvvr | TGA_VALID_VIDEO | TGA_VALID_BLANK,
492 TGA_VALID_REG);
493 break;
494
495 case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */
496 TGA_WRITE_REG(par, vvcr | 0x40000000, TGA_VERT_REG);
497 TGA_WRITE_REG(par, vvvr | TGA_VALID_BLANK, TGA_VALID_REG);
498 par->vesa_blanked = 1;
499 break;
500
501 case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */
502 TGA_WRITE_REG(par, vhcr | 0x40000000, TGA_HORIZ_REG);
503 TGA_WRITE_REG(par, vvvr | TGA_VALID_BLANK, TGA_VALID_REG);
504 par->vesa_blanked = 1;
505 break;
506
507 case FB_BLANK_POWERDOWN: /* Poweroff */
508 TGA_WRITE_REG(par, vhcr | 0x40000000, TGA_HORIZ_REG);
509 TGA_WRITE_REG(par, vvcr | 0x40000000, TGA_VERT_REG);
510 TGA_WRITE_REG(par, vvvr | TGA_VALID_BLANK, TGA_VALID_REG);
511 par->vesa_blanked = 1;
512 break;
513 }
514
515 local_irq_restore(flags);
516 return 0;
517}
518
519
520/*
521 * Acceleration.
522 */
523
524/**
525 * tgafb_imageblit - REQUIRED function. Can use generic routines if
526 * non acclerated hardware and packed pixel based.
527 * Copies a image from system memory to the screen.
528 *
529 * @info: frame buffer structure that represents a single frame buffer
530 * @image: structure defining the image.
531 */
532static void
533tgafb_imageblit(struct fb_info *info, const struct fb_image *image)
534{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 struct tga_par *par = (struct tga_par *) info->par;
536 u32 fgcolor, bgcolor, dx, dy, width, height, vxres, vyres, pixelmask;
537 unsigned long rincr, line_length, shift, pos, is8bpp;
538 unsigned long i, j;
539 const unsigned char *data;
540 void __iomem *regs_base;
541 void __iomem *fb_base;
542
543 dx = image->dx;
544 dy = image->dy;
545 width = image->width;
546 height = image->height;
547 vxres = info->var.xres_virtual;
548 vyres = info->var.yres_virtual;
549 line_length = info->fix.line_length;
550 rincr = (width + 7) / 8;
551
552 /* Crop the image to the screen. */
553 if (dx > vxres || dy > vyres)
554 return;
555 if (dx + width > vxres)
556 width = vxres - dx;
557 if (dy + height > vyres)
558 height = vyres - dy;
559
560 /* For copies that aren't pixel expansion, there's little we
561 can do better than the generic code. */
562 /* ??? There is a DMA write mode; I wonder if that could be
563 made to pull the data from the image buffer... */
564 if (image->depth > 1) {
565 cfb_imageblit(info, image);
566 return;
567 }
568
569 regs_base = par->tga_regs_base;
570 fb_base = par->tga_fb_base;
571 is8bpp = info->var.bits_per_pixel == 8;
572
573 /* Expand the color values to fill 32-bits. */
574 /* ??? Would be nice to notice colour changes elsewhere, so
575 that we can do this only when necessary. */
576 fgcolor = image->fg_color;
577 bgcolor = image->bg_color;
578 if (is8bpp) {
579 fgcolor |= fgcolor << 8;
580 fgcolor |= fgcolor << 16;
581 bgcolor |= bgcolor << 8;
582 bgcolor |= bgcolor << 16;
583 } else {
584 if (fgcolor < 16)
585 fgcolor = ((u32 *)info->pseudo_palette)[fgcolor];
586 if (bgcolor < 16)
587 bgcolor = ((u32 *)info->pseudo_palette)[bgcolor];
588 }
589 __raw_writel(fgcolor, regs_base + TGA_FOREGROUND_REG);
590 __raw_writel(bgcolor, regs_base + TGA_BACKGROUND_REG);
591
592 /* Acquire proper alignment; set up the PIXELMASK register
593 so that we only write the proper character cell. */
594 pos = dy * line_length;
595 if (is8bpp) {
596 pos += dx;
597 shift = pos & 3;
598 pos &= -4;
599 } else {
600 pos += dx * 4;
601 shift = (pos & 7) >> 2;
602 pos &= -8;
603 }
604
605 data = (const unsigned char *) image->data;
606
607 /* Enable opaque stipple mode. */
608 __raw_writel((is8bpp
609 ? TGA_MODE_SBM_8BPP | TGA_MODE_OPAQUE_STIPPLE
610 : TGA_MODE_SBM_24BPP | TGA_MODE_OPAQUE_STIPPLE),
611 regs_base + TGA_MODE_REG);
612
613 if (width + shift <= 32) {
614 unsigned long bwidth;
615
616 /* Handle common case of imaging a single character, in
617 a font less than 32 pixels wide. */
618
619 pixelmask = (1 << width) - 1;
620 pixelmask <<= shift;
621 __raw_writel(pixelmask, regs_base + TGA_PIXELMASK_REG);
622 wmb();
623
624 bwidth = (width + 7) / 8;
625
626 for (i = 0; i < height; ++i) {
627 u32 mask = 0;
628
629 /* The image data is bit big endian; we need
630 little endian. */
631 for (j = 0; j < bwidth; ++j)
Akinobu Mita1c667682006-12-08 02:36:26 -0800632 mask |= bitrev8(data[j]) << (j * 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633
634 __raw_writel(mask << shift, fb_base + pos);
635
636 pos += line_length;
637 data += rincr;
638 }
639 wmb();
640 __raw_writel(0xffffffff, regs_base + TGA_PIXELMASK_REG);
641 } else if (shift == 0) {
642 unsigned long pos0 = pos;
643 const unsigned char *data0 = data;
644 unsigned long bincr = (is8bpp ? 8 : 8*4);
645 unsigned long bwidth;
646
647 /* Handle another common case in which accel_putcs
648 generates a large bitmap, which happens to be aligned.
649 Allow the tail to be misaligned. This case is
650 interesting because we've not got to hold partial
651 bytes across the words being written. */
652
653 wmb();
654
655 bwidth = (width / 8) & -4;
656 for (i = 0; i < height; ++i) {
657 for (j = 0; j < bwidth; j += 4) {
658 u32 mask = 0;
Akinobu Mita1c667682006-12-08 02:36:26 -0800659 mask |= bitrev8(data[j+0]) << (0 * 8);
660 mask |= bitrev8(data[j+1]) << (1 * 8);
661 mask |= bitrev8(data[j+2]) << (2 * 8);
662 mask |= bitrev8(data[j+3]) << (3 * 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 __raw_writel(mask, fb_base + pos + j*bincr);
664 }
665 pos += line_length;
666 data += rincr;
667 }
668 wmb();
669
670 pixelmask = (1ul << (width & 31)) - 1;
671 if (pixelmask) {
672 __raw_writel(pixelmask, regs_base + TGA_PIXELMASK_REG);
673 wmb();
674
675 pos = pos0 + bwidth*bincr;
676 data = data0 + bwidth;
677 bwidth = ((width & 31) + 7) / 8;
678
679 for (i = 0; i < height; ++i) {
680 u32 mask = 0;
681 for (j = 0; j < bwidth; ++j)
Akinobu Mita1c667682006-12-08 02:36:26 -0800682 mask |= bitrev8(data[j]) << (j * 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 __raw_writel(mask, fb_base + pos);
684 pos += line_length;
685 data += rincr;
686 }
687 wmb();
688 __raw_writel(0xffffffff, regs_base + TGA_PIXELMASK_REG);
689 }
690 } else {
691 unsigned long pos0 = pos;
692 const unsigned char *data0 = data;
693 unsigned long bincr = (is8bpp ? 8 : 8*4);
694 unsigned long bwidth;
695
696 /* Finally, handle the generic case of misaligned start.
697 Here we split the write into 16-bit spans. This allows
698 us to use only one pixel mask, instead of four as would
699 be required by writing 24-bit spans. */
700
701 pixelmask = 0xffff << shift;
702 __raw_writel(pixelmask, regs_base + TGA_PIXELMASK_REG);
703 wmb();
704
705 bwidth = (width / 8) & -2;
706 for (i = 0; i < height; ++i) {
707 for (j = 0; j < bwidth; j += 2) {
708 u32 mask = 0;
Akinobu Mita1c667682006-12-08 02:36:26 -0800709 mask |= bitrev8(data[j+0]) << (0 * 8);
710 mask |= bitrev8(data[j+1]) << (1 * 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 mask <<= shift;
712 __raw_writel(mask, fb_base + pos + j*bincr);
713 }
714 pos += line_length;
715 data += rincr;
716 }
717 wmb();
718
719 pixelmask = ((1ul << (width & 15)) - 1) << shift;
720 if (pixelmask) {
721 __raw_writel(pixelmask, regs_base + TGA_PIXELMASK_REG);
722 wmb();
723
724 pos = pos0 + bwidth*bincr;
725 data = data0 + bwidth;
726 bwidth = (width & 15) > 8;
727
728 for (i = 0; i < height; ++i) {
Akinobu Mita1c667682006-12-08 02:36:26 -0800729 u32 mask = bitrev8(data[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 if (bwidth)
Akinobu Mita1c667682006-12-08 02:36:26 -0800731 mask |= bitrev8(data[1]) << 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 mask <<= shift;
733 __raw_writel(mask, fb_base + pos);
734 pos += line_length;
735 data += rincr;
736 }
737 wmb();
738 }
739 __raw_writel(0xffffffff, regs_base + TGA_PIXELMASK_REG);
740 }
741
742 /* Disable opaque stipple mode. */
743 __raw_writel((is8bpp
744 ? TGA_MODE_SBM_8BPP | TGA_MODE_SIMPLE
745 : TGA_MODE_SBM_24BPP | TGA_MODE_SIMPLE),
746 regs_base + TGA_MODE_REG);
747}
748
749/**
750 * tgafb_fillrect - REQUIRED function. Can use generic routines if
751 * non acclerated hardware and packed pixel based.
752 * Draws a rectangle on the screen.
753 *
754 * @info: frame buffer structure that represents a single frame buffer
755 * @rect: structure defining the rectagle and operation.
756 */
757static void
758tgafb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
759{
760 struct tga_par *par = (struct tga_par *) info->par;
761 int is8bpp = info->var.bits_per_pixel == 8;
762 u32 dx, dy, width, height, vxres, vyres, color;
763 unsigned long pos, align, line_length, i, j;
764 void __iomem *regs_base;
765 void __iomem *fb_base;
766
767 dx = rect->dx;
768 dy = rect->dy;
769 width = rect->width;
770 height = rect->height;
771 vxres = info->var.xres_virtual;
772 vyres = info->var.yres_virtual;
773 line_length = info->fix.line_length;
774 regs_base = par->tga_regs_base;
775 fb_base = par->tga_fb_base;
776
777 /* Crop the rectangle to the screen. */
778 if (dx > vxres || dy > vyres || !width || !height)
779 return;
780 if (dx + width > vxres)
781 width = vxres - dx;
782 if (dy + height > vyres)
783 height = vyres - dy;
784
785 pos = dy * line_length + dx * (is8bpp ? 1 : 4);
786
787 /* ??? We could implement ROP_XOR with opaque fill mode
788 and a RasterOp setting of GXxor, but as far as I can
789 tell, this mode is not actually used in the kernel.
790 Thus I am ignoring it for now. */
791 if (rect->rop != ROP_COPY) {
792 cfb_fillrect(info, rect);
793 return;
794 }
795
796 /* Expand the color value to fill 8 pixels. */
797 color = rect->color;
798 if (is8bpp) {
799 color |= color << 8;
800 color |= color << 16;
801 __raw_writel(color, regs_base + TGA_BLOCK_COLOR0_REG);
802 __raw_writel(color, regs_base + TGA_BLOCK_COLOR1_REG);
803 } else {
804 if (color < 16)
805 color = ((u32 *)info->pseudo_palette)[color];
806 __raw_writel(color, regs_base + TGA_BLOCK_COLOR0_REG);
807 __raw_writel(color, regs_base + TGA_BLOCK_COLOR1_REG);
808 __raw_writel(color, regs_base + TGA_BLOCK_COLOR2_REG);
809 __raw_writel(color, regs_base + TGA_BLOCK_COLOR3_REG);
810 __raw_writel(color, regs_base + TGA_BLOCK_COLOR4_REG);
811 __raw_writel(color, regs_base + TGA_BLOCK_COLOR5_REG);
812 __raw_writel(color, regs_base + TGA_BLOCK_COLOR6_REG);
813 __raw_writel(color, regs_base + TGA_BLOCK_COLOR7_REG);
814 }
815
816 /* The DATA register holds the fill mask for block fill mode.
817 Since we're not stippling, this is all ones. */
818 __raw_writel(0xffffffff, regs_base + TGA_DATA_REG);
819
820 /* Enable block fill mode. */
821 __raw_writel((is8bpp
822 ? TGA_MODE_SBM_8BPP | TGA_MODE_BLOCK_FILL
823 : TGA_MODE_SBM_24BPP | TGA_MODE_BLOCK_FILL),
824 regs_base + TGA_MODE_REG);
825 wmb();
826
827 /* We can fill 2k pixels per operation. Notice blocks that fit
828 the width of the screen so that we can take advantage of this
829 and fill more than one line per write. */
830 if (width == line_length)
831 width *= height, height = 1;
832
833 /* The write into the frame buffer must be aligned to 4 bytes,
834 but we are allowed to encode the offset within the word in
835 the data word written. */
836 align = (pos & 3) << 16;
837 pos &= -4;
838
839 if (width <= 2048) {
840 u32 data;
841
842 data = (width - 1) | align;
843
844 for (i = 0; i < height; ++i) {
845 __raw_writel(data, fb_base + pos);
846 pos += line_length;
847 }
848 } else {
849 unsigned long Bpp = (is8bpp ? 1 : 4);
850 unsigned long nwidth = width & -2048;
851 u32 fdata, ldata;
852
853 fdata = (2048 - 1) | align;
854 ldata = ((width & 2047) - 1) | align;
855
856 for (i = 0; i < height; ++i) {
857 for (j = 0; j < nwidth; j += 2048)
858 __raw_writel(fdata, fb_base + pos + j*Bpp);
859 if (j < width)
860 __raw_writel(ldata, fb_base + pos + j*Bpp);
861 pos += line_length;
862 }
863 }
864 wmb();
865
866 /* Disable block fill mode. */
867 __raw_writel((is8bpp
868 ? TGA_MODE_SBM_8BPP | TGA_MODE_SIMPLE
869 : TGA_MODE_SBM_24BPP | TGA_MODE_SIMPLE),
870 regs_base + TGA_MODE_REG);
871}
872
873/**
874 * tgafb_copyarea - REQUIRED function. Can use generic routines if
875 * non acclerated hardware and packed pixel based.
876 * Copies on area of the screen to another area.
877 *
878 * @info: frame buffer structure that represents a single frame buffer
879 * @area: structure defining the source and destination.
880 */
881
882/* Handle the special case of copying entire lines, e.g. during scrolling.
883 We can avoid a lot of needless computation in this case. In the 8bpp
884 case we need to use the COPY64 registers instead of mask writes into
885 the frame buffer to achieve maximum performance. */
886
887static inline void
888copyarea_line_8bpp(struct fb_info *info, u32 dy, u32 sy,
889 u32 height, u32 width)
890{
891 struct tga_par *par = (struct tga_par *) info->par;
892 void __iomem *tga_regs = par->tga_regs_base;
893 unsigned long dpos, spos, i, n64;
894
895 /* Set up the MODE and PIXELSHIFT registers. */
896 __raw_writel(TGA_MODE_SBM_8BPP | TGA_MODE_COPY, tga_regs+TGA_MODE_REG);
897 __raw_writel(0, tga_regs+TGA_PIXELSHIFT_REG);
898 wmb();
899
900 n64 = (height * width) / 64;
901
Maciej W. Rozycki36f71402007-02-12 00:54:53 -0800902 if (sy < dy) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 spos = (sy + height) * width;
904 dpos = (dy + height) * width;
905
906 for (i = 0; i < n64; ++i) {
907 spos -= 64;
908 dpos -= 64;
909 __raw_writel(spos, tga_regs+TGA_COPY64_SRC);
910 wmb();
911 __raw_writel(dpos, tga_regs+TGA_COPY64_DST);
912 wmb();
913 }
914 } else {
915 spos = sy * width;
916 dpos = dy * width;
917
918 for (i = 0; i < n64; ++i) {
919 __raw_writel(spos, tga_regs+TGA_COPY64_SRC);
920 wmb();
921 __raw_writel(dpos, tga_regs+TGA_COPY64_DST);
922 wmb();
923 spos += 64;
924 dpos += 64;
925 }
926 }
927
928 /* Reset the MODE register to normal. */
929 __raw_writel(TGA_MODE_SBM_8BPP|TGA_MODE_SIMPLE, tga_regs+TGA_MODE_REG);
930}
931
932static inline void
933copyarea_line_32bpp(struct fb_info *info, u32 dy, u32 sy,
934 u32 height, u32 width)
935{
936 struct tga_par *par = (struct tga_par *) info->par;
937 void __iomem *tga_regs = par->tga_regs_base;
938 void __iomem *tga_fb = par->tga_fb_base;
939 void __iomem *src;
940 void __iomem *dst;
941 unsigned long i, n16;
942
943 /* Set up the MODE and PIXELSHIFT registers. */
944 __raw_writel(TGA_MODE_SBM_24BPP | TGA_MODE_COPY, tga_regs+TGA_MODE_REG);
945 __raw_writel(0, tga_regs+TGA_PIXELSHIFT_REG);
946 wmb();
947
948 n16 = (height * width) / 16;
949
Maciej W. Rozycki36f71402007-02-12 00:54:53 -0800950 if (sy < dy) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951 src = tga_fb + (sy + height) * width * 4;
952 dst = tga_fb + (dy + height) * width * 4;
953
954 for (i = 0; i < n16; ++i) {
955 src -= 64;
956 dst -= 64;
957 __raw_writel(0xffff, src);
958 wmb();
959 __raw_writel(0xffff, dst);
960 wmb();
961 }
962 } else {
963 src = tga_fb + sy * width * 4;
964 dst = tga_fb + dy * width * 4;
965
966 for (i = 0; i < n16; ++i) {
967 __raw_writel(0xffff, src);
968 wmb();
969 __raw_writel(0xffff, dst);
970 wmb();
971 src += 64;
972 dst += 64;
973 }
974 }
975
976 /* Reset the MODE register to normal. */
977 __raw_writel(TGA_MODE_SBM_24BPP|TGA_MODE_SIMPLE, tga_regs+TGA_MODE_REG);
978}
979
980/* The general case of forward copy in 8bpp mode. */
981static inline void
982copyarea_foreward_8bpp(struct fb_info *info, u32 dx, u32 dy, u32 sx, u32 sy,
983 u32 height, u32 width, u32 line_length)
984{
985 struct tga_par *par = (struct tga_par *) info->par;
986 unsigned long i, copied, left;
987 unsigned long dpos, spos, dalign, salign, yincr;
988 u32 smask_first, dmask_first, dmask_last;
989 int pixel_shift, need_prime, need_second;
990 unsigned long n64, n32, xincr_first;
991 void __iomem *tga_regs;
992 void __iomem *tga_fb;
993
994 yincr = line_length;
995 if (dy > sy) {
996 dy += height - 1;
997 sy += height - 1;
998 yincr = -yincr;
999 }
1000
1001 /* Compute the offsets and alignments in the frame buffer.
1002 More than anything else, these control how we do copies. */
1003 dpos = dy * line_length + dx;
1004 spos = sy * line_length + sx;
1005 dalign = dpos & 7;
1006 salign = spos & 7;
1007 dpos &= -8;
1008 spos &= -8;
1009
1010 /* Compute the value for the PIXELSHIFT register. This controls
1011 both non-co-aligned source and destination and copy direction. */
1012 if (dalign >= salign)
1013 pixel_shift = dalign - salign;
1014 else
1015 pixel_shift = 8 - (salign - dalign);
1016
1017 /* Figure out if we need an additional priming step for the
1018 residue register. */
1019 need_prime = (salign > dalign);
1020 if (need_prime)
1021 dpos -= 8;
1022
1023 /* Begin by copying the leading unaligned destination. Copy enough
1024 to make the next destination address 32-byte aligned. */
1025 copied = 32 - (dalign + (dpos & 31));
1026 if (copied == 32)
1027 copied = 0;
1028 xincr_first = (copied + 7) & -8;
1029 smask_first = dmask_first = (1ul << copied) - 1;
1030 smask_first <<= salign;
1031 dmask_first <<= dalign + need_prime*8;
1032 if (need_prime && copied > 24)
1033 copied -= 8;
1034 left = width - copied;
1035
1036 /* Care for small copies. */
1037 if (copied > width) {
1038 u32 t;
1039 t = (1ul << width) - 1;
1040 t <<= dalign + need_prime*8;
1041 dmask_first &= t;
1042 left = 0;
1043 }
1044
1045 /* Attempt to use 64-byte copies. This is only possible if the
1046 source and destination are co-aligned at 64 bytes. */
1047 n64 = need_second = 0;
1048 if ((dpos & 63) == (spos & 63)
1049 && (height == 1 || line_length % 64 == 0)) {
1050 /* We may need a 32-byte copy to ensure 64 byte alignment. */
1051 need_second = (dpos + xincr_first) & 63;
1052 if ((need_second & 32) != need_second)
1053 printk(KERN_ERR "tgafb: need_second wrong\n");
1054 if (left >= need_second + 64) {
1055 left -= need_second;
1056 n64 = left / 64;
1057 left %= 64;
1058 } else
1059 need_second = 0;
1060 }
1061
1062 /* Copy trailing full 32-byte sections. This will be the main
1063 loop if the 64 byte loop can't be used. */
1064 n32 = left / 32;
1065 left %= 32;
1066
1067 /* Copy the trailing unaligned destination. */
1068 dmask_last = (1ul << left) - 1;
1069
1070 tga_regs = par->tga_regs_base;
1071 tga_fb = par->tga_fb_base;
1072
1073 /* Set up the MODE and PIXELSHIFT registers. */
1074 __raw_writel(TGA_MODE_SBM_8BPP|TGA_MODE_COPY, tga_regs+TGA_MODE_REG);
1075 __raw_writel(pixel_shift, tga_regs+TGA_PIXELSHIFT_REG);
1076 wmb();
1077
1078 for (i = 0; i < height; ++i) {
1079 unsigned long j;
1080 void __iomem *sfb;
1081 void __iomem *dfb;
1082
1083 sfb = tga_fb + spos;
1084 dfb = tga_fb + dpos;
1085 if (dmask_first) {
1086 __raw_writel(smask_first, sfb);
1087 wmb();
1088 __raw_writel(dmask_first, dfb);
1089 wmb();
1090 sfb += xincr_first;
1091 dfb += xincr_first;
1092 }
1093
1094 if (need_second) {
1095 __raw_writel(0xffffffff, sfb);
1096 wmb();
1097 __raw_writel(0xffffffff, dfb);
1098 wmb();
1099 sfb += 32;
1100 dfb += 32;
1101 }
1102
1103 if (n64 && (((unsigned long)sfb | (unsigned long)dfb) & 63))
1104 printk(KERN_ERR
1105 "tgafb: misaligned copy64 (s:%p, d:%p)\n",
1106 sfb, dfb);
1107
1108 for (j = 0; j < n64; ++j) {
1109 __raw_writel(sfb - tga_fb, tga_regs+TGA_COPY64_SRC);
1110 wmb();
1111 __raw_writel(dfb - tga_fb, tga_regs+TGA_COPY64_DST);
1112 wmb();
1113 sfb += 64;
1114 dfb += 64;
1115 }
1116
1117 for (j = 0; j < n32; ++j) {
1118 __raw_writel(0xffffffff, sfb);
1119 wmb();
1120 __raw_writel(0xffffffff, dfb);
1121 wmb();
1122 sfb += 32;
1123 dfb += 32;
1124 }
1125
1126 if (dmask_last) {
1127 __raw_writel(0xffffffff, sfb);
1128 wmb();
1129 __raw_writel(dmask_last, dfb);
1130 wmb();
1131 }
1132
1133 spos += yincr;
1134 dpos += yincr;
1135 }
1136
1137 /* Reset the MODE register to normal. */
1138 __raw_writel(TGA_MODE_SBM_8BPP|TGA_MODE_SIMPLE, tga_regs+TGA_MODE_REG);
1139}
1140
1141/* The (almost) general case of backward copy in 8bpp mode. */
1142static inline void
1143copyarea_backward_8bpp(struct fb_info *info, u32 dx, u32 dy, u32 sx, u32 sy,
1144 u32 height, u32 width, u32 line_length,
1145 const struct fb_copyarea *area)
1146{
1147 struct tga_par *par = (struct tga_par *) info->par;
1148 unsigned long i, left, yincr;
1149 unsigned long depos, sepos, dealign, sealign;
1150 u32 mask_first, mask_last;
1151 unsigned long n32;
1152 void __iomem *tga_regs;
1153 void __iomem *tga_fb;
1154
1155 yincr = line_length;
1156 if (dy > sy) {
1157 dy += height - 1;
1158 sy += height - 1;
1159 yincr = -yincr;
1160 }
1161
1162 /* Compute the offsets and alignments in the frame buffer.
1163 More than anything else, these control how we do copies. */
1164 depos = dy * line_length + dx + width;
1165 sepos = sy * line_length + sx + width;
1166 dealign = depos & 7;
1167 sealign = sepos & 7;
1168
1169 /* ??? The documentation appears to be incorrect (or very
1170 misleading) wrt how pixel shifting works in backward copy
1171 mode, i.e. when PIXELSHIFT is negative. I give up for now.
1172 Do handle the common case of co-aligned backward copies,
1173 but frob everything else back on generic code. */
1174 if (dealign != sealign) {
1175 cfb_copyarea(info, area);
1176 return;
1177 }
1178
1179 /* We begin the copy with the trailing pixels of the
1180 unaligned destination. */
1181 mask_first = (1ul << dealign) - 1;
1182 left = width - dealign;
1183
1184 /* Care for small copies. */
1185 if (dealign > width) {
1186 mask_first ^= (1ul << (dealign - width)) - 1;
1187 left = 0;
1188 }
1189
1190 /* Next copy full words at a time. */
1191 n32 = left / 32;
1192 left %= 32;
1193
1194 /* Finally copy the unaligned head of the span. */
1195 mask_last = -1 << (32 - left);
1196
1197 tga_regs = par->tga_regs_base;
1198 tga_fb = par->tga_fb_base;
1199
1200 /* Set up the MODE and PIXELSHIFT registers. */
1201 __raw_writel(TGA_MODE_SBM_8BPP|TGA_MODE_COPY, tga_regs+TGA_MODE_REG);
1202 __raw_writel(0, tga_regs+TGA_PIXELSHIFT_REG);
1203 wmb();
1204
1205 for (i = 0; i < height; ++i) {
1206 unsigned long j;
1207 void __iomem *sfb;
1208 void __iomem *dfb;
1209
1210 sfb = tga_fb + sepos;
1211 dfb = tga_fb + depos;
1212 if (mask_first) {
1213 __raw_writel(mask_first, sfb);
1214 wmb();
1215 __raw_writel(mask_first, dfb);
1216 wmb();
1217 }
1218
1219 for (j = 0; j < n32; ++j) {
1220 sfb -= 32;
1221 dfb -= 32;
1222 __raw_writel(0xffffffff, sfb);
1223 wmb();
1224 __raw_writel(0xffffffff, dfb);
1225 wmb();
1226 }
1227
1228 if (mask_last) {
1229 sfb -= 32;
1230 dfb -= 32;
1231 __raw_writel(mask_last, sfb);
1232 wmb();
1233 __raw_writel(mask_last, dfb);
1234 wmb();
1235 }
1236
1237 sepos += yincr;
1238 depos += yincr;
1239 }
1240
1241 /* Reset the MODE register to normal. */
1242 __raw_writel(TGA_MODE_SBM_8BPP|TGA_MODE_SIMPLE, tga_regs+TGA_MODE_REG);
1243}
1244
1245static void
1246tgafb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
1247{
1248 unsigned long dx, dy, width, height, sx, sy, vxres, vyres;
1249 unsigned long line_length, bpp;
1250
1251 dx = area->dx;
1252 dy = area->dy;
1253 width = area->width;
1254 height = area->height;
1255 sx = area->sx;
1256 sy = area->sy;
1257 vxres = info->var.xres_virtual;
1258 vyres = info->var.yres_virtual;
1259 line_length = info->fix.line_length;
1260
1261 /* The top left corners must be in the virtual screen. */
1262 if (dx > vxres || sx > vxres || dy > vyres || sy > vyres)
1263 return;
1264
1265 /* Clip the destination. */
1266 if (dx + width > vxres)
1267 width = vxres - dx;
1268 if (dy + height > vyres)
1269 height = vyres - dy;
1270
1271 /* The source must be completely inside the virtual screen. */
1272 if (sx + width > vxres || sy + height > vyres)
1273 return;
1274
1275 bpp = info->var.bits_per_pixel;
1276
1277 /* Detect copies of the entire line. */
1278 if (width * (bpp >> 3) == line_length) {
1279 if (bpp == 8)
1280 copyarea_line_8bpp(info, dy, sy, height, width);
1281 else
1282 copyarea_line_32bpp(info, dy, sy, height, width);
1283 }
1284
1285 /* ??? The documentation is unclear to me exactly how the pixelshift
1286 register works in 32bpp mode. Since I don't have hardware to test,
1287 give up for now and fall back on the generic routines. */
1288 else if (bpp == 32)
1289 cfb_copyarea(info, area);
1290
1291 /* Detect overlapping source and destination that requires
1292 a backward copy. */
1293 else if (dy == sy && dx > sx && dx < sx + width)
1294 copyarea_backward_8bpp(info, dx, dy, sx, sy, height,
1295 width, line_length, area);
1296 else
1297 copyarea_foreward_8bpp(info, dx, dy, sx, sy, height,
1298 width, line_length);
1299}
1300
1301
1302/*
1303 * Initialisation
1304 */
1305
1306static void
1307tgafb_init_fix(struct fb_info *info)
1308{
1309 struct tga_par *par = (struct tga_par *)info->par;
1310 u8 tga_type = par->tga_type;
1311 const char *tga_type_name;
1312
1313 switch (tga_type) {
1314 case TGA_TYPE_8PLANE:
1315 tga_type_name = "Digital ZLXp-E1";
1316 break;
1317 case TGA_TYPE_24PLANE:
1318 tga_type_name = "Digital ZLXp-E2";
1319 break;
1320 case TGA_TYPE_24PLUSZ:
1321 tga_type_name = "Digital ZLXp-E3";
1322 break;
1323 default:
1324 tga_type_name = "Unknown";
1325 break;
1326 }
1327
1328 strlcpy(info->fix.id, tga_type_name, sizeof(info->fix.id));
1329
1330 info->fix.type = FB_TYPE_PACKED_PIXELS;
1331 info->fix.type_aux = 0;
1332 info->fix.visual = (tga_type == TGA_TYPE_8PLANE
1333 ? FB_VISUAL_PSEUDOCOLOR
Maciej W. Rozyckibe601182007-02-12 00:54:54 -08001334 : FB_VISUAL_DIRECTCOLOR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335
1336 info->fix.line_length = par->xres * (par->bits_per_pixel >> 3);
1337 info->fix.smem_start = (size_t) par->tga_fb_base;
1338 info->fix.smem_len = info->fix.line_length * par->yres;
1339 info->fix.mmio_start = (size_t) par->tga_regs_base;
1340 info->fix.mmio_len = 512;
1341
1342 info->fix.xpanstep = 0;
1343 info->fix.ypanstep = 0;
1344 info->fix.ywrapstep = 0;
1345
1346 info->fix.accel = FB_ACCEL_DEC_TGA;
1347}
1348
1349static __devinit int
1350tgafb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
1351{
1352 static unsigned int const fb_offset_presets[4] = {
1353 TGA_8PLANE_FB_OFFSET,
1354 TGA_24PLANE_FB_OFFSET,
1355 0xffffffff,
1356 TGA_24PLUSZ_FB_OFFSET
1357 };
1358
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359 void __iomem *mem_base;
1360 unsigned long bar0_start, bar0_len;
Maciej W. Rozyckiee9a25e2007-02-12 00:54:52 -08001361 struct fb_info *info;
1362 struct tga_par *par;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 u8 tga_type;
1364 int ret;
1365
1366 /* Enable device in PCI config. */
1367 if (pci_enable_device(pdev)) {
1368 printk(KERN_ERR "tgafb: Cannot enable PCI device\n");
1369 return -ENODEV;
1370 }
1371
1372 /* Allocate the fb and par structures. */
Maciej W. Rozyckiee9a25e2007-02-12 00:54:52 -08001373 info = framebuffer_alloc(sizeof(struct tga_par), &pdev->dev);
1374 if (!info) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375 printk(KERN_ERR "tgafb: Cannot allocate memory\n");
1376 return -ENOMEM;
1377 }
Maciej W. Rozyckiee9a25e2007-02-12 00:54:52 -08001378
1379 par = info->par;
1380 pci_set_drvdata(pdev, info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381
1382 /* Request the mem regions. */
1383 bar0_start = pci_resource_start(pdev, 0);
1384 bar0_len = pci_resource_len(pdev, 0);
1385 ret = -ENODEV;
1386 if (!request_mem_region (bar0_start, bar0_len, "tgafb")) {
1387 printk(KERN_ERR "tgafb: cannot reserve FB region\n");
1388 goto err0;
1389 }
1390
1391 /* Map the framebuffer. */
1392 mem_base = ioremap(bar0_start, bar0_len);
1393 if (!mem_base) {
1394 printk(KERN_ERR "tgafb: Cannot map MMIO\n");
1395 goto err1;
1396 }
1397
1398 /* Grab info about the card. */
1399 tga_type = (readl(mem_base) >> 12) & 0x0f;
Maciej W. Rozyckiee9a25e2007-02-12 00:54:52 -08001400 par->pdev = pdev;
1401 par->tga_mem_base = mem_base;
1402 par->tga_fb_base = mem_base + fb_offset_presets[tga_type];
1403 par->tga_regs_base = mem_base + TGA_REGS_OFFSET;
1404 par->tga_type = tga_type;
1405 pci_read_config_byte(pdev, PCI_REVISION_ID, &par->tga_chip_rev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406
1407 /* Setup framebuffer. */
Maciej W. Rozyckiee9a25e2007-02-12 00:54:52 -08001408 info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_COPYAREA |
1409 FBINFO_HWACCEL_IMAGEBLIT | FBINFO_HWACCEL_FILLRECT;
1410 info->fbops = &tgafb_ops;
1411 info->screen_base = par->tga_fb_base;
1412 info->pseudo_palette = (void *)(par + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413
1414 /* This should give a reasonable default video mode. */
1415
Maciej W. Rozyckiee9a25e2007-02-12 00:54:52 -08001416 ret = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417 tga_type == TGA_TYPE_8PLANE ? 8 : 32);
1418 if (ret == 0 || ret == 4) {
1419 printk(KERN_ERR "tgafb: Could not find valid video mode\n");
1420 ret = -EINVAL;
1421 goto err1;
1422 }
1423
Maciej W. Rozyckiee9a25e2007-02-12 00:54:52 -08001424 if (fb_alloc_cmap(&info->cmap, 256, 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425 printk(KERN_ERR "tgafb: Could not allocate color map\n");
1426 ret = -ENOMEM;
1427 goto err1;
1428 }
1429
Maciej W. Rozyckiee9a25e2007-02-12 00:54:52 -08001430 tgafb_set_par(info);
1431 tgafb_init_fix(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432
Maciej W. Rozyckiee9a25e2007-02-12 00:54:52 -08001433 if (register_framebuffer(info) < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434 printk(KERN_ERR "tgafb: Could not register framebuffer\n");
1435 ret = -EINVAL;
1436 goto err1;
1437 }
1438
1439 printk(KERN_INFO "tgafb: DC21030 [TGA] detected, rev=0x%02x\n",
Maciej W. Rozyckiee9a25e2007-02-12 00:54:52 -08001440 par->tga_chip_rev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441 printk(KERN_INFO "tgafb: at PCI bus %d, device %d, function %d\n",
1442 pdev->bus->number, PCI_SLOT(pdev->devfn),
1443 PCI_FUNC(pdev->devfn));
1444 printk(KERN_INFO "fb%d: %s frame buffer device at 0x%lx\n",
Maciej W. Rozyckiee9a25e2007-02-12 00:54:52 -08001445 info->node, info->fix.id, bar0_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446
1447 return 0;
1448
1449 err1:
Amol Lade4bf0512006-12-08 02:40:04 -08001450 if (mem_base)
1451 iounmap(mem_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452 release_mem_region(bar0_start, bar0_len);
1453 err0:
Maciej W. Rozyckiee9a25e2007-02-12 00:54:52 -08001454 framebuffer_release(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455 return ret;
1456}
1457
Maciej W. Rozycki1b2f2fe2007-02-12 00:54:56 -08001458static void __devexit
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459tgafb_pci_unregister(struct pci_dev *pdev)
1460{
1461 struct fb_info *info = pci_get_drvdata(pdev);
1462 struct tga_par *par = info->par;
1463
1464 if (!info)
1465 return;
1466 unregister_framebuffer(info);
Maciej W. Rozyckiee9a25e2007-02-12 00:54:52 -08001467 fb_dealloc_cmap(&info->cmap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468 iounmap(par->tga_mem_base);
1469 release_mem_region(pci_resource_start(pdev, 0),
1470 pci_resource_len(pdev, 0));
Maciej W. Rozyckiee9a25e2007-02-12 00:54:52 -08001471 framebuffer_release(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472}
1473
Maciej W. Rozycki1b2f2fe2007-02-12 00:54:56 -08001474static void __devexit
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475tgafb_exit(void)
1476{
1477 pci_unregister_driver(&tgafb_driver);
1478}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479
1480#ifndef MODULE
Maciej W. Rozycki1b2f2fe2007-02-12 00:54:56 -08001481static int __devinit
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482tgafb_setup(char *arg)
1483{
1484 char *this_opt;
1485
1486 if (arg && *arg) {
1487 while ((this_opt = strsep(&arg, ","))) {
1488 if (!*this_opt)
1489 continue;
1490 if (!strncmp(this_opt, "mode:", 5))
1491 mode_option = this_opt+5;
1492 else
1493 printk(KERN_ERR
1494 "tgafb: unknown parameter %s\n",
1495 this_opt);
1496 }
1497 }
1498
1499 return 0;
1500}
1501#endif /* !MODULE */
1502
Maciej W. Rozycki1b2f2fe2007-02-12 00:54:56 -08001503static int __devinit
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504tgafb_init(void)
1505{
1506#ifndef MODULE
1507 char *option = NULL;
1508
1509 if (fb_get_options("tgafb", &option))
1510 return -ENODEV;
1511 tgafb_setup(option);
1512#endif
1513 return pci_register_driver(&tgafb_driver);
1514}
1515
1516/*
1517 * Modularisation
1518 */
1519
1520module_init(tgafb_init);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521module_exit(tgafb_exit);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522
1523MODULE_DESCRIPTION("framebuffer driver for TGA chipset");
1524MODULE_LICENSE("GPL");