linux/drivers/video/igafb.c
<<
>>
Prefs
   1/*
   2 *  linux/drivers/video/igafb.c -- Frame buffer device for IGA 1682
   3 *
   4 *      Copyright (C) 1998  Vladimir Roganov and Gleb Raiko
   5 *
   6 *  This driver is partly based on the Frame buffer device for ATI Mach64
   7 *  and partially on VESA-related code.
   8 *
   9 *      Copyright (C) 1997-1998  Geert Uytterhoeven
  10 *      Copyright (C) 1998  Bernd Harries
  11 *      Copyright (C) 1998  Eddie C. Dost  (ecd@skynet.be)
  12 *
  13 *  This file is subject to the terms and conditions of the GNU General Public
  14 *  License. See the file COPYING in the main directory of this archive for
  15 *  more details.
  16 */
  17
  18/******************************************************************************
  19
  20  TODO:
  21       Despite of IGA Card has advanced graphic acceleration, 
  22       initial version is almost dummy and does not support it.
  23       Support for video modes and acceleration must be added
  24       together with accelerated X-Windows driver implementation.
  25
  26       Most important thing at this moment is that we have working
  27       JavaEngine1  console & X  with new console interface.
  28
  29******************************************************************************/
  30
  31#include <linux/module.h>
  32#include <linux/kernel.h>
  33#include <linux/errno.h>
  34#include <linux/string.h>
  35#include <linux/mm.h>
  36#include <linux/slab.h>
  37#include <linux/vmalloc.h>
  38#include <linux/delay.h>
  39#include <linux/interrupt.h>
  40#include <linux/fb.h>
  41#include <linux/init.h>
  42#include <linux/pci.h>
  43#include <linux/nvram.h>
  44
  45#include <asm/io.h>
  46
  47#ifdef CONFIG_SPARC
  48#include <asm/prom.h>
  49#include <asm/pcic.h>
  50#endif
  51
  52#include <video/iga.h>
  53
  54struct pci_mmap_map {
  55    unsigned long voff;
  56    unsigned long poff;
  57    unsigned long size;
  58    unsigned long prot_flag;
  59    unsigned long prot_mask;
  60};
  61
  62struct iga_par {
  63        struct pci_mmap_map *mmap_map;
  64        unsigned long frame_buffer_phys;
  65        unsigned long io_base;
  66};
  67
  68struct fb_info fb_info;
  69
  70struct fb_fix_screeninfo igafb_fix __initdata = {
  71        .id             = "IGA 1682",
  72        .type           = FB_TYPE_PACKED_PIXELS,
  73        .mmio_len       = 1000
  74};
  75
  76struct fb_var_screeninfo default_var = {
  77        /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */
  78        .xres           = 640,
  79        .yres           = 480,
  80        .xres_virtual   = 640,
  81        .yres_virtual   = 480,
  82        .bits_per_pixel = 8,
  83        .red            = {0, 8, 0 },
  84        .green          = {0, 8, 0 },
  85        .blue           = {0, 8, 0 },
  86        .height         = -1,
  87        .width          = -1,
  88        .accel_flags    = FB_ACCEL_NONE,
  89        .pixclock       = 39722,
  90        .left_margin    = 48,
  91        .right_margin   = 16,
  92        .upper_margin   = 33,
  93        .lower_margin   = 10,
  94        .hsync_len      = 96,
  95        .vsync_len      = 2,
  96        .vmode          = FB_VMODE_NONINTERLACED
  97};
  98
  99#ifdef CONFIG_SPARC
 100struct fb_var_screeninfo default_var_1024x768 __initdata = {
 101        /* 1024x768, 75 Hz, Non-Interlaced (78.75 MHz dotclock) */
 102        .xres           = 1024,
 103        .yres           = 768,
 104        .xres_virtual   = 1024,
 105        .yres_virtual   = 768,
 106        .bits_per_pixel = 8,
 107        .red            = {0, 8, 0 },
 108        .green          = {0, 8, 0 },
 109        .blue           = {0, 8, 0 },
 110        .height         = -1,
 111        .width          = -1,
 112        .accel_flags    = FB_ACCEL_NONE,
 113        .pixclock       = 12699,
 114        .left_margin    = 176,
 115        .right_margin   = 16,
 116        .upper_margin   = 28,
 117        .lower_margin   = 1,
 118        .hsync_len      = 96,
 119        .vsync_len      = 3,
 120        .vmode          = FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
 121};
 122
 123struct fb_var_screeninfo default_var_1152x900 __initdata = {
 124        /* 1152x900, 76 Hz, Non-Interlaced (110.0 MHz dotclock) */
 125        .xres           = 1152,
 126        .yres           = 900,
 127        .xres_virtual   = 1152,
 128        .yres_virtual   = 900,
 129        .bits_per_pixel = 8,
 130        .red            = { 0, 8, 0 },
 131        .green          = { 0, 8, 0 },
 132        .blue           = { 0, 8, 0 },
 133        .height         = -1,
 134        .width          = -1,
 135        .accel_flags    = FB_ACCEL_NONE,
 136        .pixclock       = 9091,
 137        .left_margin    = 234,
 138        .right_margin   = 24,
 139        .upper_margin   = 34,
 140        .lower_margin   = 3,
 141        .hsync_len      = 100,
 142        .vsync_len      = 3,
 143        .vmode          = FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
 144};
 145
 146struct fb_var_screeninfo default_var_1280x1024 __initdata = {
 147        /* 1280x1024, 75 Hz, Non-Interlaced (135.00 MHz dotclock) */
 148        .xres           = 1280,
 149        .yres           = 1024,
 150        .xres_virtual   = 1280,
 151        .yres_virtual   = 1024,
 152        .bits_per_pixel = 8,
 153        .red            = {0, 8, 0 }, 
 154        .green          = {0, 8, 0 },
 155        .blue           = {0, 8, 0 },
 156        .height         = -1,
 157        .width          = -1,
 158        .accel_flags    = 0,
 159        .pixclock       = 7408,
 160        .left_margin    = 248,
 161        .right_margin   = 16,
 162        .upper_margin   = 38,
 163        .lower_margin   = 1,
 164        .hsync_len      = 144,
 165        .vsync_len      = 3,
 166        .vmode          = FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
 167};
 168
 169/*
 170 *   Memory-mapped I/O functions for Sparc PCI
 171 *
 172 * On sparc we happen to access I/O with memory mapped functions too.
 173 */ 
 174#define pci_inb(par, reg)        readb(par->io_base+(reg))
 175#define pci_outb(par, val, reg)  writeb(val, par->io_base+(reg))
 176
 177static inline unsigned int iga_inb(struct iga_par *par, unsigned int reg,
 178                                   unsigned int idx)
 179{
 180        pci_outb(par, idx, reg);
 181        return pci_inb(par, reg + 1);
 182}
 183
 184static inline void iga_outb(struct iga_par *par, unsigned char val,
 185                            unsigned int reg, unsigned int idx )
 186{
 187        pci_outb(par, idx, reg);
 188        pci_outb(par, val, reg+1);
 189}
 190
 191#endif /* CONFIG_SPARC */
 192
 193/*
 194 *  Very important functionality for the JavaEngine1 computer:
 195 *  make screen border black (usign special IGA registers) 
 196 */
 197static void iga_blank_border(struct iga_par *par)
 198{
 199        int i;
 200#if 0
 201        /*
 202         * PROM does this for us, so keep this code as a reminder
 203         * about required read from 0x3DA and writing of 0x20 in the end.
 204         */
 205        (void) pci_inb(par, 0x3DA);             /* required for every access */
 206        pci_outb(par, IGA_IDX_VGA_OVERSCAN, IGA_ATTR_CTL);
 207        (void) pci_inb(par, IGA_ATTR_CTL+1);
 208        pci_outb(par, 0x38, IGA_ATTR_CTL);
 209        pci_outb(par, 0x20, IGA_ATTR_CTL);      /* re-enable visual */
 210#endif
 211        /*
 212         * This does not work as it was designed because the overscan
 213         * color is looked up in the palette. Therefore, under X11
 214         * overscan changes color.
 215         */
 216        for (i=0; i < 3; i++)
 217                iga_outb(par, 0, IGA_EXT_CNTRL, IGA_IDX_OVERSCAN_COLOR + i);
 218}
 219
 220#ifdef CONFIG_SPARC
 221static int igafb_mmap(struct fb_info *info,
 222                      struct vm_area_struct *vma)
 223{
 224        struct iga_par *par = (struct iga_par *)info->par;
 225        unsigned int size, page, map_size = 0;
 226        unsigned long map_offset = 0;
 227        int i;
 228
 229        if (!par->mmap_map)
 230                return -ENXIO;
 231
 232        size = vma->vm_end - vma->vm_start;
 233
 234        /* Each page, see which map applies */
 235        for (page = 0; page < size; ) {
 236                map_size = 0;
 237                for (i = 0; par->mmap_map[i].size; i++) {
 238                        unsigned long start = par->mmap_map[i].voff;
 239                        unsigned long end = start + par->mmap_map[i].size;
 240                        unsigned long offset = (vma->vm_pgoff << PAGE_SHIFT) + page;
 241
 242                        if (start > offset)
 243                                continue;
 244                        if (offset >= end)
 245                                continue;
 246
 247                        map_size = par->mmap_map[i].size - (offset - start);
 248                        map_offset = par->mmap_map[i].poff + (offset - start);
 249                        break;
 250                }
 251                if (!map_size) {
 252                        page += PAGE_SIZE;
 253                        continue;
 254                }
 255                if (page + map_size > size)
 256                        map_size = size - page;
 257
 258                pgprot_val(vma->vm_page_prot) &= ~(par->mmap_map[i].prot_mask);
 259                pgprot_val(vma->vm_page_prot) |= par->mmap_map[i].prot_flag;
 260
 261                if (remap_pfn_range(vma, vma->vm_start + page,
 262                        map_offset >> PAGE_SHIFT, map_size, vma->vm_page_prot))
 263                        return -EAGAIN;
 264
 265                page += map_size;
 266        }
 267
 268        if (!map_size)
 269                return -EINVAL;
 270
 271        vma->vm_flags |= VM_IO;
 272        return 0;
 273}
 274#endif /* CONFIG_SPARC */
 275
 276static int igafb_setcolreg(unsigned regno, unsigned red, unsigned green,
 277                           unsigned blue, unsigned transp,
 278                           struct fb_info *info)
 279{
 280        /*
 281         *  Set a single color register. The values supplied are
 282         *  already rounded down to the hardware's capabilities
 283         *  (according to the entries in the `var' structure). Return
 284         *  != 0 for invalid regno.
 285         */
 286        struct iga_par *par = (struct iga_par *)info->par;
 287
 288        if (regno >= info->cmap.len)
 289                return 1;
 290
 291        pci_outb(par, regno, DAC_W_INDEX);
 292        pci_outb(par, red,   DAC_DATA);
 293        pci_outb(par, green, DAC_DATA);
 294        pci_outb(par, blue,  DAC_DATA);
 295
 296        if (regno < 16) {
 297                switch (info->var.bits_per_pixel) {
 298                case 16:
 299                        ((u16*)(info->pseudo_palette))[regno] = 
 300                                (regno << 10) | (regno << 5) | regno;
 301                        break;
 302                case 24:
 303                        ((u32*)(info->pseudo_palette))[regno] = 
 304                                (regno << 16) | (regno << 8) | regno;
 305                break;
 306                case 32:
 307                        { int i;
 308                        i = (regno << 8) | regno;
 309                        ((u32*)(info->pseudo_palette))[regno] = (i << 16) | i;
 310                        }
 311                        break;
 312                }
 313        }
 314        return 0;
 315}
 316
 317/*
 318 * Framebuffer option structure
 319 */
 320static struct fb_ops igafb_ops = {
 321        .owner          = THIS_MODULE,
 322        .fb_setcolreg   = igafb_setcolreg,
 323        .fb_fillrect    = cfb_fillrect,
 324        .fb_copyarea    = cfb_copyarea,
 325        .fb_imageblit   = cfb_imageblit,
 326#ifdef CONFIG_SPARC
 327        .fb_mmap        = igafb_mmap,
 328#endif
 329};
 330
 331static int __init iga_init(struct fb_info *info, struct iga_par *par)
 332{
 333        char vramsz = iga_inb(par, IGA_EXT_CNTRL, IGA_IDX_EXT_BUS_CNTL) 
 334                                                         & MEM_SIZE_ALIAS;
 335        int video_cmap_len;
 336
 337        switch (vramsz) {
 338        case MEM_SIZE_1M:
 339                info->fix.smem_len = 0x100000;
 340                break;
 341        case MEM_SIZE_2M:
 342                info->fix.smem_len = 0x200000;
 343                break;
 344        case MEM_SIZE_4M:
 345        case MEM_SIZE_RESERVED:
 346                info->fix.smem_len = 0x400000;
 347                break;
 348        }
 349
 350        if (info->var.bits_per_pixel > 8) 
 351                video_cmap_len = 16;
 352        else 
 353                video_cmap_len = 256;
 354
 355        info->fbops = &igafb_ops;
 356        info->flags = FBINFO_DEFAULT;
 357
 358        fb_alloc_cmap(&info->cmap, video_cmap_len, 0);
 359
 360        if (register_framebuffer(info) < 0)
 361                return 0;
 362
 363        printk("fb%d: %s frame buffer device at 0x%08lx [%dMB VRAM]\n",
 364               info->node, info->fix.id, 
 365               par->frame_buffer_phys, info->fix.smem_len >> 20);
 366
 367        iga_blank_border(par); 
 368        return 1;
 369}
 370
 371static int __init igafb_init(void)
 372{
 373        struct fb_info *info;
 374        struct pci_dev *pdev;
 375        struct iga_par *par;
 376        unsigned long addr;
 377        int size, iga2000 = 0;
 378
 379        if (fb_get_options("igafb", NULL))
 380                return -ENODEV;
 381
 382        pdev = pci_get_device(PCI_VENDOR_ID_INTERG,
 383                               PCI_DEVICE_ID_INTERG_1682, 0);
 384        if (pdev == NULL) {
 385                /*
 386                 * XXX We tried to use cyber2000fb.c for IGS 2000.
 387                 * But it does not initialize the chip in JavaStation-E, alas.
 388                 */
 389                pdev = pci_get_device(PCI_VENDOR_ID_INTERG, 0x2000, 0);
 390                if(pdev == NULL) {
 391                        return -ENXIO;
 392                }
 393                iga2000 = 1;
 394        }
 395        /* We leak a reference here but as it cannot be unloaded this is
 396           fine. If you write unload code remember to free it in unload */
 397        
 398        size = sizeof(struct iga_par) + sizeof(u32)*16;
 399
 400        info = framebuffer_alloc(size, &pdev->dev);
 401        if (!info) {
 402                printk("igafb_init: can't alloc fb_info\n");
 403                 pci_dev_put(pdev);
 404                return -ENOMEM;
 405        }
 406
 407        par = info->par;
 408
 409        if ((addr = pdev->resource[0].start) == 0) {
 410                printk("igafb_init: no memory start\n");
 411                kfree(info);
 412                pci_dev_put(pdev);
 413                return -ENXIO;
 414        }
 415
 416        if ((info->screen_base = ioremap(addr, 1024*1024*2)) == 0) {
 417                printk("igafb_init: can't remap %lx[2M]\n", addr);
 418                kfree(info);
 419                pci_dev_put(pdev);
 420                return -ENXIO;
 421        }
 422
 423        par->frame_buffer_phys = addr & PCI_BASE_ADDRESS_MEM_MASK;
 424
 425#ifdef CONFIG_SPARC
 426        /*
 427         * The following is sparc specific and this is why:
 428         *
 429         * IGS2000 has its I/O memory mapped and we want
 430         * to generate memory cycles on PCI, e.g. do ioremap(),
 431         * then readb/writeb() as in Documentation/io-mapping.txt.
 432         *
 433         * IGS1682 is more traditional, it responds to PCI I/O
 434         * cycles, so we want to access it with inb()/outb().
 435         *
 436         * On sparc, PCIC converts CPU memory access within
 437         * phys window 0x3000xxxx into PCI I/O cycles. Therefore
 438         * we may use readb/writeb to access them with IGS1682.
 439         *
 440         * We do not take io_base_phys from resource[n].start
 441         * on IGS1682 because that chip is BROKEN. It does not
 442         * have a base register for I/O. We just "know" what its
 443         * I/O addresses are.
 444         */
 445        if (iga2000) {
 446                igafb_fix.mmio_start = par->frame_buffer_phys | 0x00800000;
 447        } else {
 448                igafb_fix.mmio_start = 0x30000000;      /* XXX */
 449        }
 450        if ((par->io_base = (int) ioremap(igafb_fix.mmio_start, igafb_fix.smem_len)) == 0) {
 451                printk("igafb_init: can't remap %lx[4K]\n", igafb_fix.mmio_start);
 452                iounmap((void *)info->screen_base);
 453                kfree(info);
 454                pci_dev_put(pdev);
 455                return -ENXIO;
 456        }
 457
 458        /*
 459         * Figure mmap addresses from PCI config space.
 460         * We need two regions: for video memory and for I/O ports.
 461         * Later one can add region for video coprocessor registers.
 462         * However, mmap routine loops until size != 0, so we put
 463         * one additional region with size == 0. 
 464         */
 465
 466        par->mmap_map = kzalloc(4 * sizeof(*par->mmap_map), GFP_ATOMIC);
 467        if (!par->mmap_map) {
 468                printk("igafb_init: can't alloc mmap_map\n");
 469                iounmap((void *)par->io_base);
 470                iounmap(info->screen_base);
 471                kfree(info);
 472                pci_dev_put(pdev);
 473                return -ENOMEM;
 474        }
 475
 476        /*
 477         * Set default vmode and cmode from PROM properties.
 478         */
 479        {
 480                struct device_node *dp = pci_device_to_OF_node(pdev);
 481                int node = dp->node;
 482                int width = prom_getintdefault(node, "width", 1024);
 483                int height = prom_getintdefault(node, "height", 768);
 484                int depth = prom_getintdefault(node, "depth", 8);
 485                switch (width) {
 486                    case 1024:
 487                        if (height == 768)
 488                            default_var = default_var_1024x768;
 489                        break;
 490                    case 1152:
 491                        if (height == 900)
 492                            default_var = default_var_1152x900;
 493                        break;
 494                    case 1280:
 495                        if (height == 1024)
 496                            default_var = default_var_1280x1024;
 497                        break;
 498                    default:
 499                        break;
 500                }
 501
 502                switch (depth) {
 503                    case 8:
 504                        default_var.bits_per_pixel = 8;
 505                        break;
 506                    case 16:
 507                        default_var.bits_per_pixel = 16;
 508                        break;
 509                    case 24:
 510                        default_var.bits_per_pixel = 24;
 511                        break;
 512                    case 32:
 513                        default_var.bits_per_pixel = 32;
 514                        break;
 515                    default:
 516                        break;
 517                }
 518            }
 519
 520#endif
 521        igafb_fix.smem_start = (unsigned long) info->screen_base;
 522        igafb_fix.line_length = default_var.xres*(default_var.bits_per_pixel/8);
 523        igafb_fix.visual = default_var.bits_per_pixel <= 8 ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
 524
 525        info->var = default_var;
 526        info->fix = igafb_fix;
 527        info->pseudo_palette = (void *)(par + 1);
 528
 529        if (!iga_init(info, par)) {
 530                iounmap((void *)par->io_base);
 531                iounmap(info->screen_base);
 532                kfree(par->mmap_map);
 533                kfree(info);
 534                return -ENODEV;
 535        }
 536
 537#ifdef CONFIG_SPARC
 538            /*
 539             * Add /dev/fb mmap values.
 540             */
 541            
 542            /* First region is for video memory */
 543            par->mmap_map[0].voff = 0x0;  
 544            par->mmap_map[0].poff = par->frame_buffer_phys & PAGE_MASK;
 545            par->mmap_map[0].size = info->fix.smem_len & PAGE_MASK;
 546            par->mmap_map[0].prot_mask = SRMMU_CACHE;
 547            par->mmap_map[0].prot_flag = SRMMU_WRITE;
 548
 549            /* Second region is for I/O ports */
 550            par->mmap_map[1].voff = par->frame_buffer_phys & PAGE_MASK;
 551            par->mmap_map[1].poff = info->fix.smem_start & PAGE_MASK;
 552            par->mmap_map[1].size = PAGE_SIZE * 2; /* X wants 2 pages */
 553            par->mmap_map[1].prot_mask = SRMMU_CACHE;
 554            par->mmap_map[1].prot_flag = SRMMU_WRITE;
 555#endif /* CONFIG_SPARC */
 556
 557        return 0;
 558}
 559
 560static int __init igafb_setup(char *options)
 561{
 562    char *this_opt;
 563
 564    if (!options || !*options)
 565        return 0;
 566
 567    while ((this_opt = strsep(&options, ",")) != NULL) {
 568    }
 569    return 0;
 570}
 571
 572module_init(igafb_init);
 573MODULE_LICENSE("GPL");
 574static struct pci_device_id igafb_pci_tbl[] = {
 575        { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_1682,
 576          PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 577        { }
 578};
 579
 580MODULE_DEVICE_TABLE(pci, igafb_pci_tbl);
 581
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.