Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /* bw2.c: BWTWO frame buffer driver
0003  *
0004  * Copyright (C) 2003, 2006 David S. Miller (davem@davemloft.net)
0005  * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
0006  * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
0007  * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
0008  *
0009  * Driver layout based loosely on tgafb.c, see that file for credits.
0010  */
0011 
0012 #include <linux/module.h>
0013 #include <linux/kernel.h>
0014 #include <linux/errno.h>
0015 #include <linux/string.h>
0016 #include <linux/delay.h>
0017 #include <linux/init.h>
0018 #include <linux/fb.h>
0019 #include <linux/mm.h>
0020 #include <linux/of_device.h>
0021 
0022 #include <asm/io.h>
0023 #include <asm/fbio.h>
0024 
0025 #include "sbuslib.h"
0026 
0027 /*
0028  * Local functions.
0029  */
0030 
0031 static int bw2_blank(int, struct fb_info *);
0032 
0033 static int bw2_mmap(struct fb_info *, struct vm_area_struct *);
0034 static int bw2_ioctl(struct fb_info *, unsigned int, unsigned long);
0035 
0036 /*
0037  *  Frame buffer operations
0038  */
0039 
0040 static const struct fb_ops bw2_ops = {
0041     .owner          = THIS_MODULE,
0042     .fb_blank       = bw2_blank,
0043     .fb_fillrect        = cfb_fillrect,
0044     .fb_copyarea        = cfb_copyarea,
0045     .fb_imageblit       = cfb_imageblit,
0046     .fb_mmap        = bw2_mmap,
0047     .fb_ioctl       = bw2_ioctl,
0048 #ifdef CONFIG_COMPAT
0049     .fb_compat_ioctl    = sbusfb_compat_ioctl,
0050 #endif
0051 };
0052 
0053 /* OBio addresses for the bwtwo registers */
0054 #define BWTWO_REGISTER_OFFSET 0x400000
0055 
0056 struct bt_regs {
0057     u32 addr;
0058     u32 color_map;
0059     u32 control;
0060     u32 cursor;
0061 };
0062 
0063 struct bw2_regs {
0064     struct bt_regs  cmap;
0065     u8  control;
0066     u8  status;
0067     u8  cursor_start;
0068     u8  cursor_end;
0069     u8  h_blank_start;
0070     u8  h_blank_end;
0071     u8  h_sync_start;
0072     u8  h_sync_end;
0073     u8  comp_sync_end;
0074     u8  v_blank_start_high;
0075     u8  v_blank_start_low;
0076     u8  v_blank_end;
0077     u8  v_sync_start;
0078     u8  v_sync_end;
0079     u8  xfer_holdoff_start;
0080     u8  xfer_holdoff_end;
0081 };
0082 
0083 /* Status Register Constants */
0084 #define BWTWO_SR_RES_MASK   0x70
0085 #define BWTWO_SR_1600_1280  0x50
0086 #define BWTWO_SR_1152_900_76_A  0x40
0087 #define BWTWO_SR_1152_900_76_B  0x60
0088 #define BWTWO_SR_ID_MASK    0x0f
0089 #define BWTWO_SR_ID_MONO    0x02
0090 #define BWTWO_SR_ID_MONO_ECL    0x03
0091 #define BWTWO_SR_ID_MSYNC   0x04
0092 #define BWTWO_SR_ID_NOCONN  0x0a
0093 
0094 /* Control Register Constants */
0095 #define BWTWO_CTL_ENABLE_INTS   0x80
0096 #define BWTWO_CTL_ENABLE_VIDEO  0x40
0097 #define BWTWO_CTL_ENABLE_TIMING 0x20
0098 #define BWTWO_CTL_ENABLE_CURCMP 0x10
0099 #define BWTWO_CTL_XTAL_MASK     0x0C
0100 #define BWTWO_CTL_DIVISOR_MASK  0x03
0101 
0102 /* Status Register Constants */
0103 #define BWTWO_STAT_PENDING_INT  0x80
0104 #define BWTWO_STAT_MSENSE_MASK  0x70
0105 #define BWTWO_STAT_ID_MASK      0x0f
0106 
0107 struct bw2_par {
0108     spinlock_t      lock;
0109     struct bw2_regs     __iomem *regs;
0110 
0111     u32         flags;
0112 #define BW2_FLAG_BLANKED    0x00000001
0113 
0114     unsigned long       which_io;
0115 };
0116 
0117 /**
0118  *      bw2_blank - Optional function.  Blanks the display.
0119  *      @blank: the blank mode we want.
0120  *      @info: frame buffer structure that represents a single frame buffer
0121  */
0122 static int
0123 bw2_blank(int blank, struct fb_info *info)
0124 {
0125     struct bw2_par *par = (struct bw2_par *) info->par;
0126     struct bw2_regs __iomem *regs = par->regs;
0127     unsigned long flags;
0128     u8 val;
0129 
0130     spin_lock_irqsave(&par->lock, flags);
0131 
0132     switch (blank) {
0133     case FB_BLANK_UNBLANK: /* Unblanking */
0134         val = sbus_readb(&regs->control);
0135         val |= BWTWO_CTL_ENABLE_VIDEO;
0136         sbus_writeb(val, &regs->control);
0137         par->flags &= ~BW2_FLAG_BLANKED;
0138         break;
0139 
0140     case FB_BLANK_NORMAL: /* Normal blanking */
0141     case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */
0142     case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */
0143     case FB_BLANK_POWERDOWN: /* Poweroff */
0144         val = sbus_readb(&regs->control);
0145         val &= ~BWTWO_CTL_ENABLE_VIDEO;
0146         sbus_writeb(val, &regs->control);
0147         par->flags |= BW2_FLAG_BLANKED;
0148         break;
0149     }
0150 
0151     spin_unlock_irqrestore(&par->lock, flags);
0152 
0153     return 0;
0154 }
0155 
0156 static struct sbus_mmap_map bw2_mmap_map[] = {
0157     {
0158         .size = SBUS_MMAP_FBSIZE(1)
0159     },
0160     { .size = 0 }
0161 };
0162 
0163 static int bw2_mmap(struct fb_info *info, struct vm_area_struct *vma)
0164 {
0165     struct bw2_par *par = (struct bw2_par *)info->par;
0166 
0167     return sbusfb_mmap_helper(bw2_mmap_map,
0168                   info->fix.smem_start, info->fix.smem_len,
0169                   par->which_io,
0170                   vma);
0171 }
0172 
0173 static int bw2_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
0174 {
0175     return sbusfb_ioctl_helper(cmd, arg, info,
0176                    FBTYPE_SUN2BW, 1, info->fix.smem_len);
0177 }
0178 
0179 /*
0180  *  Initialisation
0181  */
0182 
0183 static void bw2_init_fix(struct fb_info *info, int linebytes)
0184 {
0185     strscpy(info->fix.id, "bwtwo", sizeof(info->fix.id));
0186 
0187     info->fix.type = FB_TYPE_PACKED_PIXELS;
0188     info->fix.visual = FB_VISUAL_MONO01;
0189 
0190     info->fix.line_length = linebytes;
0191 
0192     info->fix.accel = FB_ACCEL_SUN_BWTWO;
0193 }
0194 
0195 static u8 bw2regs_1600[] = {
0196     0x14, 0x8b, 0x15, 0x28, 0x16, 0x03, 0x17, 0x13,
0197     0x18, 0x7b, 0x19, 0x05, 0x1a, 0x34, 0x1b, 0x2e,
0198     0x1c, 0x00, 0x1d, 0x0a, 0x1e, 0xff, 0x1f, 0x01,
0199     0x10, 0x21, 0
0200 };
0201 
0202 static u8 bw2regs_ecl[] = {
0203     0x14, 0x65, 0x15, 0x1e, 0x16, 0x04, 0x17, 0x0c,
0204     0x18, 0x5e, 0x19, 0x03, 0x1a, 0xa7, 0x1b, 0x23,
0205     0x1c, 0x00, 0x1d, 0x08, 0x1e, 0xff, 0x1f, 0x01,
0206     0x10, 0x20, 0
0207 };
0208 
0209 static u8 bw2regs_analog[] = {
0210     0x14, 0xbb, 0x15, 0x2b, 0x16, 0x03, 0x17, 0x13,
0211     0x18, 0xb0, 0x19, 0x03, 0x1a, 0xa6, 0x1b, 0x22,
0212     0x1c, 0x01, 0x1d, 0x05, 0x1e, 0xff, 0x1f, 0x01,
0213     0x10, 0x20, 0
0214 };
0215 
0216 static u8 bw2regs_76hz[] = {
0217     0x14, 0xb7, 0x15, 0x27, 0x16, 0x03, 0x17, 0x0f,
0218     0x18, 0xae, 0x19, 0x03, 0x1a, 0xae, 0x1b, 0x2a,
0219     0x1c, 0x01, 0x1d, 0x09, 0x1e, 0xff, 0x1f, 0x01,
0220     0x10, 0x24, 0
0221 };
0222 
0223 static u8 bw2regs_66hz[] = {
0224     0x14, 0xbb, 0x15, 0x2b, 0x16, 0x04, 0x17, 0x14,
0225     0x18, 0xae, 0x19, 0x03, 0x1a, 0xa8, 0x1b, 0x24,
0226     0x1c, 0x01, 0x1d, 0x05, 0x1e, 0xff, 0x1f, 0x01,
0227     0x10, 0x20, 0
0228 };
0229 
0230 static int bw2_do_default_mode(struct bw2_par *par, struct fb_info *info,
0231                    int *linebytes)
0232 {
0233     u8 status, mon;
0234     u8 *p;
0235 
0236     status = sbus_readb(&par->regs->status);
0237     mon = status & BWTWO_SR_RES_MASK;
0238     switch (status & BWTWO_SR_ID_MASK) {
0239     case BWTWO_SR_ID_MONO_ECL:
0240         if (mon == BWTWO_SR_1600_1280) {
0241             p = bw2regs_1600;
0242             info->var.xres = info->var.xres_virtual = 1600;
0243             info->var.yres = info->var.yres_virtual = 1280;
0244             *linebytes = 1600 / 8;
0245         } else
0246             p = bw2regs_ecl;
0247         break;
0248 
0249     case BWTWO_SR_ID_MONO:
0250         p = bw2regs_analog;
0251         break;
0252 
0253     case BWTWO_SR_ID_MSYNC:
0254         if (mon == BWTWO_SR_1152_900_76_A ||
0255             mon == BWTWO_SR_1152_900_76_B)
0256             p = bw2regs_76hz;
0257         else
0258             p = bw2regs_66hz;
0259         break;
0260 
0261     case BWTWO_SR_ID_NOCONN:
0262         return 0;
0263 
0264     default:
0265         printk(KERN_ERR "bw2: can't handle SR %02x\n",
0266                status);
0267         return -EINVAL;
0268     }
0269     for ( ; *p; p += 2) {
0270         u8 __iomem *regp = &((u8 __iomem *)par->regs)[p[0]];
0271         sbus_writeb(p[1], regp);
0272     }
0273     return 0;
0274 }
0275 
0276 static int bw2_probe(struct platform_device *op)
0277 {
0278     struct device_node *dp = op->dev.of_node;
0279     struct fb_info *info;
0280     struct bw2_par *par;
0281     int linebytes, err;
0282 
0283     info = framebuffer_alloc(sizeof(struct bw2_par), &op->dev);
0284 
0285     err = -ENOMEM;
0286     if (!info)
0287         goto out_err;
0288     par = info->par;
0289 
0290     spin_lock_init(&par->lock);
0291 
0292     info->fix.smem_start = op->resource[0].start;
0293     par->which_io = op->resource[0].flags & IORESOURCE_BITS;
0294 
0295     sbusfb_fill_var(&info->var, dp, 1);
0296     linebytes = of_getintprop_default(dp, "linebytes",
0297                       info->var.xres);
0298 
0299     info->var.red.length = info->var.green.length =
0300         info->var.blue.length = info->var.bits_per_pixel;
0301     info->var.red.offset = info->var.green.offset =
0302         info->var.blue.offset = 0;
0303 
0304     par->regs = of_ioremap(&op->resource[0], BWTWO_REGISTER_OFFSET,
0305                    sizeof(struct bw2_regs), "bw2 regs");
0306     if (!par->regs)
0307         goto out_release_fb;
0308 
0309     if (!of_find_property(dp, "width", NULL)) {
0310         err = bw2_do_default_mode(par, info, &linebytes);
0311         if (err)
0312             goto out_unmap_regs;
0313     }
0314 
0315     info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres);
0316 
0317     info->flags = FBINFO_DEFAULT;
0318     info->fbops = &bw2_ops;
0319 
0320     info->screen_base = of_ioremap(&op->resource[0], 0,
0321                        info->fix.smem_len, "bw2 ram");
0322     if (!info->screen_base) {
0323         err = -ENOMEM;
0324         goto out_unmap_regs;
0325     }
0326 
0327     bw2_blank(FB_BLANK_UNBLANK, info);
0328 
0329     bw2_init_fix(info, linebytes);
0330 
0331     err = register_framebuffer(info);
0332     if (err < 0)
0333         goto out_unmap_screen;
0334 
0335     dev_set_drvdata(&op->dev, info);
0336 
0337     printk(KERN_INFO "%pOF: bwtwo at %lx:%lx\n",
0338            dp, par->which_io, info->fix.smem_start);
0339 
0340     return 0;
0341 
0342 out_unmap_screen:
0343     of_iounmap(&op->resource[0], info->screen_base, info->fix.smem_len);
0344 
0345 out_unmap_regs:
0346     of_iounmap(&op->resource[0], par->regs, sizeof(struct bw2_regs));
0347 
0348 out_release_fb:
0349     framebuffer_release(info);
0350 
0351 out_err:
0352     return err;
0353 }
0354 
0355 static int bw2_remove(struct platform_device *op)
0356 {
0357     struct fb_info *info = dev_get_drvdata(&op->dev);
0358     struct bw2_par *par = info->par;
0359 
0360     unregister_framebuffer(info);
0361 
0362     of_iounmap(&op->resource[0], par->regs, sizeof(struct bw2_regs));
0363     of_iounmap(&op->resource[0], info->screen_base, info->fix.smem_len);
0364 
0365     framebuffer_release(info);
0366 
0367     return 0;
0368 }
0369 
0370 static const struct of_device_id bw2_match[] = {
0371     {
0372         .name = "bwtwo",
0373     },
0374     {},
0375 };
0376 MODULE_DEVICE_TABLE(of, bw2_match);
0377 
0378 static struct platform_driver bw2_driver = {
0379     .driver = {
0380         .name = "bw2",
0381         .of_match_table = bw2_match,
0382     },
0383     .probe      = bw2_probe,
0384     .remove     = bw2_remove,
0385 };
0386 
0387 static int __init bw2_init(void)
0388 {
0389     if (fb_get_options("bw2fb", NULL))
0390         return -ENODEV;
0391 
0392     return platform_driver_register(&bw2_driver);
0393 }
0394 
0395 static void __exit bw2_exit(void)
0396 {
0397     platform_driver_unregister(&bw2_driver);
0398 }
0399 
0400 module_init(bw2_init);
0401 module_exit(bw2_exit);
0402 
0403 MODULE_DESCRIPTION("framebuffer driver for BWTWO chipsets");
0404 MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
0405 MODULE_VERSION("2.0");
0406 MODULE_LICENSE("GPL");