Back to home page

OSCL-LXR

 
 

    


0001 /* sunxvr1000.c: Sun XVR-1000 fb driver for sparc64 systems
0002  *
0003  * License: GPL
0004  *
0005  * Copyright (C) 2010 David S. Miller (davem@davemloft.net)
0006  */
0007 
0008 #include <linux/kernel.h>
0009 #include <linux/fb.h>
0010 #include <linux/init.h>
0011 #include <linux/of_device.h>
0012 
0013 struct gfb_info {
0014     struct fb_info      *info;
0015 
0016     char __iomem        *fb_base;
0017     unsigned long       fb_base_phys;
0018 
0019     struct device_node  *of_node;
0020 
0021     unsigned int        width;
0022     unsigned int        height;
0023     unsigned int        depth;
0024     unsigned int        fb_size;
0025 
0026     u32         pseudo_palette[16];
0027 };
0028 
0029 static int gfb_get_props(struct gfb_info *gp)
0030 {
0031     gp->width = of_getintprop_default(gp->of_node, "width", 0);
0032     gp->height = of_getintprop_default(gp->of_node, "height", 0);
0033     gp->depth = of_getintprop_default(gp->of_node, "depth", 32);
0034 
0035     if (!gp->width || !gp->height) {
0036         printk(KERN_ERR "gfb: Critical properties missing for %pOF\n",
0037                gp->of_node);
0038         return -EINVAL;
0039     }
0040 
0041     return 0;
0042 }
0043 
0044 static int gfb_setcolreg(unsigned regno,
0045              unsigned red, unsigned green, unsigned blue,
0046              unsigned transp, struct fb_info *info)
0047 {
0048     u32 value;
0049 
0050     if (regno < 16) {
0051         red >>= 8;
0052         green >>= 8;
0053         blue >>= 8;
0054 
0055         value = (blue << 16) | (green << 8) | red;
0056         ((u32 *)info->pseudo_palette)[regno] = value;
0057     }
0058 
0059     return 0;
0060 }
0061 
0062 static const struct fb_ops gfb_ops = {
0063     .owner          = THIS_MODULE,
0064     .fb_setcolreg       = gfb_setcolreg,
0065     .fb_fillrect        = cfb_fillrect,
0066     .fb_copyarea        = cfb_copyarea,
0067     .fb_imageblit       = cfb_imageblit,
0068 };
0069 
0070 static int gfb_set_fbinfo(struct gfb_info *gp)
0071 {
0072     struct fb_info *info = gp->info;
0073     struct fb_var_screeninfo *var = &info->var;
0074 
0075     info->flags = FBINFO_DEFAULT;
0076     info->fbops = &gfb_ops;
0077     info->screen_base = gp->fb_base;
0078     info->screen_size = gp->fb_size;
0079 
0080     info->pseudo_palette = gp->pseudo_palette;
0081 
0082     /* Fill fix common fields */
0083     strscpy(info->fix.id, "gfb", sizeof(info->fix.id));
0084         info->fix.smem_start = gp->fb_base_phys;
0085         info->fix.smem_len = gp->fb_size;
0086         info->fix.type = FB_TYPE_PACKED_PIXELS;
0087     if (gp->depth == 32 || gp->depth == 24)
0088         info->fix.visual = FB_VISUAL_TRUECOLOR;
0089     else
0090         info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
0091 
0092     var->xres = gp->width;
0093     var->yres = gp->height;
0094     var->xres_virtual = var->xres;
0095     var->yres_virtual = var->yres;
0096     var->bits_per_pixel = gp->depth;
0097 
0098     var->red.offset = 0;
0099     var->red.length = 8;
0100     var->green.offset = 8;
0101     var->green.length = 8;
0102     var->blue.offset = 16;
0103     var->blue.length = 8;
0104     var->transp.offset = 0;
0105     var->transp.length = 0;
0106 
0107     if (fb_alloc_cmap(&info->cmap, 256, 0)) {
0108         printk(KERN_ERR "gfb: Cannot allocate color map.\n");
0109         return -ENOMEM;
0110     }
0111 
0112         return 0;
0113 }
0114 
0115 static int gfb_probe(struct platform_device *op)
0116 {
0117     struct device_node *dp = op->dev.of_node;
0118     struct fb_info *info;
0119     struct gfb_info *gp;
0120     int err;
0121 
0122     info = framebuffer_alloc(sizeof(struct gfb_info), &op->dev);
0123     if (!info) {
0124         err = -ENOMEM;
0125         goto err_out;
0126     }
0127 
0128     gp = info->par;
0129     gp->info = info;
0130     gp->of_node = dp;
0131 
0132     gp->fb_base_phys = op->resource[6].start;
0133 
0134     err = gfb_get_props(gp);
0135     if (err)
0136         goto err_release_fb;
0137 
0138     /* Framebuffer length is the same regardless of resolution. */
0139     info->fix.line_length = 16384;
0140     gp->fb_size = info->fix.line_length * gp->height;
0141 
0142     gp->fb_base = of_ioremap(&op->resource[6], 0,
0143                  gp->fb_size, "gfb fb");
0144     if (!gp->fb_base) {
0145         err = -ENOMEM;
0146         goto err_release_fb;
0147     }
0148 
0149     err = gfb_set_fbinfo(gp);
0150     if (err)
0151         goto err_unmap_fb;
0152 
0153     printk("gfb: Found device at %pOF\n", dp);
0154 
0155     err = register_framebuffer(info);
0156     if (err < 0) {
0157         printk(KERN_ERR "gfb: Could not register framebuffer %pOF\n",
0158                dp);
0159         goto err_unmap_fb;
0160     }
0161 
0162     dev_set_drvdata(&op->dev, info);
0163 
0164     return 0;
0165 
0166 err_unmap_fb:
0167     of_iounmap(&op->resource[6], gp->fb_base, gp->fb_size);
0168 
0169 err_release_fb:
0170         framebuffer_release(info);
0171 
0172 err_out:
0173     return err;
0174 }
0175 
0176 static const struct of_device_id gfb_match[] = {
0177     {
0178         .name = "SUNW,gfb",
0179     },
0180     {},
0181 };
0182 
0183 static struct platform_driver gfb_driver = {
0184     .probe      = gfb_probe,
0185     .driver = {
0186         .name           = "gfb",
0187         .of_match_table     = gfb_match,
0188         .suppress_bind_attrs    = true,
0189     },
0190 };
0191 
0192 static int __init gfb_init(void)
0193 {
0194     if (fb_get_options("gfb", NULL))
0195         return -ENODEV;
0196 
0197     return platform_driver_register(&gfb_driver);
0198 }
0199 device_initcall(gfb_init);