root/drivers/video/fbdev/sunxvr500.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. e3d_get_props
  2. e3d_clut_write
  3. e3d_setcolreg
  4. e3d_imageblit
  5. e3d_fillrect
  6. e3d_copyarea
  7. e3d_set_fbinfo
  8. e3d_pci_register
  9. e3d_init

   1 /* sunxvr500.c: Sun 3DLABS XVR-500 Expert3D fb driver for sparc64 systems
   2  *
   3  * License: GPL
   4  *
   5  * Copyright (C) 2007 David S. Miller (davem@davemloft.net)
   6  */
   7 
   8 #include <linux/kernel.h>
   9 #include <linux/fb.h>
  10 #include <linux/pci.h>
  11 #include <linux/init.h>
  12 #include <linux/of_device.h>
  13 
  14 #include <asm/io.h>
  15 
  16 /* XXX This device has a 'dev-comm' property which apparently is
  17  * XXX a pointer into the openfirmware's address space which is
  18  * XXX a shared area the kernel driver can use to keep OBP
  19  * XXX informed about the current resolution setting.  The idea
  20  * XXX is that the kernel can change resolutions, and as long
  21  * XXX as the values in the 'dev-comm' area are accurate then
  22  * XXX OBP can still render text properly to the console.
  23  * XXX
  24  * XXX I'm still working out the layout of this and whether there
  25  * XXX are any signatures we need to look for etc.
  26  */
  27 struct e3d_info {
  28         struct fb_info          *info;
  29         struct pci_dev          *pdev;
  30 
  31         spinlock_t              lock;
  32 
  33         char __iomem            *fb_base;
  34         unsigned long           fb_base_phys;
  35 
  36         unsigned long           fb8_buf_diff;
  37         unsigned long           regs_base_phys;
  38 
  39         void __iomem            *ramdac;
  40 
  41         struct device_node      *of_node;
  42 
  43         unsigned int            width;
  44         unsigned int            height;
  45         unsigned int            depth;
  46         unsigned int            fb_size;
  47 
  48         u32                     fb_base_reg;
  49         u32                     fb8_0_off;
  50         u32                     fb8_1_off;
  51 
  52         u32                     pseudo_palette[16];
  53 };
  54 
  55 static int e3d_get_props(struct e3d_info *ep)
  56 {
  57         ep->width = of_getintprop_default(ep->of_node, "width", 0);
  58         ep->height = of_getintprop_default(ep->of_node, "height", 0);
  59         ep->depth = of_getintprop_default(ep->of_node, "depth", 8);
  60 
  61         if (!ep->width || !ep->height) {
  62                 printk(KERN_ERR "e3d: Critical properties missing for %s\n",
  63                        pci_name(ep->pdev));
  64                 return -EINVAL;
  65         }
  66 
  67         return 0;
  68 }
  69 
  70 /* My XVR-500 comes up, at 1280x768 and a FB base register value of
  71  * 0x04000000, the following video layout register values:
  72  *
  73  * RAMDAC_VID_WH        0x03ff04ff
  74  * RAMDAC_VID_CFG       0x1a0b0088
  75  * RAMDAC_VID_32FB_0    0x04000000
  76  * RAMDAC_VID_32FB_1    0x04800000
  77  * RAMDAC_VID_8FB_0     0x05000000
  78  * RAMDAC_VID_8FB_1     0x05200000
  79  * RAMDAC_VID_XXXFB     0x05400000
  80  * RAMDAC_VID_YYYFB     0x05c00000
  81  * RAMDAC_VID_ZZZFB     0x05e00000
  82  */
  83 /* Video layout registers */
  84 #define RAMDAC_VID_WH           0x00000070UL /* (height-1)<<16 | (width-1) */
  85 #define RAMDAC_VID_CFG          0x00000074UL /* 0x1a000088|(linesz_log2<<16) */
  86 #define RAMDAC_VID_32FB_0       0x00000078UL /* PCI base 32bpp FB buffer 0 */
  87 #define RAMDAC_VID_32FB_1       0x0000007cUL /* PCI base 32bpp FB buffer 1 */
  88 #define RAMDAC_VID_8FB_0        0x00000080UL /* PCI base 8bpp FB buffer 0 */
  89 #define RAMDAC_VID_8FB_1        0x00000084UL /* PCI base 8bpp FB buffer 1 */
  90 #define RAMDAC_VID_XXXFB        0x00000088UL /* PCI base of XXX FB */
  91 #define RAMDAC_VID_YYYFB        0x0000008cUL /* PCI base of YYY FB */
  92 #define RAMDAC_VID_ZZZFB        0x00000090UL /* PCI base of ZZZ FB */
  93 
  94 /* CLUT registers */
  95 #define RAMDAC_INDEX            0x000000bcUL
  96 #define RAMDAC_DATA             0x000000c0UL
  97 
  98 static void e3d_clut_write(struct e3d_info *ep, int index, u32 val)
  99 {
 100         void __iomem *ramdac = ep->ramdac;
 101         unsigned long flags;
 102 
 103         spin_lock_irqsave(&ep->lock, flags);
 104 
 105         writel(index, ramdac + RAMDAC_INDEX);
 106         writel(val, ramdac + RAMDAC_DATA);
 107 
 108         spin_unlock_irqrestore(&ep->lock, flags);
 109 }
 110 
 111 static int e3d_setcolreg(unsigned regno,
 112                          unsigned red, unsigned green, unsigned blue,
 113                          unsigned transp, struct fb_info *info)
 114 {
 115         struct e3d_info *ep = info->par;
 116         u32 red_8, green_8, blue_8;
 117         u32 red_10, green_10, blue_10;
 118         u32 value;
 119 
 120         if (regno >= 256)
 121                 return 1;
 122 
 123         red_8 = red >> 8;
 124         green_8 = green >> 8;
 125         blue_8 = blue >> 8;
 126 
 127         value = (blue_8 << 24) | (green_8 << 16) | (red_8 << 8);
 128 
 129         if (info->fix.visual == FB_VISUAL_TRUECOLOR && regno < 16)
 130                 ((u32 *)info->pseudo_palette)[regno] = value;
 131 
 132 
 133         red_10 = red >> 6;
 134         green_10 = green >> 6;
 135         blue_10 = blue >> 6;
 136 
 137         value = (blue_10 << 20) | (green_10 << 10) | (red_10 << 0);
 138         e3d_clut_write(ep, regno, value);
 139 
 140         return 0;
 141 }
 142 
 143 /* XXX This is a bit of a hack.  I can't figure out exactly how the
 144  * XXX two 8bpp areas of the framebuffer work.  I imagine there is
 145  * XXX a WID attribute somewhere else in the framebuffer which tells
 146  * XXX the ramdac which of the two 8bpp framebuffer regions to take
 147  * XXX the pixel from.  So, for now, render into both regions to make
 148  * XXX sure the pixel shows up.
 149  */
 150 static void e3d_imageblit(struct fb_info *info, const struct fb_image *image)
 151 {
 152         struct e3d_info *ep = info->par;
 153         unsigned long flags;
 154 
 155         spin_lock_irqsave(&ep->lock, flags);
 156         cfb_imageblit(info, image);
 157         info->screen_base += ep->fb8_buf_diff;
 158         cfb_imageblit(info, image);
 159         info->screen_base -= ep->fb8_buf_diff;
 160         spin_unlock_irqrestore(&ep->lock, flags);
 161 }
 162 
 163 static void e3d_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
 164 {
 165         struct e3d_info *ep = info->par;
 166         unsigned long flags;
 167 
 168         spin_lock_irqsave(&ep->lock, flags);
 169         cfb_fillrect(info, rect);
 170         info->screen_base += ep->fb8_buf_diff;
 171         cfb_fillrect(info, rect);
 172         info->screen_base -= ep->fb8_buf_diff;
 173         spin_unlock_irqrestore(&ep->lock, flags);
 174 }
 175 
 176 static void e3d_copyarea(struct fb_info *info, const struct fb_copyarea *area)
 177 {
 178         struct e3d_info *ep = info->par;
 179         unsigned long flags;
 180 
 181         spin_lock_irqsave(&ep->lock, flags);
 182         cfb_copyarea(info, area);
 183         info->screen_base += ep->fb8_buf_diff;
 184         cfb_copyarea(info, area);
 185         info->screen_base -= ep->fb8_buf_diff;
 186         spin_unlock_irqrestore(&ep->lock, flags);
 187 }
 188 
 189 static struct fb_ops e3d_ops = {
 190         .owner                  = THIS_MODULE,
 191         .fb_setcolreg           = e3d_setcolreg,
 192         .fb_fillrect            = e3d_fillrect,
 193         .fb_copyarea            = e3d_copyarea,
 194         .fb_imageblit           = e3d_imageblit,
 195 };
 196 
 197 static int e3d_set_fbinfo(struct e3d_info *ep)
 198 {
 199         struct fb_info *info = ep->info;
 200         struct fb_var_screeninfo *var = &info->var;
 201 
 202         info->flags = FBINFO_DEFAULT;
 203         info->fbops = &e3d_ops;
 204         info->screen_base = ep->fb_base;
 205         info->screen_size = ep->fb_size;
 206 
 207         info->pseudo_palette = ep->pseudo_palette;
 208 
 209         /* Fill fix common fields */
 210         strlcpy(info->fix.id, "e3d", sizeof(info->fix.id));
 211         info->fix.smem_start = ep->fb_base_phys;
 212         info->fix.smem_len = ep->fb_size;
 213         info->fix.type = FB_TYPE_PACKED_PIXELS;
 214         if (ep->depth == 32 || ep->depth == 24)
 215                 info->fix.visual = FB_VISUAL_TRUECOLOR;
 216         else
 217                 info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
 218 
 219         var->xres = ep->width;
 220         var->yres = ep->height;
 221         var->xres_virtual = var->xres;
 222         var->yres_virtual = var->yres;
 223         var->bits_per_pixel = ep->depth;
 224 
 225         var->red.offset = 8;
 226         var->red.length = 8;
 227         var->green.offset = 16;
 228         var->green.length = 8;
 229         var->blue.offset = 24;
 230         var->blue.length = 8;
 231         var->transp.offset = 0;
 232         var->transp.length = 0;
 233 
 234         if (fb_alloc_cmap(&info->cmap, 256, 0)) {
 235                 printk(KERN_ERR "e3d: Cannot allocate color map.\n");
 236                 return -ENOMEM;
 237         }
 238 
 239         return 0;
 240 }
 241 
 242 static int e3d_pci_register(struct pci_dev *pdev,
 243                             const struct pci_device_id *ent)
 244 {
 245         struct device_node *of_node;
 246         const char *device_type;
 247         struct fb_info *info;
 248         struct e3d_info *ep;
 249         unsigned int line_length;
 250         int err;
 251 
 252         of_node = pci_device_to_OF_node(pdev);
 253         if (!of_node) {
 254                 printk(KERN_ERR "e3d: Cannot find OF node of %s\n",
 255                        pci_name(pdev));
 256                 return -ENODEV;
 257         }
 258 
 259         device_type = of_get_property(of_node, "device_type", NULL);
 260         if (!device_type) {
 261                 printk(KERN_INFO "e3d: Ignoring secondary output device "
 262                        "at %s\n", pci_name(pdev));
 263                 return -ENODEV;
 264         }
 265 
 266         err = pci_enable_device(pdev);
 267         if (err < 0) {
 268                 printk(KERN_ERR "e3d: Cannot enable PCI device %s\n",
 269                        pci_name(pdev));
 270                 goto err_out;
 271         }
 272 
 273         info = framebuffer_alloc(sizeof(struct e3d_info), &pdev->dev);
 274         if (!info) {
 275                 err = -ENOMEM;
 276                 goto err_disable;
 277         }
 278 
 279         ep = info->par;
 280         ep->info = info;
 281         ep->pdev = pdev;
 282         spin_lock_init(&ep->lock);
 283         ep->of_node = of_node;
 284 
 285         /* Read the PCI base register of the frame buffer, which we
 286          * need in order to interpret the RAMDAC_VID_*FB* values in
 287          * the ramdac correctly.
 288          */
 289         pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0,
 290                               &ep->fb_base_reg);
 291         ep->fb_base_reg &= PCI_BASE_ADDRESS_MEM_MASK;
 292 
 293         ep->regs_base_phys = pci_resource_start (pdev, 1);
 294         err = pci_request_region(pdev, 1, "e3d regs");
 295         if (err < 0) {
 296                 printk("e3d: Cannot request region 1 for %s\n",
 297                        pci_name(pdev));
 298                 goto err_release_fb;
 299         }
 300         ep->ramdac = ioremap(ep->regs_base_phys + 0x8000, 0x1000);
 301         if (!ep->ramdac) {
 302                 err = -ENOMEM;
 303                 goto err_release_pci1;
 304         }
 305 
 306         ep->fb8_0_off = readl(ep->ramdac + RAMDAC_VID_8FB_0);
 307         ep->fb8_0_off -= ep->fb_base_reg;
 308 
 309         ep->fb8_1_off = readl(ep->ramdac + RAMDAC_VID_8FB_1);
 310         ep->fb8_1_off -= ep->fb_base_reg;
 311 
 312         ep->fb8_buf_diff = ep->fb8_1_off - ep->fb8_0_off;
 313 
 314         ep->fb_base_phys = pci_resource_start (pdev, 0);
 315         ep->fb_base_phys += ep->fb8_0_off;
 316 
 317         err = pci_request_region(pdev, 0, "e3d framebuffer");
 318         if (err < 0) {
 319                 printk("e3d: Cannot request region 0 for %s\n",
 320                        pci_name(pdev));
 321                 goto err_unmap_ramdac;
 322         }
 323 
 324         err = e3d_get_props(ep);
 325         if (err)
 326                 goto err_release_pci0;
 327 
 328         line_length = (readl(ep->ramdac + RAMDAC_VID_CFG) >> 16) & 0xff;
 329         line_length = 1 << line_length;
 330 
 331         switch (ep->depth) {
 332         case 8:
 333                 info->fix.line_length = line_length;
 334                 break;
 335         case 16:
 336                 info->fix.line_length = line_length * 2;
 337                 break;
 338         case 24:
 339                 info->fix.line_length = line_length * 3;
 340                 break;
 341         case 32:
 342                 info->fix.line_length = line_length * 4;
 343                 break;
 344         }
 345         ep->fb_size = info->fix.line_length * ep->height;
 346 
 347         ep->fb_base = ioremap(ep->fb_base_phys, ep->fb_size);
 348         if (!ep->fb_base) {
 349                 err = -ENOMEM;
 350                 goto err_release_pci0;
 351         }
 352 
 353         err = e3d_set_fbinfo(ep);
 354         if (err)
 355                 goto err_unmap_fb;
 356 
 357         pci_set_drvdata(pdev, info);
 358 
 359         printk("e3d: Found device at %s\n", pci_name(pdev));
 360 
 361         err = register_framebuffer(info);
 362         if (err < 0) {
 363                 printk(KERN_ERR "e3d: Could not register framebuffer %s\n",
 364                        pci_name(pdev));
 365                 goto err_free_cmap;
 366         }
 367 
 368         return 0;
 369 
 370 err_free_cmap:
 371         fb_dealloc_cmap(&info->cmap);
 372 
 373 err_unmap_fb:
 374         iounmap(ep->fb_base);
 375 
 376 err_release_pci0:
 377         pci_release_region(pdev, 0);
 378 
 379 err_unmap_ramdac:
 380         iounmap(ep->ramdac);
 381 
 382 err_release_pci1:
 383         pci_release_region(pdev, 1);
 384 
 385 err_release_fb:
 386         framebuffer_release(info);
 387 
 388 err_disable:
 389         pci_disable_device(pdev);
 390 
 391 err_out:
 392         return err;
 393 }
 394 
 395 static const struct pci_device_id e3d_pci_table[] = {
 396         {       PCI_DEVICE(PCI_VENDOR_ID_3DLABS, 0x7a0),        },
 397         {       PCI_DEVICE(0x1091, 0x7a0),                      },
 398         {       PCI_DEVICE(PCI_VENDOR_ID_3DLABS, 0x7a2),        },
 399         {       .vendor = PCI_VENDOR_ID_3DLABS,
 400                 .device = PCI_ANY_ID,
 401                 .subvendor = PCI_VENDOR_ID_3DLABS,
 402                 .subdevice = 0x0108,
 403         },
 404         {       .vendor = PCI_VENDOR_ID_3DLABS,
 405                 .device = PCI_ANY_ID,
 406                 .subvendor = PCI_VENDOR_ID_3DLABS,
 407                 .subdevice = 0x0140,
 408         },
 409         {       .vendor = PCI_VENDOR_ID_3DLABS,
 410                 .device = PCI_ANY_ID,
 411                 .subvendor = PCI_VENDOR_ID_3DLABS,
 412                 .subdevice = 0x1024,
 413         },
 414         { 0, }
 415 };
 416 
 417 static struct pci_driver e3d_driver = {
 418         .driver = {
 419                 .suppress_bind_attrs = true,
 420         },
 421         .name           = "e3d",
 422         .id_table       = e3d_pci_table,
 423         .probe          = e3d_pci_register,
 424 };
 425 
 426 static int __init e3d_init(void)
 427 {
 428         if (fb_get_options("e3d", NULL))
 429                 return -ENODEV;
 430 
 431         return pci_register_driver(&e3d_driver);
 432 }
 433 device_initcall(e3d_init);

/* [<][>][^][v][top][bottom][index][help] */