/* * linux/drivers/video/tgafb.c -- DEC 21030 TGA frame buffer device * * Copyright (C) 1995 Jay Estabrook * Copyright (C) 1997 Geert Uytterhoeven * Copyright (C) 1999,2000 Martin Lucina, Tom Zerucha * Copyright (C) 2002 Richard Henderson * Copyright (C) 2006, 2007 Maciej W. Rozycki * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive for * more details. */ #include <linux/aperture.h>#include <linux/bitrev.h>#include <linux/compiler.h>#include <linux/delay.h>#include <linux/device.h>#include <linux/errno.h>#include <linux/fb.h>#include <linux/init.h>#include <linux/ioport.h>#include <linux/kernel.h>#include <linux/mm.h>#include <linux/module.h>#include <linux/pci.h>#include <linux/selection.h>#include <linux/string.h>#include <linux/tc.h> #include <asm/io.h> #include <video/tgafb.h> #ifdef CONFIG_TC#define TGA_BUS_TC(dev) (dev->bus == &tc_bus_type)#else#define TGA_BUS_TC(dev) 0#endif /* * Local functions. */ static int tgafb_check_var(struct fb_var_screeninfo *, struct fb_info *);static int tgafb_set_par(struct fb_info *);static void tgafb_set_pll(struct tga_par *, int);static int tgafb_setcolreg(unsigned, unsigned, unsigned, unsigned, unsigned, struct fb_info *);static int tgafb_blank(int, struct fb_info *);static void tgafb_init_fix(struct fb_info *); static void tgafb_imageblit(struct fb_info *, const struct fb_image *);static void tgafb_fillrect(struct fb_info *, const struct fb_fillrect *);static void tgafb_copyarea(struct fb_info *, const struct fb_copyarea *);static int tgafb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info); static int tgafb_register(struct device *dev);static void tgafb_unregister(struct device *dev); static const char *mode_option;static const char *mode_option_pci = "640x480@60";static const char *mode_option_tc = "1280x1024@72"; static struct pci_driver tgafb_pci_driver;static struct tc_driver tgafb_tc_driver; /* * Frame buffer operations */ static const struct fb_ops tgafb_ops = { .owner = THIS_MODULE, __FB_DEFAULT_IOMEM_OPS_RDWR, .fb_check_var = tgafb_check_var, .fb_set_par = tgafb_set_par, .fb_setcolreg = tgafb_setcolreg, .fb_blank = tgafb_blank, .fb_pan_display = tgafb_pan_display, .fb_fillrect = tgafb_fillrect, .fb_copyarea = tgafb_copyarea, .fb_imageblit = tgafb_imageblit, __FB_DEFAULT_IOMEM_OPS_MMAP,}; #ifdef CONFIG_PCI/* * PCI registration operations */static int tgafb_pci_register(struct pci_dev *, const struct pci_device_id *);static void tgafb_pci_unregister(struct pci_dev *); static struct pci_device_id const tgafb_pci_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TGA) }, { }};MODULE_DEVICE_TABLE(pci, tgafb_pci_table); static struct pci_driver tgafb_pci_driver = { .name = "tgafb", .id_table = tgafb_pci_table, .probe = tgafb_pci_register, .remove = tgafb_pci_unregister,}; static int tgafb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent){ int ret; ret = aperture_remove_conflicting_pci_devices(pdev, "tgafb"); if (ret) return ret; return tgafb_register(&pdev->dev);} static void tgafb_pci_unregister(struct pci_dev *pdev){ tgafb_unregister(&pdev->dev);}#endif /* CONFIG_PCI */ #ifdef CONFIG_TC/* * TC registration operations */static int tgafb_tc_register(struct device *);static int tgafb_tc_unregister(struct device *); static struct tc_device_id const tgafb_tc_table[] = { { "DEC ", "PMAGD-AA" }, { "DEC ", "PMAGD " }, { }};MODULE_DEVICE_TABLE(tc, tgafb_tc_table); static struct tc_driver tgafb_tc_driver = { .id_table = tgafb_tc_table, .driver = { .name = "tgafb", .bus = &tc_bus_type, .probe = tgafb_tc_register, .remove = tgafb_tc_unregister, },}; static int tgafb_tc_register(struct device *dev){ int status = tgafb_register(dev); if (!status) get_device(dev); return status;} static int tgafb_tc_unregister(struct device *dev){ put_device(dev); tgafb_unregister(dev); return 0;}#endif /* CONFIG_TC */ /** * tgafb_check_var - Optional function. Validates a var passed in. * @var: frame buffer variable screen structure * @info: frame buffer structure that represents a single frame buffer */static inttgafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info){ struct tga_par *par = (struct tga_par *)info->par; if (!var->pixclock) return -EINVAL; if (par->tga_type == TGA_TYPE_8PLANE) { if (var->bits_per_pixel != 8) return -EINVAL; } else { if (var->bits_per_pixel != 32) return -EINVAL; } var->red.length = var->green.length = var->blue.length = 8; if (var->bits_per_pixel == 32) { var->red.offset = 16; var->green.offset = 8; var->blue.offset = 0; } if (var->xres_virtual != var->xres || var->yres_virtual != var->yres) return -EINVAL; if (var->xres * var->yres * (var->bits_per_pixel >> 3) > info->fix.smem_len) return -EINVAL; if (var->nonstd) return -EINVAL; if (1000000000 / var->pixclock > TGA_PLL_MAX_FREQ) return -EINVAL; if ((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) return -EINVAL; /* Some of the acceleration routines assume the line width is a multiple of 8 bytes. */ if (var->xres * (par->tga_type == TGA_TYPE_8PLANE ? 1 : 4) % 8) return -EINVAL; return 0;} /** * tgafb_set_par - Optional function. Alters the hardware state. * @info: frame buffer structure that represents a single frame buffer */static inttgafb_set_par(struct fb_info *info){ static unsigned int const deep_presets[4] = { 0x00004000, 0x0000440d, 0xffffffff, 0x0000441d }; static unsigned int const rasterop_presets[4] = { 0x00000003, 0x00000303, 0xffffffff, 0x00000303 }; static unsigned int const mode_presets[4] = { 0x00000000, 0x00000300, 0xffffffff, 0x00000300 }; static unsigned int const base_addr_presets[4] = { 0x00000000, 0x00000001, 0xffffffff, 0x00000001 }; struct tga_par *par = (struct tga_par *) info->par; int tga_bus_pci = dev_is_pci(par->dev); int tga_bus_tc = TGA_BUS_TC(par->dev); u32 htimings, vtimings, pll_freq; u8 tga_type; int i; /* Encode video timings. */ htimings = (((info->var.xres/4) & TGA_HORIZ_ACT_LSB) | (((info->var.xres/4) & 0x600 << 19) & TGA_HORIZ_ACT_MSB)); vtimings = (info->var.yres & TGA_VERT_ACTIVE); htimings |= ((info->var.right_margin/4) << 9) & TGA_HORIZ_FP; vtimings |= (info->var.lower_margin << 11) & TGA_VERT_FP; htimings |= ((info->var.hsync_len/4) << 14) & TGA_HORIZ_SYNC; vtimings |= (info->var.vsync_len << 16) & TGA_VERT_SYNC; htimings |= ((info->var.left_margin/4) << 21) & TGA_HORIZ_BP; vtimings |= (info->var.upper_margin << 22) & TGA_VERT_BP; if (info->var.sync & FB_SYNC_HOR_HIGH_ACT) htimings |= TGA_HORIZ_POLARITY; if (info->var.sync & FB_SYNC_VERT_HIGH_ACT) vtimings |= TGA_VERT_POLARITY; par->htimings = htimings; par->vtimings = vtimings; par->sync_on_green = !!(info->var.sync & FB_SYNC_ON_GREEN); /* Store other useful values in par. */ par->xres = info->var.xres; par->yres = info->var.yres; par->pll_freq = pll_freq = 1000000000 / info->var.pixclock; par->bits_per_pixel = info->var.bits_per_pixel; info->fix.line_length = par->xres * (par->bits_per_pixel >> 3); tga_type = par->tga_type; /* First, disable video. */ TGA_WRITE_REG(par, TGA_VALID_VIDEO | TGA_VALID_BLANK, TGA_VALID_REG); /* Write the DEEP register. */ while (TGA_READ_REG(par, TGA_CMD_STAT_REG) & 1) /* wait for not busy */ continue; mb(); TGA_WRITE_REG(par, deep_presets[tga_type] | (par->sync_on_green ? 0x0 : 0x00010000), TGA_DEEP_REG); while (TGA_READ_REG(par, TGA_CMD_STAT_REG) & 1) /* wait for not busy */ continue; mb(); /* Write some more registers. */ TGA_WRITE_REG(par, rasterop_presets[tga_type], TGA_RASTEROP_REG); TGA_WRITE_REG(par, mode_presets[tga_type], TGA_MODE_REG); TGA_WRITE_REG(par, base_addr_presets[tga_type], TGA_BASE_ADDR_REG); /* Calculate & write the PLL. */ tgafb_set_pll(par, pll_freq); /* Write some more registers. */ TGA_WRITE_REG(par, 0xffffffff, TGA_PLANEMASK_REG); TGA_WRITE_REG(par, 0xffffffff, TGA_PIXELMASK_REG); /* Init video timing regs. */ TGA_WRITE_REG(par, htimings, TGA_HORIZ_REG); TGA_WRITE_REG(par, vtimings, TGA_VERT_REG); /* Initialise RAMDAC. */ if (tga_type == TGA_TYPE_8PLANE && tga_bus_pci) { /* Init BT485 RAMDAC registers. */ BT485_WRITE(par, 0xa2 | (par->sync_on_green ? 0x8 : 0x0), BT485_CMD_0); BT485_WRITE(par, 0x01, BT485_ADDR_PAL_WRITE); BT485_WRITE(par, 0x14, BT485_CMD_3); /* cursor 64x64 */ BT485_WRITE(par, 0x40, BT485_CMD_1); BT485_WRITE(par, 0x20, BT485_CMD_2); /* cursor off, for now */ BT485_WRITE(par, 0xff, BT485_PIXEL_MASK); /* Fill palette registers. */ BT485_WRITE(par, 0x00, BT485_ADDR_PAL_WRITE); TGA_WRITE_REG(par, BT485_DATA_PAL, TGA_RAMDAC_SETUP_REG); for (i = 0; i < 256 * 3; i += 4) { TGA_WRITE_REG(par, 0x55 | (BT485_DATA_PAL << 8), TGA_RAMDAC_REG); TGA_WRITE_REG(par, 0x00 | (BT485_DATA_PAL << 8), TGA_RAMDAC_REG); TGA_WRITE_REG(par, 0x00 | (BT485_DATA_PAL << 8), TGA_RAMDAC_REG); TGA_WRITE_REG(par, 0x00 | (BT485_DATA_PAL << 8), TGA_RAMDAC_REG); } } else if (tga_type == TGA_TYPE_8PLANE && tga_bus_tc) { /* Init BT459 RAMDAC registers. */ BT459_WRITE(par, BT459_REG_ACC, BT459_CMD_REG_0, 0x40); BT459_WRITE(par, BT459_REG_ACC, BT459_CMD_REG_1, 0x00); BT459_WRITE(par, BT459_REG_ACC, BT459_CMD_REG_2, (par->sync_on_green ? 0xc0 : 0x40)); BT459_WRITE(par, BT459_REG_ACC, BT459_CUR_CMD_REG, 0x00); /* Fill the palette. */ BT459_LOAD_ADDR(par, 0x0000); TGA_WRITE_REG(par, BT459_PALETTE << 2, TGA_RAMDAC_SETUP_REG); for (i = 0; i < 256 * 3; i += 4) { TGA_WRITE_REG(par, 0x55, TGA_RAMDAC_REG); TGA_WRITE_REG(par, 0x00, TGA_RAMDAC_REG); TGA_WRITE_REG(par, 0x00, TGA_RAMDAC_REG); TGA_WRITE_REG(par, 0x00, TGA_RAMDAC_REG); } } else { /* 24-plane or 24plusZ */ /* Init BT463 RAMDAC registers. */ BT463_WRITE(par, BT463_REG_ACC, BT463_CMD_REG_0, 0x40); BT463_WRITE(par, BT463_REG_ACC, BT463_CMD_REG_1, 0x08); BT463_WRITE(par, BT463_REG_ACC, BT463_CMD_REG_2, (par->sync_on_green ? 0xc0 : 0x40)); BT463_WRITE(par, BT463_REG_ACC, BT463_READ_MASK_0, 0xff); BT463_WRITE(par, BT463_REG_ACC, BT463_READ_MASK_1, 0xff); BT463_WRITE(par, BT463_REG_ACC, BT463_READ_MASK_2, 0xff); BT463_WRITE(par, BT463_REG_ACC, BT463_READ_MASK_3, 0x0f); BT463_WRITE(par, BT463_REG_ACC, BT463_BLINK_MASK_0, 0x00); BT463_WRITE(par, BT463_REG_ACC, BT463_BLINK_MASK_1, 0x00); BT463_WRITE(par, BT463_REG_ACC, BT463_BLINK_MASK_2, 0x00); BT463_WRITE(par, BT463_REG_ACC, BT463_BLINK_MASK_3, 0x00); /* Fill the palette. */ BT463_LOAD_ADDR(par, 0x0000); TGA_WRITE_REG(par, BT463_PALETTE << 2, TGA_RAMDAC_SETUP_REG); #ifdef CONFIG_VT for (i = 0; i < 16; i++) { int j = color_table[i]; TGA_WRITE_REG(par, default_red[j], TGA_RAMDAC_REG); TGA_WRITE_REG(par, default_grn[j], TGA_RAMDAC_REG); TGA_WRITE_REG(par, default_blu[j], TGA_RAMDAC_REG); } for (i = 0; i < 512 * 3; i += 4) {#else for (i = 0; i < 528 * 3; i += 4) {#endif TGA_WRITE_REG(par, 0x55, TGA_RAMDAC_REG); TGA_WRITE_REG(par, 0x00, TGA_RAMDAC_REG); TGA_WRITE_REG(par, 0x00, TGA_RAMDAC_REG); TGA_WRITE_REG(par, 0x00, TGA_RAMDAC_REG); } /* Fill window type table after start of vertical retrace. */ while (!(TGA_READ_REG(par, TGA_INTR_STAT_REG) & 0x01)) continue; TGA_WRITE_REG(par, 0x01, TGA_INTR_STAT_REG); mb(); while (!(TGA_READ_REG(par, TGA_INTR_STAT_REG) & 0x01)) continue; TGA_WRITE_REG(par, 0x01, TGA_INTR_STAT_REG); BT463_LOAD_ADDR(par, BT463_WINDOW_TYPE_BASE); TGA_WRITE_REG(par, BT463_REG_ACC << 2, TGA_RAMDAC_SETUP_REG); for (i = 0; i < 16; i++) { TGA_WRITE_REG(par, 0x00, TGA_RAMDAC_REG); TGA_WRITE_REG(par, 0x01, TGA_RAMDAC_REG); TGA_WRITE_REG(par, 0x00, TGA_RAMDAC_REG); } } /* Finally, enable video scan (and pray for the monitor... :-) */ TGA_WRITE_REG(par, TGA_VALID_VIDEO, TGA_VALID_REG); return 0;} #define DIFFCHECK(X) \do { \ if (m <= 0x3f) { \ int delta = f - (TGA_PLL_BASE_FREQ * (X)) / (r << shift); \ if (delta < 0) \ delta = -delta; \ if (delta < min_diff) \ min_diff = delta, vm = m, va = a, vr = r; \ } \} while (0) static voidtgafb_set_pll(struct tga_par *par, int f){ int n, shift, base, min_diff, target; int r,a,m,vm = 34, va = 1, vr = 30; for (r = 0 ; r < 12 ; r++) TGA_WRITE_REG(par, !r, TGA_CLOCK_REG); if (f > TGA_PLL_MAX_FREQ) f = TGA_PLL_MAX_FREQ; if (f >= TGA_PLL_MAX_FREQ / 2) shift = 0; else if (f >= TGA_PLL_MAX_FREQ / 4) shift = 1; else shift = 2; TGA_WRITE_REG(par, shift & 1, TGA_CLOCK_REG); TGA_WRITE_REG(par, shift >> 1, TGA_CLOCK_REG); for (r = 0 ; r < 10 ; r++) TGA_WRITE_REG(par, 0, TGA_CLOCK_REG); if (f <= 120000) { TGA_WRITE_REG(par, 0, TGA_CLOCK_REG); TGA_WRITE_REG(par, 0, TGA_CLOCK_REG); } else if (f <= 200000) { TGA_WRITE_REG(par, 1, TGA_CLOCK_REG); TGA_WRITE_REG(par, 0, TGA_CLOCK_REG); } else { TGA_WRITE_REG(par, 0, TGA_CLOCK_REG); TGA_WRITE_REG(par, 1, TGA_CLOCK_REG); } TGA_WRITE_REG(par, 1, TGA_CLOCK_REG); TGA_WRITE_REG(par, 0, TGA_CLOCK_REG); TGA_WRITE_REG(par, 0, TGA_CLOCK_REG); TGA_WRITE_REG(par, 1, TGA_CLOCK_REG); TGA_WRITE_REG(par, 0, TGA_CLOCK_REG); TGA_WRITE_REG(par, 1, TGA_CLOCK_REG); target = (f << shift) / TGA_PLL_BASE_FREQ; min_diff = TGA_PLL_MAX_FREQ; r = 7 / target; if (!r) r = 1; base = target * r; while (base < 449) { for (n = base < 7 ? 7 : base; n < base + target && n < 449; n++) { m = ((n + 3) / 7) - 1; a = 0; DIFFCHECK((m + 1) * 7); m++; DIFFCHECK((m + 1) * 7); m = (n / 6) - 1; if ((a = n % 6)) DIFFCHECK(n); }Lines 1–500 of 1629. Load more
/* * linux/drivers/video/tgafb.c -- DEC 21030 TGA frame buffer device * * Copyright (C) 1995 Jay Estabrook * Copyright (C) 1997 Geert Uytterhoeven * Copyright (C) 1999,2000 Martin Lucina, Tom Zerucha * Copyright (C) 2002 Richard Henderson * Copyright (C) 2006, 2007 Maciej W. Rozycki * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive for * more details. */ #include <linux/aperture.h> #include <linux/bitrev.h> #include <linux/compiler.h> #include <linux/delay.h> #include <linux/device.h> #include <linux/errno.h> #include <linux/fb.h> #include <linux/init.h> #include <linux/ioport.h> #include <linux/kernel.h> #include <linux/mm.h> #include <linux/module.h> #include <linux/pci.h> #include <linux/selection.h> #include <linux/string.h> #include <linux/tc.h> #include <asm/io.h> #include <video/tgafb.h> #ifdef CONFIG_TC #define TGA_BUS_TC(dev) (dev->bus == &tc_bus_type) #else #define TGA_BUS_TC(dev) 0 #endif /* * Local functions. */ static int tgafb_check_var(struct fb_var_screeninfo *, struct fb_info *); static int tgafb_set_par(struct fb_info *); static void tgafb_set_pll(struct tga_par *, int); static int tgafb_setcolreg(unsigned, unsigned, unsigned, unsigned, unsigned, struct fb_info *); static int tgafb_blank(int, struct fb_info *); static void tgafb_init_fix(struct fb_info *); static void tgafb_imageblit(struct fb_info *, const struct fb_image *); static void tgafb_fillrect(struct fb_info *, const struct fb_fillrect *); static void tgafb_copyarea(struct fb_info *, const struct fb_copyarea *); static int tgafb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info); static int tgafb_register(struct device *dev); static void tgafb_unregister(struct device *dev); static const char *mode_option; static const char *mode_option_pci = "640x480@60"; static const char *mode_option_tc = "1280x1024@72"; static struct pci_driver tgafb_pci_driver; static struct tc_driver tgafb_tc_driver; /* * Frame buffer operations */ static const struct fb_ops tgafb_ops = { .owner = THIS_MODULE, __FB_DEFAULT_IOMEM_OPS_RDWR, .fb_check_var = tgafb_check_var, .fb_set_par = tgafb_set_par, .fb_setcolreg = tgafb_setcolreg, .fb_blank = tgafb_blank, .fb_pan_display = tgafb_pan_display, .fb_fillrect = tgafb_fillrect, .fb_copyarea = tgafb_copyarea, .fb_imageblit = tgafb_imageblit, __FB_DEFAULT_IOMEM_OPS_MMAP, }; #ifdef CONFIG_PCI /* * PCI registration operations */ static int tgafb_pci_register(struct pci_dev *, const struct pci_device_id *); static void tgafb_pci_unregister(struct pci_dev *); static struct pci_device_id const tgafb_pci_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TGA) }, { } }; MODULE_DEVICE_TABLE(pci, tgafb_pci_table); static struct pci_driver tgafb_pci_driver = { .name = "tgafb", .id_table = tgafb_pci_table, .probe = tgafb_pci_register, .remove = tgafb_pci_unregister, }; static int tgafb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent) { int ret; ret = aperture_remove_conflicting_pci_devices(pdev, "tgafb"); if (ret) return ret; return tgafb_register(&pdev->dev); } static void tgafb_pci_unregister(struct pci_dev *pdev) { tgafb_unregister(&pdev->dev); } #endif /* CONFIG_PCI */ #ifdef CONFIG_TC /* * TC registration operations */ static int tgafb_tc_register(struct device *); static int tgafb_tc_unregister(struct device *); static struct tc_device_id const tgafb_tc_table[] = { { "DEC ", "PMAGD-AA" }, { "DEC ", "PMAGD " }, { } }; MODULE_DEVICE_TABLE(tc, tgafb_tc_table); static struct tc_driver tgafb_tc_driver = { .id_table = tgafb_tc_table, .driver = { .name = "tgafb", .bus = &tc_bus_type, .probe = tgafb_tc_register, .remove = tgafb_tc_unregister, }, }; static int tgafb_tc_register(struct device *dev) { int status = tgafb_register(dev); if (!status) get_device(dev); return status; } static int tgafb_tc_unregister(struct device *dev) { put_device(dev); tgafb_unregister(dev); return 0; } #endif /* CONFIG_TC */ /** * tgafb_check_var - Optional function. Validates a var passed in. * @var: frame buffer variable screen structure * @info: frame buffer structure that represents a single frame buffer */ static int tgafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { struct tga_par *par = (struct tga_par *)info->par; if (!var->pixclock) return -EINVAL; if (par->tga_type == TGA_TYPE_8PLANE) { if (var->bits_per_pixel != 8) return -EINVAL; } else { if (var->bits_per_pixel != 32) return -EINVAL; } var->red.length = var->green.length = var->blue.length = 8; if (var->bits_per_pixel == 32) { var->red.offset = 16; var->green.offset = 8; var->blue.offset = 0; } if (var->xres_virtual != var->xres || var->yres_virtual != var->yres) return -EINVAL; if (var->xres * var->yres * (var->bits_per_pixel >> 3) > info->fix.smem_len) return -EINVAL; if (var->nonstd) return -EINVAL; if (1000000000 / var->pixclock > TGA_PLL_MAX_FREQ) return -EINVAL; if ((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) return -EINVAL; /* Some of the acceleration routines assume the line width is a multiple of 8 bytes. */ if (var->xres * (par->tga_type == TGA_TYPE_8PLANE ? 1 : 4) % 8) return -EINVAL; return 0; } /** * tgafb_set_par - Optional function. Alters the hardware state. * @info: frame buffer structure that represents a single frame buffer */ static int tgafb_set_par(struct fb_info *info) { static unsigned int const deep_presets[4] = { 0x00004000, 0x0000440d, 0xffffffff, 0x0000441d }; static unsigned int const rasterop_presets[4] = { 0x00000003, 0x00000303, 0xffffffff, 0x00000303 }; static unsigned int const mode_presets[4] = { 0x00000000, 0x00000300, 0xffffffff, 0x00000300 }; static unsigned int const base_addr_presets[4] = { 0x00000000, 0x00000001, 0xffffffff, 0x00000001 }; struct tga_par *par = (struct tga_par *) info->par; int tga_bus_pci = dev_is_pci(par->dev); int tga_bus_tc = TGA_BUS_TC(par->dev); u32 htimings, vtimings, pll_freq; u8 tga_type; int i; /* Encode video timings. */ htimings = (((info->var.xres/4) & TGA_HORIZ_ACT_LSB) | (((info->var.xres/4) & 0x600 << 19) & TGA_HORIZ_ACT_MSB)); vtimings = (info->var.yres & TGA_VERT_ACTIVE); htimings |= ((info->var.right_margin/4) << 9) & TGA_HORIZ_FP; vtimings |= (info->var.lower_margin << 11) & TGA_VERT_FP; htimings |= ((info->var.hsync_len/4) << 14) & TGA_HORIZ_SYNC; vtimings |= (info->var.vsync_len << 16) & TGA_VERT_SYNC; htimings |= ((info->var.left_margin/4) << 21) & TGA_HORIZ_BP; vtimings |= (info->var.upper_margin << 22) & TGA_VERT_BP; if (info->var.sync & FB_SYNC_HOR_HIGH_ACT) htimings |= TGA_HORIZ_POLARITY; if (info->var.sync & FB_SYNC_VERT_HIGH_ACT) vtimings |= TGA_VERT_POLARITY; par->htimings = htimings; par->vtimings = vtimings; par->sync_on_green = !!(info->var.sync & FB_SYNC_ON_GREEN); /* Store other useful values in par. */ par->xres = info->var.xres; par->yres = info->var.yres; par->pll_freq = pll_freq = 1000000000 / info->var.pixclock; par->bits_per_pixel = info->var.bits_per_pixel; info->fix.line_length = par->xres * (par->bits_per_pixel >> 3); tga_type = par->tga_type; /* First, disable video. */ TGA_WRITE_REG(par, TGA_VALID_VIDEO | TGA_VALID_BLANK, TGA_VALID_REG); /* Write the DEEP register. */ while (TGA_READ_REG(par, TGA_CMD_STAT_REG) & 1) /* wait for not busy */ continue; mb(); TGA_WRITE_REG(par, deep_presets[tga_type] | (par->sync_on_green ? 0x0 : 0x00010000), TGA_DEEP_REG); while (TGA_READ_REG(par, TGA_CMD_STAT_REG) & 1) /* wait for not busy */ continue; mb(); /* Write some more registers. */ TGA_WRITE_REG(par, rasterop_presets[tga_type], TGA_RASTEROP_REG); TGA_WRITE_REG(par, mode_presets[tga_type], TGA_MODE_REG); TGA_WRITE_REG(par, base_addr_presets[tga_type], TGA_BASE_ADDR_REG); /* Calculate & write the PLL. */ tgafb_set_pll(par, pll_freq); /* Write some more registers. */ TGA_WRITE_REG(par, 0xffffffff, TGA_PLANEMASK_REG); TGA_WRITE_REG(par, 0xffffffff, TGA_PIXELMASK_REG); /* Init video timing regs. */ TGA_WRITE_REG(par, htimings, TGA_HORIZ_REG); TGA_WRITE_REG(par, vtimings, TGA_VERT_REG); /* Initialise RAMDAC. */ if (tga_type == TGA_TYPE_8PLANE && tga_bus_pci) { /* Init BT485 RAMDAC registers. */ BT485_WRITE(par, 0xa2 | (par->sync_on_green ? 0x8 : 0x0), BT485_CMD_0); BT485_WRITE(par, 0x01, BT485_ADDR_PAL_WRITE); BT485_WRITE(par, 0x14, BT485_CMD_3); /* cursor 64x64 */ BT485_WRITE(par, 0x40, BT485_CMD_1); BT485_WRITE(par, 0x20, BT485_CMD_2); /* cursor off, for now */ BT485_WRITE(par, 0xff, BT485_PIXEL_MASK); /* Fill palette registers. */ BT485_WRITE(par, 0x00, BT485_ADDR_PAL_WRITE); TGA_WRITE_REG(par, BT485_DATA_PAL, TGA_RAMDAC_SETUP_REG); for (i = 0; i < 256 * 3; i += 4) { TGA_WRITE_REG(par, 0x55 | (BT485_DATA_PAL << 8), TGA_RAMDAC_REG); TGA_WRITE_REG(par, 0x00 | (BT485_DATA_PAL << 8), TGA_RAMDAC_REG); TGA_WRITE_REG(par, 0x00 | (BT485_DATA_PAL << 8), TGA_RAMDAC_REG); TGA_WRITE_REG(par, 0x00 | (BT485_DATA_PAL << 8), TGA_RAMDAC_REG); } } else if (tga_type == TGA_TYPE_8PLANE && tga_bus_tc) { /* Init BT459 RAMDAC registers. */ BT459_WRITE(par, BT459_REG_ACC, BT459_CMD_REG_0, 0x40); BT459_WRITE(par, BT459_REG_ACC, BT459_CMD_REG_1, 0x00); BT459_WRITE(par, BT459_REG_ACC, BT459_CMD_REG_2, (par->sync_on_green ? 0xc0 : 0x40)); BT459_WRITE(par, BT459_REG_ACC, BT459_CUR_CMD_REG, 0x00); /* Fill the palette. */ BT459_LOAD_ADDR(par, 0x0000); TGA_WRITE_REG(par, BT459_PALETTE << 2, TGA_RAMDAC_SETUP_REG); for (i = 0; i < 256 * 3; i += 4) { TGA_WRITE_REG(par, 0x55, TGA_RAMDAC_REG); TGA_WRITE_REG(par, 0x00, TGA_RAMDAC_REG); TGA_WRITE_REG(par, 0x00, TGA_RAMDAC_REG); TGA_WRITE_REG(par, 0x00, TGA_RAMDAC_REG); } } else { /* 24-plane or 24plusZ */ /* Init BT463 RAMDAC registers. */ BT463_WRITE(par, BT463_REG_ACC, BT463_CMD_REG_0, 0x40); BT463_WRITE(par, BT463_REG_ACC, BT463_CMD_REG_1, 0x08); BT463_WRITE(par, BT463_REG_ACC, BT463_CMD_REG_2, (par->sync_on_green ? 0xc0 : 0x40)); BT463_WRITE(par, BT463_REG_ACC, BT463_READ_MASK_0, 0xff); BT463_WRITE(par, BT463_REG_ACC, BT463_READ_MASK_1, 0xff); BT463_WRITE(par, BT463_REG_ACC, BT463_READ_MASK_2, 0xff); BT463_WRITE(par, BT463_REG_ACC, BT463_READ_MASK_3, 0x0f); BT463_WRITE(par, BT463_REG_ACC, BT463_BLINK_MASK_0, 0x00); BT463_WRITE(par, BT463_REG_ACC, BT463_BLINK_MASK_1, 0x00); BT463_WRITE(par, BT463_REG_ACC, BT463_BLINK_MASK_2, 0x00); BT463_WRITE(par, BT463_REG_ACC, BT463_BLINK_MASK_3, 0x00); /* Fill the palette. */ BT463_LOAD_ADDR(par, 0x0000); TGA_WRITE_REG(par, BT463_PALETTE << 2, TGA_RAMDAC_SETUP_REG); #ifdef CONFIG_VT for (i = 0; i < 16; i++) { int j = color_table[i]; TGA_WRITE_REG(par, default_red[j], TGA_RAMDAC_REG); TGA_WRITE_REG(par, default_grn[j], TGA_RAMDAC_REG); TGA_WRITE_REG(par, default_blu[j], TGA_RAMDAC_REG); } for (i = 0; i < 512 * 3; i += 4) { #else for (i = 0; i < 528 * 3; i += 4) { #endif TGA_WRITE_REG(par, 0x55, TGA_RAMDAC_REG); TGA_WRITE_REG(par, 0x00, TGA_RAMDAC_REG); TGA_WRITE_REG(par, 0x00, TGA_RAMDAC_REG); TGA_WRITE_REG(par, 0x00, TGA_RAMDAC_REG); } /* Fill window type table after start of vertical retrace. */ while (!(TGA_READ_REG(par, TGA_INTR_STAT_REG) & 0x01)) continue; TGA_WRITE_REG(par, 0x01, TGA_INTR_STAT_REG); mb(); while (!(TGA_READ_REG(par, TGA_INTR_STAT_REG) & 0x01)) continue; TGA_WRITE_REG(par, 0x01, TGA_INTR_STAT_REG); BT463_LOAD_ADDR(par, BT463_WINDOW_TYPE_BASE); TGA_WRITE_REG(par, BT463_REG_ACC << 2, TGA_RAMDAC_SETUP_REG); for (i = 0; i < 16; i++) { TGA_WRITE_REG(par, 0x00, TGA_RAMDAC_REG); TGA_WRITE_REG(par, 0x01, TGA_RAMDAC_REG); TGA_WRITE_REG(par, 0x00, TGA_RAMDAC_REG); } } /* Finally, enable video scan (and pray for the monitor... :-) */ TGA_WRITE_REG(par, TGA_VALID_VIDEO, TGA_VALID_REG); return 0; } #define DIFFCHECK(X) \ do { \ if (m <= 0x3f) { \ int delta = f - (TGA_PLL_BASE_FREQ * (X)) / (r << shift); \ if (delta < 0) \ delta = -delta; \ if (delta < min_diff) \ min_diff = delta, vm = m, va = a, vr = r; \ } \ } while (0) static void tgafb_set_pll(struct tga_par *par, int f) { int n, shift, base, min_diff, target; int r,a,m,vm = 34, va = 1, vr = 30; for (r = 0 ; r < 12 ; r++) TGA_WRITE_REG(par, !r, TGA_CLOCK_REG); if (f > TGA_PLL_MAX_FREQ) f = TGA_PLL_MAX_FREQ; if (f >= TGA_PLL_MAX_FREQ / 2) shift = 0; else if (f >= TGA_PLL_MAX_FREQ / 4) shift = 1; else shift = 2; TGA_WRITE_REG(par, shift & 1, TGA_CLOCK_REG); TGA_WRITE_REG(par, shift >> 1, TGA_CLOCK_REG); for (r = 0 ; r < 10 ; r++) TGA_WRITE_REG(par, 0, TGA_CLOCK_REG); if (f <= 120000) { TGA_WRITE_REG(par, 0, TGA_CLOCK_REG); TGA_WRITE_REG(par, 0, TGA_CLOCK_REG); } else if (f <= 200000) { TGA_WRITE_REG(par, 1, TGA_CLOCK_REG); TGA_WRITE_REG(par, 0, TGA_CLOCK_REG); } else { TGA_WRITE_REG(par, 0, TGA_CLOCK_REG); TGA_WRITE_REG(par, 1, TGA_CLOCK_REG); } TGA_WRITE_REG(par, 1, TGA_CLOCK_REG); TGA_WRITE_REG(par, 0, TGA_CLOCK_REG); TGA_WRITE_REG(par, 0, TGA_CLOCK_REG); TGA_WRITE_REG(par, 1, TGA_CLOCK_REG); TGA_WRITE_REG(par, 0, TGA_CLOCK_REG); TGA_WRITE_REG(par, 1, TGA_CLOCK_REG); target = (f << shift) / TGA_PLL_BASE_FREQ; min_diff = TGA_PLL_MAX_FREQ; r = 7 / target; if (!r) r = 1; base = target * r; while (base < 449) { for (n = base < 7 ? 7 : base; n < base + target && n < 449; n++) { m = ((n + 3) / 7) - 1; a = 0; DIFFCHECK((m + 1) * 7); m++; DIFFCHECK((m + 1) * 7); m = (n / 6) - 1; if ((a = n % 6)) DIFFCHECK(n); }