31 #include <linux/module.h>
32 #include <linux/kernel.h>
33 #include <linux/errno.h>
34 #include <linux/string.h>
36 #include <linux/slab.h>
39 #include <linux/pci.h>
40 #include <asm/cacheflush.h>
41 #include <asm/tlbflush.h>
48 #define MODULE_NAME "vmlfb"
50 #define VML_TOHW(_val, _width) ((((_val) << (_width)) + 0x7FFF - (_val)) >> 16)
52 static struct mutex vml_mutex;
55 static struct fb_ops vmlfb_ops;
57 static char *vml_default_mode =
"1024x768@60";
59 NULL, 60, 1024, 768, 12896, 144, 24, 29, 3, 136, 6,
63 static u32 vml_mem_requested = (10 * 1024 * 1024);
64 static u32 vml_mem_contig = (4 * 1024 * 1024);
65 static u32 vml_mem_min = (4 * 1024 * 1024);
67 static u32 vml_clocks[] = {
87 static int vmlfb_alloc_vram_area(
struct vram_area *
va,
unsigned max_order,
105 }
while (va->
logical == 0 && max_order > min_order);
112 va->
order = max_order;
133 ": Allocated %ld bytes vram area at 0x%08lx\n",
144 static void vmlfb_free_vram_area(
struct vram_area *va)
168 ": Freeing %ld bytes vram area at 0x%08lx\n",
180 static void vmlfb_free_vram(
struct vml_info *vinfo)
185 vmlfb_free_vram_area(&vinfo->
vram[i]);
197 static int vmlfb_alloc_vram(
struct vml_info *vinfo,
199 size_t min_total,
size_t min_contig)
210 va = &vinfo->
vram[
i];
216 err = vmlfb_alloc_vram_area(va, order, 0);
229 for (j = 0; j <
i; ++
j) {
230 va2 = &vinfo->
vram[
j];
247 vmlfb_free_vram_area(va);
252 if (requested < va->
size)
255 requested -= va->
size;
262 ": Contiguous vram: %ld bytes at physical 0x%08lx.\n",
270 ": Could not allocate requested minimal amount of vram.\n");
272 vmlfb_free_vram(vinfo);
281 static int vmlfb_get_gpu(
struct vml_par *par)
303 static int vmlfb_vram_offset(
struct vml_info *vinfo,
unsigned long offset)
305 unsigned long aoffset;
311 if (aoffset < vinfo->vram[i].
size) {
323 static int vmlfb_enable_mmio(
struct vml_par *par)
331 ": Could not claim display controller MMIO.\n");
337 ": Could not map display controller MMIO.\n");
371 static void vmlfb_disable_mmio(
struct vml_par *par)
383 static void vmlfb_release_devices(
struct vml_par *par)
386 pci_set_drvdata(par->
vdc,
NULL);
402 info = pci_get_drvdata(dev);
409 vmlfb_free_vram(vinfo);
410 vmlfb_disable_mmio(par);
411 vmlfb_release_devices(par);
422 var->
blue.offset = 0;
423 var->
blue.length = 5;
424 var->
green.offset = 5;
425 var->
green.length = 5;
426 var->
red.offset = 10;
432 var->
blue.offset = 0;
433 var->
blue.length = 8;
434 var->
green.offset = 8;
435 var->
green.length = 8;
436 var->
red.offset = 16;
445 var->
blue.msb_right = var->
green.msb_right =
446 var->
red.msb_right = var->
transp.msb_right = 0;
479 if ((err = vmlfb_get_gpu(par)))
481 pci_set_drvdata(dev, &vinfo->
info);
492 err = vmlfb_enable_mmio(par);
496 err = vmlfb_alloc_vram(vinfo, vml_mem_requested,
497 vml_mem_contig, vml_mem_min);
502 info->
fix.mmio_start = 0;
503 info->
fix.mmio_len = 0;
508 info->
fix.ypanstep = 1;
509 info->
fix.xpanstep = 1;
510 info->
fix.ywrapstep = 0;
515 info->
fbops = &vmlfb_ops;
518 INIT_LIST_HEAD(&vinfo->
head);
522 info->
var.grayscale = 0;
523 info->
var.bits_per_pixel = 16;
524 vmlfb_set_pref_pixel_format(&info->
var);
527 (&info->
var, info, vml_default_mode,
NULL, 0, &defaultmode, 16)) {
542 printk(
"Initialized vmlfb\n");
549 vmlfb_free_vram(vinfo);
551 vmlfb_disable_mmio(par);
553 vmlfb_release_devices(par);
561 static int vmlfb_open(
struct fb_info *info,
int user)
569 static int vmlfb_release(
struct fb_info *info,
int user)
578 static int vml_nearest_clock(
int clock)
587 cur_diff = clock - vml_clocks[0];
588 cur_diff = (cur_diff < 0) ? -cur_diff : cur_diff;
589 for (i = 1; i < vml_num_clocks; ++
i) {
590 diff = clock - vml_clocks[
i];
591 diff = (diff < 0) ? -diff : diff;
592 if (diff < cur_diff) {
597 return vml_clocks[cur_index];
616 nearest_clock = vml_nearest_clock(clock);
623 clock_diff = nearest_clock -
clock;
624 clock_diff = (clock_diff < 0) ? -clock_diff : clock_diff;
625 if (clock_diff > clock / 5) {
640 ": Virtual resolution failure.\n");
643 switch (v.bits_per_pixel) {
645 v.bits_per_pixel = 16;
648 v.bits_per_pixel = 32;
662 switch (v.bits_per_pixel) {
664 if (var->
blue.offset != 0 ||
665 var->
blue.length != 5 ||
666 var->
green.offset != 5 ||
667 var->
green.length != 5 ||
668 var->
red.offset != 10 ||
669 var->
red.length != 5 ||
671 vmlfb_set_pref_pixel_format(&v);
675 if (var->
blue.offset != 0 ||
676 var->
blue.length != 8 ||
677 var->
green.offset != 8 ||
678 var->
green.length != 8 ||
679 var->
red.offset != 16 ||
680 var->
red.length != 8 ||
682 (var->
transp.length == 8 && var->
transp.offset != 24)) {
683 vmlfb_set_pref_pixel_format(&v);
701 ret = vmlfb_check_var_locked(var, vinfo);
707 static void vml_wait_vblank(
struct vml_info *vinfo)
713 static void vmlfb_disable_pipe(
struct vml_info *vinfo)
726 vml_wait_vblank(vinfo);
735 #ifdef VERMILION_DEBUG
736 static void vml_dump_regs(
struct vml_info *vinfo)
779 static int vmlfb_set_par_locked(
struct vml_info *vinfo)
784 u32 htotal, hactive, hblank_start, hblank_end, hsync_start, hsync_end;
785 u32 vtotal, vactive, vblank_start, vblank_end, vsync_start, vsync_end;
799 hblank_start = var->
xres;
802 hsync_end = hsync_start + var->
hsync_len;
807 vblank_start = var->
yres;
810 vsync_end = vsync_start + var->
vsync_len;
818 clock = vml_nearest_clock(clock);
821 ": Set mode Hfreq : %d kHz, Vfreq : %d Hz.\n", clock / htotal,
822 ((clock / htotal) * 1000) / vtotal);
829 if (var->
transp.length == 8)
838 vmlfb_disable_pipe(vinfo);
848 ((hblank_end - 1) << 16) | (hblank_start - 1));
850 ((hsync_end - 1) << 16) | (hsync_start - 1));
853 ((vblank_end - 1) << 16) | (vblank_start - 1));
855 ((vsync_end - 1) << 16) | (vsync_start - 1));
858 ((var->
yres - 1) << 16) | (var->
xres - 1));
864 ((var->
xres - 1) << 16) | (var->
yres - 1));
881 #ifdef VERMILION_DEBUG
882 vml_dump_regs(vinfo);
888 static int vmlfb_set_par(
struct fb_info *info)
894 list_move(&vinfo->
head, (subsys) ? &global_has_mode : &global_no_mode);
895 ret = vmlfb_set_par_locked(vinfo);
901 static int vmlfb_blank_locked(
struct vml_info *vinfo)
909 vmlfb_set_par_locked(vinfo);
916 vmlfb_set_par_locked(vinfo);
924 vmlfb_disable_pipe(vinfo);
929 vmlfb_disable_pipe(vinfo);
939 static int vmlfb_blank(
int blank_mode,
struct fb_info *info)
946 ret = vmlfb_blank_locked(vinfo);
975 if (info->
var.grayscale) {
976 red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
985 transp =
VML_TOHW(transp, info->
var.transp.length);
987 v = (red << info->
var.red.offset) |
988 (green << info->
var.green.offset) |
989 (blue << info->
var.blue.offset) |
990 (transp << info->
var.transp.offset);
992 switch (info->
var.bits_per_pixel) {
1015 ret = vmlfb_vram_offset(vinfo, offset);
1027 static int vmlfb_sync(
struct fb_info *info)
1037 static struct fb_ops vmlfb_ops = {
1039 .fb_open = vmlfb_open,
1040 .fb_release = vmlfb_release,
1041 .fb_check_var = vmlfb_check_var,
1042 .fb_set_par = vmlfb_set_par,
1043 .fb_blank = vmlfb_blank,
1044 .fb_pan_display = vmlfb_pan_display,
1048 .fb_cursor = vmlfb_cursor,
1049 .fb_sync = vmlfb_sync,
1050 .fb_mmap = vmlfb_mmap,
1051 .fb_setcolreg = vmlfb_setcolreg
1059 static struct pci_driver vmlfb_pci_driver = {
1061 .id_table = vml_ids,
1062 .probe = vml_pci_probe,
1066 static void __exit vmlfb_cleanup(
void)
1071 static int __init vmlfb_init(
void)
1083 INIT_LIST_HEAD(&global_no_mode);
1084 INIT_LIST_HEAD(&global_has_mode);
1086 return pci_register_driver(&vmlfb_pci_driver);
1096 if (subsys !=
NULL) {
1100 subsys->
save(subsys);
1107 list = global_no_mode.next;
1108 while (list != &global_no_mode) {
1109 list_del_init(list);
1117 if (!vmlfb_check_var_locked(&entry->
info.var, entry)) {
1118 vmlfb_set_par_locked(entry);
1128 save_activate = entry->
info.var.activate;
1129 entry->
info.var.bits_per_pixel = 16;
1130 vmlfb_set_pref_pixel_format(&entry->
info.var);
1133 vml_default_mode,
NULL, 0,
NULL, 16)) {
1134 entry->
info.var.activate |=
1139 ": Sorry. no mode found for this subsys.\n");
1141 entry->
info.var.activate = save_activate;
1144 vmlfb_blank_locked(entry);
1145 list = global_no_mode.next;
1150 subsys->
name ? subsys->
name :
"unknown");
1161 if (subsys != sys) {
1169 vmlfb_disable_pipe(entry);
1170 list_move_tail(&entry->
head, &global_no_mode);