0001
0002
0003
0004
0005
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
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
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);