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