^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /* sunxvr1000.c: Sun XVR-1000 fb driver for sparc64 systems
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * License: GPL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2010 David S. Miller (davem@davemloft.net)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/fb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/of_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) struct gfb_info {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) struct fb_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) char __iomem *fb_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) unsigned long fb_base_phys;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) struct device_node *of_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) unsigned int width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) unsigned int height;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) unsigned int depth;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) unsigned int fb_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) u32 pseudo_palette[16];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) static int gfb_get_props(struct gfb_info *gp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) gp->width = of_getintprop_default(gp->of_node, "width", 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) gp->height = of_getintprop_default(gp->of_node, "height", 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) gp->depth = of_getintprop_default(gp->of_node, "depth", 32);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) if (!gp->width || !gp->height) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) printk(KERN_ERR "gfb: Critical properties missing for %pOF\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) gp->of_node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) static int gfb_setcolreg(unsigned regno,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) unsigned red, unsigned green, unsigned blue,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) unsigned transp, struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) u32 value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) if (regno < 16) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) red >>= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) green >>= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) blue >>= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) value = (blue << 16) | (green << 8) | red;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) ((u32 *)info->pseudo_palette)[regno] = value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) static const struct fb_ops gfb_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) .fb_setcolreg = gfb_setcolreg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) .fb_fillrect = cfb_fillrect,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) .fb_copyarea = cfb_copyarea,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) .fb_imageblit = cfb_imageblit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) static int gfb_set_fbinfo(struct gfb_info *gp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) struct fb_info *info = gp->info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) struct fb_var_screeninfo *var = &info->var;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) info->flags = FBINFO_DEFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) info->fbops = &gfb_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) info->screen_base = gp->fb_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) info->screen_size = gp->fb_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) info->pseudo_palette = gp->pseudo_palette;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) /* Fill fix common fields */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) strlcpy(info->fix.id, "gfb", sizeof(info->fix.id));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) info->fix.smem_start = gp->fb_base_phys;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) info->fix.smem_len = gp->fb_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) info->fix.type = FB_TYPE_PACKED_PIXELS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) if (gp->depth == 32 || gp->depth == 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) info->fix.visual = FB_VISUAL_TRUECOLOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) var->xres = gp->width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) var->yres = gp->height;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) var->xres_virtual = var->xres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) var->yres_virtual = var->yres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) var->bits_per_pixel = gp->depth;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) var->red.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) var->red.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) var->green.offset = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) var->green.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) var->blue.offset = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) var->blue.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) var->transp.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) var->transp.length = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) if (fb_alloc_cmap(&info->cmap, 256, 0)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) printk(KERN_ERR "gfb: Cannot allocate color map.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) static int gfb_probe(struct platform_device *op)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) struct device_node *dp = op->dev.of_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) struct fb_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) struct gfb_info *gp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) info = framebuffer_alloc(sizeof(struct gfb_info), &op->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) if (!info) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) err = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) goto err_out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) gp = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) gp->info = info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) gp->of_node = dp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) gp->fb_base_phys = op->resource[6].start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) err = gfb_get_props(gp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) goto err_release_fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) /* Framebuffer length is the same regardless of resolution. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) info->fix.line_length = 16384;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) gp->fb_size = info->fix.line_length * gp->height;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) gp->fb_base = of_ioremap(&op->resource[6], 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) gp->fb_size, "gfb fb");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) if (!gp->fb_base) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) err = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) goto err_release_fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) err = gfb_set_fbinfo(gp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) goto err_unmap_fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) printk("gfb: Found device at %pOF\n", dp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) err = register_framebuffer(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) if (err < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) printk(KERN_ERR "gfb: Could not register framebuffer %pOF\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) dp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) goto err_unmap_fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) dev_set_drvdata(&op->dev, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) err_unmap_fb:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) of_iounmap(&op->resource[6], gp->fb_base, gp->fb_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) err_release_fb:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) framebuffer_release(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) err_out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) static const struct of_device_id gfb_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) .name = "SUNW,gfb",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) {},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) static struct platform_driver gfb_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) .probe = gfb_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) .name = "gfb",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) .of_match_table = gfb_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) .suppress_bind_attrs = true,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) static int __init gfb_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) if (fb_get_options("gfb", NULL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) return platform_driver_register(&gfb_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) device_initcall(gfb_init);