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