linux/drivers/video/p9100.c
<<
>>
Prefs
   1/* p9100.c: P9100 frame buffer driver
   2 *
   3 * Copyright (C) 2003, 2006 David S. Miller (davem@davemloft.net)
   4 * Copyright 1999 Derrick J Brashear (shadow@dementia.org)
   5 *
   6 * Driver layout based loosely on tgafb.c, see that file for credits.
   7 */
   8
   9#include <linux/module.h>
  10#include <linux/kernel.h>
  11#include <linux/errno.h>
  12#include <linux/string.h>
  13#include <linux/delay.h>
  14#include <linux/init.h>
  15#include <linux/fb.h>
  16#include <linux/mm.h>
  17#include <linux/of_device.h>
  18
  19#include <asm/io.h>
  20#include <asm/fbio.h>
  21
  22#include "sbuslib.h"
  23
  24/*
  25 * Local functions.
  26 */
  27
  28static int p9100_setcolreg(unsigned, unsigned, unsigned, unsigned,
  29                           unsigned, struct fb_info *);
  30static int p9100_blank(int, struct fb_info *);
  31
  32static int p9100_mmap(struct fb_info *, struct vm_area_struct *);
  33static int p9100_ioctl(struct fb_info *, unsigned int, unsigned long);
  34
  35/*
  36 *  Frame buffer operations
  37 */
  38
  39static struct fb_ops p9100_ops = {
  40        .owner                  = THIS_MODULE,
  41        .fb_setcolreg           = p9100_setcolreg,
  42        .fb_blank               = p9100_blank,
  43        .fb_fillrect            = cfb_fillrect,
  44        .fb_copyarea            = cfb_copyarea,
  45        .fb_imageblit           = cfb_imageblit,
  46        .fb_mmap                = p9100_mmap,
  47        .fb_ioctl               = p9100_ioctl,
  48#ifdef CONFIG_COMPAT
  49        .fb_compat_ioctl        = sbusfb_compat_ioctl,
  50#endif
  51};
  52
  53/* P9100 control registers */
  54#define P9100_SYSCTL_OFF        0x0UL
  55#define P9100_VIDEOCTL_OFF      0x100UL
  56#define P9100_VRAMCTL_OFF       0x180UL
  57#define P9100_RAMDAC_OFF        0x200UL
  58#define P9100_VIDEOCOPROC_OFF   0x400UL
  59
  60/* P9100 command registers */
  61#define P9100_CMD_OFF 0x0UL
  62
  63/* P9100 framebuffer memory */
  64#define P9100_FB_OFF 0x0UL
  65
  66/* 3 bits: 2=8bpp 3=16bpp 5=32bpp 7=24bpp */
  67#define SYS_CONFIG_PIXELSIZE_SHIFT 26 
  68
  69#define SCREENPAINT_TIMECTL1_ENABLE_VIDEO 0x20 /* 0 = off, 1 = on */
  70
  71struct p9100_regs {
  72        /* Registers for the system control */
  73        u32 sys_base;
  74        u32 sys_config;
  75        u32 sys_intr;
  76        u32 sys_int_ena;
  77        u32 sys_alt_rd;
  78        u32 sys_alt_wr;
  79        u32 sys_xxx[58];
  80
  81        /* Registers for the video control */
  82        u32 vid_base;
  83        u32 vid_hcnt;
  84        u32 vid_htotal;
  85        u32 vid_hsync_rise;
  86        u32 vid_hblank_rise;
  87        u32 vid_hblank_fall;
  88        u32 vid_hcnt_preload;
  89        u32 vid_vcnt;
  90        u32 vid_vlen;
  91        u32 vid_vsync_rise;
  92        u32 vid_vblank_rise;
  93        u32 vid_vblank_fall;
  94        u32 vid_vcnt_preload;
  95        u32 vid_screenpaint_addr;
  96        u32 vid_screenpaint_timectl1;
  97        u32 vid_screenpaint_qsfcnt;
  98        u32 vid_screenpaint_timectl2;
  99        u32 vid_xxx[15];
 100
 101        /* Registers for the video control */
 102        u32 vram_base;
 103        u32 vram_memcfg;
 104        u32 vram_refresh_pd;
 105        u32 vram_refresh_cnt;
 106        u32 vram_raslo_max;
 107        u32 vram_raslo_cur;
 108        u32 pwrup_cfg;
 109        u32 vram_xxx[25];
 110
 111        /* Registers for IBM RGB528 Palette */
 112        u32 ramdac_cmap_wridx; 
 113        u32 ramdac_palette_data;
 114        u32 ramdac_pixel_mask;
 115        u32 ramdac_palette_rdaddr;
 116        u32 ramdac_idx_lo;
 117        u32 ramdac_idx_hi;
 118        u32 ramdac_idx_data;
 119        u32 ramdac_idx_ctl;
 120        u32 ramdac_xxx[1784];
 121};
 122
 123struct p9100_cmd_parameng {
 124        u32 parameng_status;
 125        u32 parameng_bltcmd;
 126        u32 parameng_quadcmd;
 127};
 128
 129struct p9100_par {
 130        spinlock_t              lock;
 131        struct p9100_regs       __iomem *regs;
 132
 133        u32                     flags;
 134#define P9100_FLAG_BLANKED      0x00000001
 135
 136        unsigned long           which_io;
 137};
 138
 139/**
 140 *      p9100_setcolreg - Optional function. Sets a color register.
 141 *      @regno: boolean, 0 copy local, 1 get_user() function
 142 *      @red: frame buffer colormap structure
 143 *      @green: The green value which can be up to 16 bits wide
 144 *      @blue:  The blue value which can be up to 16 bits wide.
 145 *      @transp: If supported the alpha value which can be up to 16 bits wide.
 146 *      @info: frame buffer info structure
 147 */
 148static int p9100_setcolreg(unsigned regno,
 149                           unsigned red, unsigned green, unsigned blue,
 150                           unsigned transp, struct fb_info *info)
 151{
 152        struct p9100_par *par = (struct p9100_par *) info->par;
 153        struct p9100_regs __iomem *regs = par->regs;
 154        unsigned long flags;
 155
 156        if (regno >= 256)
 157                return 1;
 158
 159        red >>= 8;
 160        green >>= 8;
 161        blue >>= 8;
 162
 163        spin_lock_irqsave(&par->lock, flags);
 164
 165        sbus_writel((regno << 16), &regs->ramdac_cmap_wridx);
 166        sbus_writel((red << 16), &regs->ramdac_palette_data);
 167        sbus_writel((green << 16), &regs->ramdac_palette_data);
 168        sbus_writel((blue << 16), &regs->ramdac_palette_data);
 169
 170        spin_unlock_irqrestore(&par->lock, flags);
 171
 172        return 0;
 173}
 174
 175/**
 176 *      p9100_blank - Optional function.  Blanks the display.
 177 *      @blank_mode: the blank mode we want.
 178 *      @info: frame buffer structure that represents a single frame buffer
 179 */
 180static int
 181p9100_blank(int blank, struct fb_info *info)
 182{
 183        struct p9100_par *par = (struct p9100_par *) info->par;
 184        struct p9100_regs __iomem *regs = par->regs;
 185        unsigned long flags;
 186        u32 val;
 187
 188        spin_lock_irqsave(&par->lock, flags);
 189
 190        switch (blank) {
 191        case FB_BLANK_UNBLANK: /* Unblanking */
 192                val = sbus_readl(&regs->vid_screenpaint_timectl1);
 193                val |= SCREENPAINT_TIMECTL1_ENABLE_VIDEO;
 194                sbus_writel(val, &regs->vid_screenpaint_timectl1);
 195                par->flags &= ~P9100_FLAG_BLANKED;
 196                break;
 197
 198        case FB_BLANK_NORMAL: /* Normal blanking */
 199        case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */
 200        case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */
 201        case FB_BLANK_POWERDOWN: /* Poweroff */
 202                val = sbus_readl(&regs->vid_screenpaint_timectl1);
 203                val &= ~SCREENPAINT_TIMECTL1_ENABLE_VIDEO;
 204                sbus_writel(val, &regs->vid_screenpaint_timectl1);
 205                par->flags |= P9100_FLAG_BLANKED;
 206                break;
 207        }
 208
 209        spin_unlock_irqrestore(&par->lock, flags);
 210
 211        return 0;
 212}
 213
 214static struct sbus_mmap_map p9100_mmap_map[] = {
 215        { CG3_MMAP_OFFSET,      0,              SBUS_MMAP_FBSIZE(1) },
 216        { 0,                    0,              0                   }
 217};
 218
 219static int p9100_mmap(struct fb_info *info, struct vm_area_struct *vma)
 220{
 221        struct p9100_par *par = (struct p9100_par *)info->par;
 222
 223        return sbusfb_mmap_helper(p9100_mmap_map,
 224                                  info->fix.smem_start, info->fix.smem_len,
 225                                  par->which_io, vma);
 226}
 227
 228static int p9100_ioctl(struct fb_info *info, unsigned int cmd,
 229                       unsigned long arg)
 230{
 231        /* Make it look like a cg3. */
 232        return sbusfb_ioctl_helper(cmd, arg, info,
 233                                   FBTYPE_SUN3COLOR, 8, info->fix.smem_len);
 234}
 235
 236/*
 237 *  Initialisation
 238 */
 239
 240static void p9100_init_fix(struct fb_info *info, int linebytes, struct device_node *dp)
 241{
 242        strlcpy(info->fix.id, dp->name, sizeof(info->fix.id));
 243
 244        info->fix.type = FB_TYPE_PACKED_PIXELS;
 245        info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
 246
 247        info->fix.line_length = linebytes;
 248
 249        info->fix.accel = FB_ACCEL_SUN_CGTHREE;
 250}
 251
 252static int __devinit p9100_probe(struct platform_device *op, const struct of_device_id *match)
 253{
 254        struct device_node *dp = op->dev.of_node;
 255        struct fb_info *info;
 256        struct p9100_par *par;
 257        int linebytes, err;
 258
 259        info = framebuffer_alloc(sizeof(struct p9100_par), &op->dev);
 260
 261        err = -ENOMEM;
 262        if (!info)
 263                goto out_err;
 264        par = info->par;
 265
 266        spin_lock_init(&par->lock);
 267
 268        /* This is the framebuffer and the only resource apps can mmap.  */
 269        info->fix.smem_start = op->resource[2].start;
 270        par->which_io = op->resource[2].flags & IORESOURCE_BITS;
 271
 272        sbusfb_fill_var(&info->var, dp, 8);
 273        info->var.red.length = 8;
 274        info->var.green.length = 8;
 275        info->var.blue.length = 8;
 276
 277        linebytes = of_getintprop_default(dp, "linebytes", info->var.xres);
 278        info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres);
 279
 280        par->regs = of_ioremap(&op->resource[0], 0,
 281                               sizeof(struct p9100_regs), "p9100 regs");
 282        if (!par->regs)
 283                goto out_release_fb;
 284
 285        info->flags = FBINFO_DEFAULT;
 286        info->fbops = &p9100_ops;
 287        info->screen_base = of_ioremap(&op->resource[2], 0,
 288                                       info->fix.smem_len, "p9100 ram");
 289        if (!info->screen_base)
 290                goto out_unmap_regs;
 291
 292        p9100_blank(FB_BLANK_UNBLANK, info);
 293
 294        if (fb_alloc_cmap(&info->cmap, 256, 0))
 295                goto out_unmap_screen;
 296
 297        p9100_init_fix(info, linebytes, dp);
 298
 299        err = register_framebuffer(info);
 300        if (err < 0)
 301                goto out_dealloc_cmap;
 302
 303        fb_set_cmap(&info->cmap, info);
 304
 305        dev_set_drvdata(&op->dev, info);
 306
 307        printk(KERN_INFO "%s: p9100 at %lx:%lx\n",
 308               dp->full_name,
 309               par->which_io, info->fix.smem_start);
 310
 311        return 0;
 312
 313out_dealloc_cmap:
 314        fb_dealloc_cmap(&info->cmap);
 315
 316out_unmap_screen:
 317        of_iounmap(&op->resource[2], info->screen_base, info->fix.smem_len);
 318
 319out_unmap_regs:
 320        of_iounmap(&op->resource[0], par->regs, sizeof(struct p9100_regs));
 321
 322out_release_fb:
 323        framebuffer_release(info);
 324
 325out_err:
 326        return err;
 327}
 328
 329static int __devexit p9100_remove(struct platform_device *op)
 330{
 331        struct fb_info *info = dev_get_drvdata(&op->dev);
 332        struct p9100_par *par = info->par;
 333
 334        unregister_framebuffer(info);
 335        fb_dealloc_cmap(&info->cmap);
 336
 337        of_iounmap(&op->resource[0], par->regs, sizeof(struct p9100_regs));
 338        of_iounmap(&op->resource[2], info->screen_base, info->fix.smem_len);
 339
 340        framebuffer_release(info);
 341
 342        dev_set_drvdata(&op->dev, NULL);
 343
 344        return 0;
 345}
 346
 347static const struct of_device_id p9100_match[] = {
 348        {
 349                .name = "p9100",
 350        },
 351        {},
 352};
 353MODULE_DEVICE_TABLE(of, p9100_match);
 354
 355static struct of_platform_driver p9100_driver = {
 356        .driver = {
 357                .name = "p9100",
 358                .owner = THIS_MODULE,
 359                .of_match_table = p9100_match,
 360        },
 361        .probe          = p9100_probe,
 362        .remove         = __devexit_p(p9100_remove),
 363};
 364
 365static int __init p9100_init(void)
 366{
 367        if (fb_get_options("p9100fb", NULL))
 368                return -ENODEV;
 369
 370        return of_register_platform_driver(&p9100_driver);
 371}
 372
 373static void __exit p9100_exit(void)
 374{
 375        of_unregister_platform_driver(&p9100_driver);
 376}
 377
 378module_init(p9100_init);
 379module_exit(p9100_exit);
 380
 381MODULE_DESCRIPTION("framebuffer driver for P9100 chipsets");
 382MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
 383MODULE_VERSION("2.0");
 384MODULE_LICENSE("GPL");
 385