diff options
Diffstat (limited to 'drivers/video/tgafb.c')
-rw-r--r-- | drivers/video/tgafb.c | 425 |
1 files changed, 341 insertions, 84 deletions
diff --git a/drivers/video/tgafb.c b/drivers/video/tgafb.c index 7478d0e3e211..f0fde6ea7c36 100644 --- a/drivers/video/tgafb.c +++ b/drivers/video/tgafb.c | |||
@@ -5,27 +5,45 @@ | |||
5 | * Copyright (C) 1997 Geert Uytterhoeven | 5 | * Copyright (C) 1997 Geert Uytterhoeven |
6 | * Copyright (C) 1999,2000 Martin Lucina, Tom Zerucha | 6 | * Copyright (C) 1999,2000 Martin Lucina, Tom Zerucha |
7 | * Copyright (C) 2002 Richard Henderson | 7 | * Copyright (C) 2002 Richard Henderson |
8 | * Copyright (C) 2006 Maciej W. Rozycki | ||
8 | * | 9 | * |
9 | * This file is subject to the terms and conditions of the GNU General Public | 10 | * 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 | * License. See the file COPYING in the main directory of this archive for |
11 | * more details. | 12 | * more details. |
12 | */ | 13 | */ |
13 | 14 | ||
14 | #include <linux/module.h> | 15 | #include <linux/bitrev.h> |
15 | #include <linux/kernel.h> | ||
16 | #include <linux/errno.h> | ||
17 | #include <linux/string.h> | ||
18 | #include <linux/mm.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/delay.h> | 16 | #include <linux/delay.h> |
21 | #include <linux/init.h> | 17 | #include <linux/device.h> |
18 | #include <linux/errno.h> | ||
22 | #include <linux/fb.h> | 19 | #include <linux/fb.h> |
20 | #include <linux/init.h> | ||
21 | #include <linux/ioport.h> | ||
22 | #include <linux/kernel.h> | ||
23 | #include <linux/mm.h> | ||
24 | #include <linux/module.h> | ||
23 | #include <linux/pci.h> | 25 | #include <linux/pci.h> |
24 | #include <linux/selection.h> | 26 | #include <linux/selection.h> |
25 | #include <linux/bitrev.h> | 27 | #include <linux/slab.h> |
28 | #include <linux/string.h> | ||
29 | #include <linux/tc.h> | ||
30 | |||
26 | #include <asm/io.h> | 31 | #include <asm/io.h> |
32 | |||
27 | #include <video/tgafb.h> | 33 | #include <video/tgafb.h> |
28 | 34 | ||
35 | #ifdef CONFIG_PCI | ||
36 | #define TGA_BUS_PCI(dev) (dev->bus == &pci_bus_type) | ||
37 | #else | ||
38 | #define TGA_BUS_PCI(dev) 0 | ||
39 | #endif | ||
40 | |||
41 | #ifdef CONFIG_TC | ||
42 | #define TGA_BUS_TC(dev) (dev->bus == &tc_bus_type) | ||
43 | #else | ||
44 | #define TGA_BUS_TC(dev) 0 | ||
45 | #endif | ||
46 | |||
29 | /* | 47 | /* |
30 | * Local functions. | 48 | * Local functions. |
31 | */ | 49 | */ |
@@ -41,14 +59,19 @@ static void tgafb_init_fix(struct fb_info *); | |||
41 | static void tgafb_imageblit(struct fb_info *, const struct fb_image *); | 59 | static void tgafb_imageblit(struct fb_info *, const struct fb_image *); |
42 | static void tgafb_fillrect(struct fb_info *, const struct fb_fillrect *); | 60 | static void tgafb_fillrect(struct fb_info *, const struct fb_fillrect *); |
43 | static void tgafb_copyarea(struct fb_info *, const struct fb_copyarea *); | 61 | static void tgafb_copyarea(struct fb_info *, const struct fb_copyarea *); |
62 | static int tgafb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info); | ||
44 | 63 | ||
45 | static int __devinit tgafb_pci_register(struct pci_dev *, | 64 | static int __devinit tgafb_register(struct device *dev); |
46 | const struct pci_device_id *); | 65 | static void __devexit tgafb_unregister(struct device *dev); |
47 | static void __devexit tgafb_pci_unregister(struct pci_dev *); | ||
48 | 66 | ||
49 | static const char *mode_option = "640x480@60"; | 67 | static const char *mode_option; |
68 | static const char *mode_option_pci = "640x480@60"; | ||
69 | static const char *mode_option_tc = "1280x1024@72"; | ||
50 | 70 | ||
51 | 71 | ||
72 | static struct pci_driver tgafb_pci_driver; | ||
73 | static struct tc_driver tgafb_tc_driver; | ||
74 | |||
52 | /* | 75 | /* |
53 | * Frame buffer operations | 76 | * Frame buffer operations |
54 | */ | 77 | */ |
@@ -59,15 +82,20 @@ static struct fb_ops tgafb_ops = { | |||
59 | .fb_set_par = tgafb_set_par, | 82 | .fb_set_par = tgafb_set_par, |
60 | .fb_setcolreg = tgafb_setcolreg, | 83 | .fb_setcolreg = tgafb_setcolreg, |
61 | .fb_blank = tgafb_blank, | 84 | .fb_blank = tgafb_blank, |
85 | .fb_pan_display = tgafb_pan_display, | ||
62 | .fb_fillrect = tgafb_fillrect, | 86 | .fb_fillrect = tgafb_fillrect, |
63 | .fb_copyarea = tgafb_copyarea, | 87 | .fb_copyarea = tgafb_copyarea, |
64 | .fb_imageblit = tgafb_imageblit, | 88 | .fb_imageblit = tgafb_imageblit, |
65 | }; | 89 | }; |
66 | 90 | ||
67 | 91 | ||
92 | #ifdef CONFIG_PCI | ||
68 | /* | 93 | /* |
69 | * PCI registration operations | 94 | * PCI registration operations |
70 | */ | 95 | */ |
96 | static int __devinit tgafb_pci_register(struct pci_dev *, | ||
97 | const struct pci_device_id *); | ||
98 | static void __devexit tgafb_pci_unregister(struct pci_dev *); | ||
71 | 99 | ||
72 | static struct pci_device_id const tgafb_pci_table[] = { | 100 | static struct pci_device_id const tgafb_pci_table[] = { |
73 | { PCI_DEVICE(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TGA) }, | 101 | { PCI_DEVICE(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TGA) }, |
@@ -75,13 +103,68 @@ static struct pci_device_id const tgafb_pci_table[] = { | |||
75 | }; | 103 | }; |
76 | MODULE_DEVICE_TABLE(pci, tgafb_pci_table); | 104 | MODULE_DEVICE_TABLE(pci, tgafb_pci_table); |
77 | 105 | ||
78 | static struct pci_driver tgafb_driver = { | 106 | static struct pci_driver tgafb_pci_driver = { |
79 | .name = "tgafb", | 107 | .name = "tgafb", |
80 | .id_table = tgafb_pci_table, | 108 | .id_table = tgafb_pci_table, |
81 | .probe = tgafb_pci_register, | 109 | .probe = tgafb_pci_register, |
82 | .remove = __devexit_p(tgafb_pci_unregister), | 110 | .remove = __devexit_p(tgafb_pci_unregister), |
83 | }; | 111 | }; |
84 | 112 | ||
113 | static int __devinit | ||
114 | tgafb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent) | ||
115 | { | ||
116 | return tgafb_register(&pdev->dev); | ||
117 | } | ||
118 | |||
119 | static void __devexit | ||
120 | tgafb_pci_unregister(struct pci_dev *pdev) | ||
121 | { | ||
122 | tgafb_unregister(&pdev->dev); | ||
123 | } | ||
124 | #endif /* CONFIG_PCI */ | ||
125 | |||
126 | #ifdef CONFIG_TC | ||
127 | /* | ||
128 | * TC registration operations | ||
129 | */ | ||
130 | static int __devinit tgafb_tc_register(struct device *); | ||
131 | static int __devexit tgafb_tc_unregister(struct device *); | ||
132 | |||
133 | static struct tc_device_id const tgafb_tc_table[] = { | ||
134 | { "DEC ", "PMAGD-AA" }, | ||
135 | { "DEC ", "PMAGD " }, | ||
136 | { } | ||
137 | }; | ||
138 | MODULE_DEVICE_TABLE(tc, tgafb_tc_table); | ||
139 | |||
140 | static struct tc_driver tgafb_tc_driver = { | ||
141 | .id_table = tgafb_tc_table, | ||
142 | .driver = { | ||
143 | .name = "tgafb", | ||
144 | .bus = &tc_bus_type, | ||
145 | .probe = tgafb_tc_register, | ||
146 | .remove = __devexit_p(tgafb_tc_unregister), | ||
147 | }, | ||
148 | }; | ||
149 | |||
150 | static int __devinit | ||
151 | tgafb_tc_register(struct device *dev) | ||
152 | { | ||
153 | int status = tgafb_register(dev); | ||
154 | if (!status) | ||
155 | get_device(dev); | ||
156 | return status; | ||
157 | } | ||
158 | |||
159 | static int __devexit | ||
160 | tgafb_tc_unregister(struct device *dev) | ||
161 | { | ||
162 | put_device(dev); | ||
163 | tgafb_unregister(dev); | ||
164 | return 0; | ||
165 | } | ||
166 | #endif /* CONFIG_TC */ | ||
167 | |||
85 | 168 | ||
86 | /** | 169 | /** |
87 | * tgafb_check_var - Optional function. Validates a var passed in. | 170 | * tgafb_check_var - Optional function. Validates a var passed in. |
@@ -132,10 +215,10 @@ static int | |||
132 | tgafb_set_par(struct fb_info *info) | 215 | tgafb_set_par(struct fb_info *info) |
133 | { | 216 | { |
134 | static unsigned int const deep_presets[4] = { | 217 | static unsigned int const deep_presets[4] = { |
135 | 0x00014000, | 218 | 0x00004000, |
136 | 0x0001440d, | 219 | 0x0000440d, |
137 | 0xffffffff, | 220 | 0xffffffff, |
138 | 0x0001441d | 221 | 0x0000441d |
139 | }; | 222 | }; |
140 | static unsigned int const rasterop_presets[4] = { | 223 | static unsigned int const rasterop_presets[4] = { |
141 | 0x00000003, | 224 | 0x00000003, |
@@ -157,6 +240,8 @@ tgafb_set_par(struct fb_info *info) | |||
157 | }; | 240 | }; |
158 | 241 | ||
159 | struct tga_par *par = (struct tga_par *) info->par; | 242 | struct tga_par *par = (struct tga_par *) info->par; |
243 | int tga_bus_pci = TGA_BUS_PCI(par->dev); | ||
244 | int tga_bus_tc = TGA_BUS_TC(par->dev); | ||
160 | u32 htimings, vtimings, pll_freq; | 245 | u32 htimings, vtimings, pll_freq; |
161 | u8 tga_type; | 246 | u8 tga_type; |
162 | int i; | 247 | int i; |
@@ -221,7 +306,7 @@ tgafb_set_par(struct fb_info *info) | |||
221 | TGA_WRITE_REG(par, vtimings, TGA_VERT_REG); | 306 | TGA_WRITE_REG(par, vtimings, TGA_VERT_REG); |
222 | 307 | ||
223 | /* Initalise RAMDAC. */ | 308 | /* Initalise RAMDAC. */ |
224 | if (tga_type == TGA_TYPE_8PLANE) { | 309 | if (tga_type == TGA_TYPE_8PLANE && tga_bus_pci) { |
225 | 310 | ||
226 | /* Init BT485 RAMDAC registers. */ | 311 | /* Init BT485 RAMDAC registers. */ |
227 | BT485_WRITE(par, 0xa2 | (par->sync_on_green ? 0x8 : 0x0), | 312 | BT485_WRITE(par, 0xa2 | (par->sync_on_green ? 0x8 : 0x0), |
@@ -236,21 +321,7 @@ tgafb_set_par(struct fb_info *info) | |||
236 | BT485_WRITE(par, 0x00, BT485_ADDR_PAL_WRITE); | 321 | BT485_WRITE(par, 0x00, BT485_ADDR_PAL_WRITE); |
237 | TGA_WRITE_REG(par, BT485_DATA_PAL, TGA_RAMDAC_SETUP_REG); | 322 | TGA_WRITE_REG(par, BT485_DATA_PAL, TGA_RAMDAC_SETUP_REG); |
238 | 323 | ||
239 | #ifdef CONFIG_HW_CONSOLE | ||
240 | for (i = 0; i < 16; i++) { | ||
241 | int j = color_table[i]; | ||
242 | |||
243 | TGA_WRITE_REG(par, default_red[j]|(BT485_DATA_PAL<<8), | ||
244 | TGA_RAMDAC_REG); | ||
245 | TGA_WRITE_REG(par, default_grn[j]|(BT485_DATA_PAL<<8), | ||
246 | TGA_RAMDAC_REG); | ||
247 | TGA_WRITE_REG(par, default_blu[j]|(BT485_DATA_PAL<<8), | ||
248 | TGA_RAMDAC_REG); | ||
249 | } | ||
250 | for (i = 0; i < 240 * 3; i += 4) { | ||
251 | #else | ||
252 | for (i = 0; i < 256 * 3; i += 4) { | 324 | for (i = 0; i < 256 * 3; i += 4) { |
253 | #endif | ||
254 | TGA_WRITE_REG(par, 0x55 | (BT485_DATA_PAL << 8), | 325 | TGA_WRITE_REG(par, 0x55 | (BT485_DATA_PAL << 8), |
255 | TGA_RAMDAC_REG); | 326 | TGA_RAMDAC_REG); |
256 | TGA_WRITE_REG(par, 0x00 | (BT485_DATA_PAL << 8), | 327 | TGA_WRITE_REG(par, 0x00 | (BT485_DATA_PAL << 8), |
@@ -261,6 +332,27 @@ tgafb_set_par(struct fb_info *info) | |||
261 | TGA_RAMDAC_REG); | 332 | TGA_RAMDAC_REG); |
262 | } | 333 | } |
263 | 334 | ||
335 | } else if (tga_type == TGA_TYPE_8PLANE && tga_bus_tc) { | ||
336 | |||
337 | /* Init BT459 RAMDAC registers. */ | ||
338 | BT459_WRITE(par, BT459_REG_ACC, BT459_CMD_REG_0, 0x40); | ||
339 | BT459_WRITE(par, BT459_REG_ACC, BT459_CMD_REG_1, 0x00); | ||
340 | BT459_WRITE(par, BT459_REG_ACC, BT459_CMD_REG_2, | ||
341 | (par->sync_on_green ? 0xc0 : 0x40)); | ||
342 | |||
343 | BT459_WRITE(par, BT459_REG_ACC, BT459_CUR_CMD_REG, 0x00); | ||
344 | |||
345 | /* Fill the palette. */ | ||
346 | BT459_LOAD_ADDR(par, 0x0000); | ||
347 | TGA_WRITE_REG(par, BT459_PALETTE << 2, TGA_RAMDAC_SETUP_REG); | ||
348 | |||
349 | for (i = 0; i < 256 * 3; i += 4) { | ||
350 | TGA_WRITE_REG(par, 0x55, TGA_RAMDAC_REG); | ||
351 | TGA_WRITE_REG(par, 0x00, TGA_RAMDAC_REG); | ||
352 | TGA_WRITE_REG(par, 0x00, TGA_RAMDAC_REG); | ||
353 | TGA_WRITE_REG(par, 0x00, TGA_RAMDAC_REG); | ||
354 | } | ||
355 | |||
264 | } else { /* 24-plane or 24plusZ */ | 356 | } else { /* 24-plane or 24plusZ */ |
265 | 357 | ||
266 | /* Init BT463 RAMDAC registers. */ | 358 | /* Init BT463 RAMDAC registers. */ |
@@ -431,6 +523,8 @@ tgafb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, | |||
431 | unsigned transp, struct fb_info *info) | 523 | unsigned transp, struct fb_info *info) |
432 | { | 524 | { |
433 | struct tga_par *par = (struct tga_par *) info->par; | 525 | struct tga_par *par = (struct tga_par *) info->par; |
526 | int tga_bus_pci = TGA_BUS_PCI(par->dev); | ||
527 | int tga_bus_tc = TGA_BUS_TC(par->dev); | ||
434 | 528 | ||
435 | if (regno > 255) | 529 | if (regno > 255) |
436 | return 1; | 530 | return 1; |
@@ -438,12 +532,18 @@ tgafb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, | |||
438 | green >>= 8; | 532 | green >>= 8; |
439 | blue >>= 8; | 533 | blue >>= 8; |
440 | 534 | ||
441 | if (par->tga_type == TGA_TYPE_8PLANE) { | 535 | if (par->tga_type == TGA_TYPE_8PLANE && tga_bus_pci) { |
442 | BT485_WRITE(par, regno, BT485_ADDR_PAL_WRITE); | 536 | BT485_WRITE(par, regno, BT485_ADDR_PAL_WRITE); |
443 | TGA_WRITE_REG(par, BT485_DATA_PAL, TGA_RAMDAC_SETUP_REG); | 537 | TGA_WRITE_REG(par, BT485_DATA_PAL, TGA_RAMDAC_SETUP_REG); |
444 | TGA_WRITE_REG(par, red|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG); | 538 | TGA_WRITE_REG(par, red|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG); |
445 | TGA_WRITE_REG(par, green|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG); | 539 | TGA_WRITE_REG(par, green|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG); |
446 | TGA_WRITE_REG(par, blue|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG); | 540 | TGA_WRITE_REG(par, blue|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG); |
541 | } else if (par->tga_type == TGA_TYPE_8PLANE && tga_bus_tc) { | ||
542 | BT459_LOAD_ADDR(par, regno); | ||
543 | TGA_WRITE_REG(par, BT459_PALETTE << 2, TGA_RAMDAC_SETUP_REG); | ||
544 | TGA_WRITE_REG(par, red, TGA_RAMDAC_REG); | ||
545 | TGA_WRITE_REG(par, green, TGA_RAMDAC_REG); | ||
546 | TGA_WRITE_REG(par, blue, TGA_RAMDAC_REG); | ||
447 | } else { | 547 | } else { |
448 | if (regno < 16) { | 548 | if (regno < 16) { |
449 | u32 value = (regno << 16) | (regno << 8) | regno; | 549 | u32 value = (regno << 16) | (regno << 8) | regno; |
@@ -523,16 +623,8 @@ tgafb_blank(int blank, struct fb_info *info) | |||
523 | * Acceleration. | 623 | * Acceleration. |
524 | */ | 624 | */ |
525 | 625 | ||
526 | /** | ||
527 | * tgafb_imageblit - REQUIRED function. Can use generic routines if | ||
528 | * non acclerated hardware and packed pixel based. | ||
529 | * Copies a image from system memory to the screen. | ||
530 | * | ||
531 | * @info: frame buffer structure that represents a single frame buffer | ||
532 | * @image: structure defining the image. | ||
533 | */ | ||
534 | static void | 626 | static void |
535 | tgafb_imageblit(struct fb_info *info, const struct fb_image *image) | 627 | tgafb_mono_imageblit(struct fb_info *info, const struct fb_image *image) |
536 | { | 628 | { |
537 | struct tga_par *par = (struct tga_par *) info->par; | 629 | struct tga_par *par = (struct tga_par *) info->par; |
538 | u32 fgcolor, bgcolor, dx, dy, width, height, vxres, vyres, pixelmask; | 630 | u32 fgcolor, bgcolor, dx, dy, width, height, vxres, vyres, pixelmask; |
@@ -542,6 +634,17 @@ tgafb_imageblit(struct fb_info *info, const struct fb_image *image) | |||
542 | void __iomem *regs_base; | 634 | void __iomem *regs_base; |
543 | void __iomem *fb_base; | 635 | void __iomem *fb_base; |
544 | 636 | ||
637 | is8bpp = info->var.bits_per_pixel == 8; | ||
638 | |||
639 | /* For copies that aren't pixel expansion, there's little we | ||
640 | can do better than the generic code. */ | ||
641 | /* ??? There is a DMA write mode; I wonder if that could be | ||
642 | made to pull the data from the image buffer... */ | ||
643 | if (image->depth > 1) { | ||
644 | cfb_imageblit(info, image); | ||
645 | return; | ||
646 | } | ||
647 | |||
545 | dx = image->dx; | 648 | dx = image->dx; |
546 | dy = image->dy; | 649 | dy = image->dy; |
547 | width = image->width; | 650 | width = image->width; |
@@ -559,18 +662,8 @@ tgafb_imageblit(struct fb_info *info, const struct fb_image *image) | |||
559 | if (dy + height > vyres) | 662 | if (dy + height > vyres) |
560 | height = vyres - dy; | 663 | height = vyres - dy; |
561 | 664 | ||
562 | /* For copies that aren't pixel expansion, there's little we | ||
563 | can do better than the generic code. */ | ||
564 | /* ??? There is a DMA write mode; I wonder if that could be | ||
565 | made to pull the data from the image buffer... */ | ||
566 | if (image->depth > 1) { | ||
567 | cfb_imageblit(info, image); | ||
568 | return; | ||
569 | } | ||
570 | |||
571 | regs_base = par->tga_regs_base; | 665 | regs_base = par->tga_regs_base; |
572 | fb_base = par->tga_fb_base; | 666 | fb_base = par->tga_fb_base; |
573 | is8bpp = info->var.bits_per_pixel == 8; | ||
574 | 667 | ||
575 | /* Expand the color values to fill 32-bits. */ | 668 | /* Expand the color values to fill 32-bits. */ |
576 | /* ??? Would be nice to notice colour changes elsewhere, so | 669 | /* ??? Would be nice to notice colour changes elsewhere, so |
@@ -748,6 +841,85 @@ tgafb_imageblit(struct fb_info *info, const struct fb_image *image) | |||
748 | regs_base + TGA_MODE_REG); | 841 | regs_base + TGA_MODE_REG); |
749 | } | 842 | } |
750 | 843 | ||
844 | static void | ||
845 | tgafb_clut_imageblit(struct fb_info *info, const struct fb_image *image) | ||
846 | { | ||
847 | struct tga_par *par = (struct tga_par *) info->par; | ||
848 | u32 color, dx, dy, width, height, vxres, vyres; | ||
849 | u32 *palette = ((u32 *)info->pseudo_palette); | ||
850 | unsigned long pos, line_length, i, j; | ||
851 | const unsigned char *data; | ||
852 | void *regs_base, *fb_base; | ||
853 | |||
854 | dx = image->dx; | ||
855 | dy = image->dy; | ||
856 | width = image->width; | ||
857 | height = image->height; | ||
858 | vxres = info->var.xres_virtual; | ||
859 | vyres = info->var.yres_virtual; | ||
860 | line_length = info->fix.line_length; | ||
861 | |||
862 | /* Crop the image to the screen. */ | ||
863 | if (dx > vxres || dy > vyres) | ||
864 | return; | ||
865 | if (dx + width > vxres) | ||
866 | width = vxres - dx; | ||
867 | if (dy + height > vyres) | ||
868 | height = vyres - dy; | ||
869 | |||
870 | regs_base = par->tga_regs_base; | ||
871 | fb_base = par->tga_fb_base; | ||
872 | |||
873 | pos = dy * line_length + (dx * 4); | ||
874 | data = image->data; | ||
875 | |||
876 | /* Now copy the image, color_expanding via the palette. */ | ||
877 | for (i = 0; i < height; i++) { | ||
878 | for (j = 0; j < width; j++) { | ||
879 | color = palette[*data++]; | ||
880 | __raw_writel(color, fb_base + pos + j*4); | ||
881 | } | ||
882 | pos += line_length; | ||
883 | } | ||
884 | } | ||
885 | |||
886 | /** | ||
887 | * tgafb_imageblit - REQUIRED function. Can use generic routines if | ||
888 | * non acclerated hardware and packed pixel based. | ||
889 | * Copies a image from system memory to the screen. | ||
890 | * | ||
891 | * @info: frame buffer structure that represents a single frame buffer | ||
892 | * @image: structure defining the image. | ||
893 | */ | ||
894 | static void | ||
895 | tgafb_imageblit(struct fb_info *info, const struct fb_image *image) | ||
896 | { | ||
897 | unsigned int is8bpp = info->var.bits_per_pixel == 8; | ||
898 | |||
899 | /* If a mono image, regardless of FB depth, go do it. */ | ||
900 | if (image->depth == 1) { | ||
901 | tgafb_mono_imageblit(info, image); | ||
902 | return; | ||
903 | } | ||
904 | |||
905 | /* For copies that aren't pixel expansion, there's little we | ||
906 | can do better than the generic code. */ | ||
907 | /* ??? There is a DMA write mode; I wonder if that could be | ||
908 | made to pull the data from the image buffer... */ | ||
909 | if (image->depth == info->var.bits_per_pixel) { | ||
910 | cfb_imageblit(info, image); | ||
911 | return; | ||
912 | } | ||
913 | |||
914 | /* If 24-plane FB and the image is 8-plane with CLUT, we can do it. */ | ||
915 | if (!is8bpp && image->depth == 8) { | ||
916 | tgafb_clut_imageblit(info, image); | ||
917 | return; | ||
918 | } | ||
919 | |||
920 | /* Silently return... */ | ||
921 | } | ||
922 | |||
751 | /** | 923 | /** |
752 | * tgafb_fillrect - REQUIRED function. Can use generic routines if | 924 | * tgafb_fillrect - REQUIRED function. Can use generic routines if |
753 | * non acclerated hardware and packed pixel based. | 925 | * non acclerated hardware and packed pixel based. |
@@ -1309,18 +1481,29 @@ static void | |||
1309 | tgafb_init_fix(struct fb_info *info) | 1481 | tgafb_init_fix(struct fb_info *info) |
1310 | { | 1482 | { |
1311 | struct tga_par *par = (struct tga_par *)info->par; | 1483 | struct tga_par *par = (struct tga_par *)info->par; |
1484 | int tga_bus_pci = TGA_BUS_PCI(par->dev); | ||
1485 | int tga_bus_tc = TGA_BUS_TC(par->dev); | ||
1312 | u8 tga_type = par->tga_type; | 1486 | u8 tga_type = par->tga_type; |
1313 | const char *tga_type_name; | 1487 | const char *tga_type_name = NULL; |
1314 | 1488 | ||
1315 | switch (tga_type) { | 1489 | switch (tga_type) { |
1316 | case TGA_TYPE_8PLANE: | 1490 | case TGA_TYPE_8PLANE: |
1317 | tga_type_name = "Digital ZLXp-E1"; | 1491 | if (tga_bus_pci) |
1492 | tga_type_name = "Digital ZLXp-E1"; | ||
1493 | if (tga_bus_tc) | ||
1494 | tga_type_name = "Digital ZLX-E1"; | ||
1318 | break; | 1495 | break; |
1319 | case TGA_TYPE_24PLANE: | 1496 | case TGA_TYPE_24PLANE: |
1320 | tga_type_name = "Digital ZLXp-E2"; | 1497 | if (tga_bus_pci) |
1498 | tga_type_name = "Digital ZLXp-E2"; | ||
1499 | if (tga_bus_tc) | ||
1500 | tga_type_name = "Digital ZLX-E2"; | ||
1321 | break; | 1501 | break; |
1322 | case TGA_TYPE_24PLUSZ: | 1502 | case TGA_TYPE_24PLUSZ: |
1323 | tga_type_name = "Digital ZLXp-E3"; | 1503 | if (tga_bus_pci) |
1504 | tga_type_name = "Digital ZLXp-E3"; | ||
1505 | if (tga_bus_tc) | ||
1506 | tga_type_name = "Digital ZLX-E3"; | ||
1324 | break; | 1507 | break; |
1325 | default: | 1508 | default: |
1326 | tga_type_name = "Unknown"; | 1509 | tga_type_name = "Unknown"; |
@@ -1346,11 +1529,37 @@ tgafb_init_fix(struct fb_info *info) | |||
1346 | info->fix.ywrapstep = 0; | 1529 | info->fix.ywrapstep = 0; |
1347 | 1530 | ||
1348 | info->fix.accel = FB_ACCEL_DEC_TGA; | 1531 | info->fix.accel = FB_ACCEL_DEC_TGA; |
1532 | |||
1533 | /* | ||
1534 | * These are needed by fb_set_logo_truepalette(), so we | ||
1535 | * set them here for 24-plane cards. | ||
1536 | */ | ||
1537 | if (tga_type != TGA_TYPE_8PLANE) { | ||
1538 | info->var.red.length = 8; | ||
1539 | info->var.green.length = 8; | ||
1540 | info->var.blue.length = 8; | ||
1541 | info->var.red.offset = 16; | ||
1542 | info->var.green.offset = 8; | ||
1543 | info->var.blue.offset = 0; | ||
1544 | } | ||
1349 | } | 1545 | } |
1350 | 1546 | ||
1351 | static __devinit int | 1547 | static int tgafb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) |
1352 | tgafb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent) | 1548 | { |
1549 | /* We just use this to catch switches out of graphics mode. */ | ||
1550 | tgafb_set_par(info); /* A bit of overkill for BASE_ADDR reset. */ | ||
1551 | return 0; | ||
1552 | } | ||
1553 | |||
1554 | static int __devinit | ||
1555 | tgafb_register(struct device *dev) | ||
1353 | { | 1556 | { |
1557 | static const struct fb_videomode modedb_tc = { | ||
1558 | /* 1280x1024 @ 72 Hz, 76.8 kHz hsync */ | ||
1559 | "1280x1024@72", 0, 1280, 1024, 7645, 224, 28, 33, 3, 160, 3, | ||
1560 | FB_SYNC_ON_GREEN, FB_VMODE_NONINTERLACED | ||
1561 | }; | ||
1562 | |||
1354 | static unsigned int const fb_offset_presets[4] = { | 1563 | static unsigned int const fb_offset_presets[4] = { |
1355 | TGA_8PLANE_FB_OFFSET, | 1564 | TGA_8PLANE_FB_OFFSET, |
1356 | TGA_24PLANE_FB_OFFSET, | 1565 | TGA_24PLANE_FB_OFFSET, |
@@ -1358,40 +1567,51 @@ tgafb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
1358 | TGA_24PLUSZ_FB_OFFSET | 1567 | TGA_24PLUSZ_FB_OFFSET |
1359 | }; | 1568 | }; |
1360 | 1569 | ||
1570 | const struct fb_videomode *modedb_tga = NULL; | ||
1571 | resource_size_t bar0_start = 0, bar0_len = 0; | ||
1572 | const char *mode_option_tga = NULL; | ||
1573 | int tga_bus_pci = TGA_BUS_PCI(dev); | ||
1574 | int tga_bus_tc = TGA_BUS_TC(dev); | ||
1575 | unsigned int modedbsize_tga = 0; | ||
1361 | void __iomem *mem_base; | 1576 | void __iomem *mem_base; |
1362 | unsigned long bar0_start, bar0_len; | ||
1363 | struct fb_info *info; | 1577 | struct fb_info *info; |
1364 | struct tga_par *par; | 1578 | struct tga_par *par; |
1365 | u8 tga_type; | 1579 | u8 tga_type; |
1366 | int ret; | 1580 | int ret = 0; |
1367 | 1581 | ||
1368 | /* Enable device in PCI config. */ | 1582 | /* Enable device in PCI config. */ |
1369 | if (pci_enable_device(pdev)) { | 1583 | if (tga_bus_pci && pci_enable_device(to_pci_dev(dev))) { |
1370 | printk(KERN_ERR "tgafb: Cannot enable PCI device\n"); | 1584 | printk(KERN_ERR "tgafb: Cannot enable PCI device\n"); |
1371 | return -ENODEV; | 1585 | return -ENODEV; |
1372 | } | 1586 | } |
1373 | 1587 | ||
1374 | /* Allocate the fb and par structures. */ | 1588 | /* Allocate the fb and par structures. */ |
1375 | info = framebuffer_alloc(sizeof(struct tga_par), &pdev->dev); | 1589 | info = framebuffer_alloc(sizeof(struct tga_par), dev); |
1376 | if (!info) { | 1590 | if (!info) { |
1377 | printk(KERN_ERR "tgafb: Cannot allocate memory\n"); | 1591 | printk(KERN_ERR "tgafb: Cannot allocate memory\n"); |
1378 | return -ENOMEM; | 1592 | return -ENOMEM; |
1379 | } | 1593 | } |
1380 | 1594 | ||
1381 | par = info->par; | 1595 | par = info->par; |
1382 | pci_set_drvdata(pdev, info); | 1596 | dev_set_drvdata(dev, info); |
1383 | 1597 | ||
1384 | /* Request the mem regions. */ | 1598 | /* Request the mem regions. */ |
1385 | bar0_start = pci_resource_start(pdev, 0); | ||
1386 | bar0_len = pci_resource_len(pdev, 0); | ||
1387 | ret = -ENODEV; | 1599 | ret = -ENODEV; |
1600 | if (tga_bus_pci) { | ||
1601 | bar0_start = pci_resource_start(to_pci_dev(dev), 0); | ||
1602 | bar0_len = pci_resource_len(to_pci_dev(dev), 0); | ||
1603 | } | ||
1604 | if (tga_bus_tc) { | ||
1605 | bar0_start = to_tc_dev(dev)->resource.start; | ||
1606 | bar0_len = to_tc_dev(dev)->resource.end - bar0_start + 1; | ||
1607 | } | ||
1388 | if (!request_mem_region (bar0_start, bar0_len, "tgafb")) { | 1608 | if (!request_mem_region (bar0_start, bar0_len, "tgafb")) { |
1389 | printk(KERN_ERR "tgafb: cannot reserve FB region\n"); | 1609 | printk(KERN_ERR "tgafb: cannot reserve FB region\n"); |
1390 | goto err0; | 1610 | goto err0; |
1391 | } | 1611 | } |
1392 | 1612 | ||
1393 | /* Map the framebuffer. */ | 1613 | /* Map the framebuffer. */ |
1394 | mem_base = ioremap(bar0_start, bar0_len); | 1614 | mem_base = ioremap_nocache(bar0_start, bar0_len); |
1395 | if (!mem_base) { | 1615 | if (!mem_base) { |
1396 | printk(KERN_ERR "tgafb: Cannot map MMIO\n"); | 1616 | printk(KERN_ERR "tgafb: Cannot map MMIO\n"); |
1397 | goto err1; | 1617 | goto err1; |
@@ -1399,12 +1619,16 @@ tgafb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
1399 | 1619 | ||
1400 | /* Grab info about the card. */ | 1620 | /* Grab info about the card. */ |
1401 | tga_type = (readl(mem_base) >> 12) & 0x0f; | 1621 | tga_type = (readl(mem_base) >> 12) & 0x0f; |
1402 | par->pdev = pdev; | 1622 | par->dev = dev; |
1403 | par->tga_mem_base = mem_base; | 1623 | par->tga_mem_base = mem_base; |
1404 | par->tga_fb_base = mem_base + fb_offset_presets[tga_type]; | 1624 | par->tga_fb_base = mem_base + fb_offset_presets[tga_type]; |
1405 | par->tga_regs_base = mem_base + TGA_REGS_OFFSET; | 1625 | par->tga_regs_base = mem_base + TGA_REGS_OFFSET; |
1406 | par->tga_type = tga_type; | 1626 | par->tga_type = tga_type; |
1407 | pci_read_config_byte(pdev, PCI_REVISION_ID, &par->tga_chip_rev); | 1627 | if (tga_bus_pci) |
1628 | pci_read_config_byte(to_pci_dev(dev), PCI_REVISION_ID, | ||
1629 | &par->tga_chip_rev); | ||
1630 | if (tga_bus_tc) | ||
1631 | par->tga_chip_rev = TGA_READ_REG(par, TGA_START_REG) & 0xff; | ||
1408 | 1632 | ||
1409 | /* Setup framebuffer. */ | 1633 | /* Setup framebuffer. */ |
1410 | info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_COPYAREA | | 1634 | info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_COPYAREA | |
@@ -1414,8 +1638,17 @@ tgafb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
1414 | info->pseudo_palette = (void *)(par + 1); | 1638 | info->pseudo_palette = (void *)(par + 1); |
1415 | 1639 | ||
1416 | /* This should give a reasonable default video mode. */ | 1640 | /* This should give a reasonable default video mode. */ |
1417 | 1641 | if (tga_bus_pci) { | |
1418 | ret = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, | 1642 | mode_option_tga = mode_option_pci; |
1643 | } | ||
1644 | if (tga_bus_tc) { | ||
1645 | mode_option_tga = mode_option_tc; | ||
1646 | modedb_tga = &modedb_tc; | ||
1647 | modedbsize_tga = 1; | ||
1648 | } | ||
1649 | ret = fb_find_mode(&info->var, info, | ||
1650 | mode_option ? mode_option : mode_option_tga, | ||
1651 | modedb_tga, modedbsize_tga, NULL, | ||
1419 | tga_type == TGA_TYPE_8PLANE ? 8 : 32); | 1652 | tga_type == TGA_TYPE_8PLANE ? 8 : 32); |
1420 | if (ret == 0 || ret == 4) { | 1653 | if (ret == 0 || ret == 4) { |
1421 | printk(KERN_ERR "tgafb: Could not find valid video mode\n"); | 1654 | printk(KERN_ERR "tgafb: Could not find valid video mode\n"); |
@@ -1438,13 +1671,19 @@ tgafb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
1438 | goto err1; | 1671 | goto err1; |
1439 | } | 1672 | } |
1440 | 1673 | ||
1441 | printk(KERN_INFO "tgafb: DC21030 [TGA] detected, rev=0x%02x\n", | 1674 | if (tga_bus_pci) { |
1442 | par->tga_chip_rev); | 1675 | pr_info("tgafb: DC21030 [TGA] detected, rev=0x%02x\n", |
1443 | printk(KERN_INFO "tgafb: at PCI bus %d, device %d, function %d\n", | 1676 | par->tga_chip_rev); |
1444 | pdev->bus->number, PCI_SLOT(pdev->devfn), | 1677 | pr_info("tgafb: at PCI bus %d, device %d, function %d\n", |
1445 | PCI_FUNC(pdev->devfn)); | 1678 | to_pci_dev(dev)->bus->number, |
1446 | printk(KERN_INFO "fb%d: %s frame buffer device at 0x%lx\n", | 1679 | PCI_SLOT(to_pci_dev(dev)->devfn), |
1447 | info->node, info->fix.id, bar0_start); | 1680 | PCI_FUNC(to_pci_dev(dev)->devfn)); |
1681 | } | ||
1682 | if (tga_bus_tc) | ||
1683 | pr_info("tgafb: SFB+ detected, rev=0x%02x\n", | ||
1684 | par->tga_chip_rev); | ||
1685 | pr_info("fb%d: %s frame buffer device at 0x%lx\n", | ||
1686 | info->node, info->fix.id, (long)bar0_start); | ||
1448 | 1687 | ||
1449 | return 0; | 1688 | return 0; |
1450 | 1689 | ||
@@ -1458,25 +1697,39 @@ tgafb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
1458 | } | 1697 | } |
1459 | 1698 | ||
1460 | static void __devexit | 1699 | static void __devexit |
1461 | tgafb_pci_unregister(struct pci_dev *pdev) | 1700 | tgafb_unregister(struct device *dev) |
1462 | { | 1701 | { |
1463 | struct fb_info *info = pci_get_drvdata(pdev); | 1702 | resource_size_t bar0_start = 0, bar0_len = 0; |
1464 | struct tga_par *par = info->par; | 1703 | int tga_bus_pci = TGA_BUS_PCI(dev); |
1704 | int tga_bus_tc = TGA_BUS_TC(dev); | ||
1705 | struct fb_info *info = NULL; | ||
1706 | struct tga_par *par; | ||
1465 | 1707 | ||
1708 | info = dev_get_drvdata(dev); | ||
1466 | if (!info) | 1709 | if (!info) |
1467 | return; | 1710 | return; |
1711 | |||
1712 | par = info->par; | ||
1468 | unregister_framebuffer(info); | 1713 | unregister_framebuffer(info); |
1469 | fb_dealloc_cmap(&info->cmap); | 1714 | fb_dealloc_cmap(&info->cmap); |
1470 | iounmap(par->tga_mem_base); | 1715 | iounmap(par->tga_mem_base); |
1471 | release_mem_region(pci_resource_start(pdev, 0), | 1716 | if (tga_bus_pci) { |
1472 | pci_resource_len(pdev, 0)); | 1717 | bar0_start = pci_resource_start(to_pci_dev(dev), 0); |
1718 | bar0_len = pci_resource_len(to_pci_dev(dev), 0); | ||
1719 | } | ||
1720 | if (tga_bus_tc) { | ||
1721 | bar0_start = to_tc_dev(dev)->resource.start; | ||
1722 | bar0_len = to_tc_dev(dev)->resource.end - bar0_start + 1; | ||
1723 | } | ||
1724 | release_mem_region(bar0_start, bar0_len); | ||
1473 | framebuffer_release(info); | 1725 | framebuffer_release(info); |
1474 | } | 1726 | } |
1475 | 1727 | ||
1476 | static void __devexit | 1728 | static void __devexit |
1477 | tgafb_exit(void) | 1729 | tgafb_exit(void) |
1478 | { | 1730 | { |
1479 | pci_unregister_driver(&tgafb_driver); | 1731 | tc_unregister_driver(&tgafb_tc_driver); |
1732 | pci_unregister_driver(&tgafb_pci_driver); | ||
1480 | } | 1733 | } |
1481 | 1734 | ||
1482 | #ifndef MODULE | 1735 | #ifndef MODULE |
@@ -1505,6 +1758,7 @@ tgafb_setup(char *arg) | |||
1505 | static int __devinit | 1758 | static int __devinit |
1506 | tgafb_init(void) | 1759 | tgafb_init(void) |
1507 | { | 1760 | { |
1761 | int status; | ||
1508 | #ifndef MODULE | 1762 | #ifndef MODULE |
1509 | char *option = NULL; | 1763 | char *option = NULL; |
1510 | 1764 | ||
@@ -1512,7 +1766,10 @@ tgafb_init(void) | |||
1512 | return -ENODEV; | 1766 | return -ENODEV; |
1513 | tgafb_setup(option); | 1767 | tgafb_setup(option); |
1514 | #endif | 1768 | #endif |
1515 | return pci_register_driver(&tgafb_driver); | 1769 | status = pci_register_driver(&tgafb_pci_driver); |
1770 | if (!status) | ||
1771 | status = tc_register_driver(&tgafb_tc_driver); | ||
1772 | return status; | ||
1516 | } | 1773 | } |
1517 | 1774 | ||
1518 | /* | 1775 | /* |
@@ -1522,5 +1779,5 @@ tgafb_init(void) | |||
1522 | module_init(tgafb_init); | 1779 | module_init(tgafb_init); |
1523 | module_exit(tgafb_exit); | 1780 | module_exit(tgafb_exit); |
1524 | 1781 | ||
1525 | MODULE_DESCRIPTION("framebuffer driver for TGA chipset"); | 1782 | MODULE_DESCRIPTION("Framebuffer driver for TGA/SFB+ chipset"); |
1526 | MODULE_LICENSE("GPL"); | 1783 | MODULE_LICENSE("GPL"); |