Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  *  linux/drivers/video/pmag-ba-fb.c
0003  *
0004  *  PMAG-BA TURBOchannel Color Frame Buffer (CFB) card support,
0005  *  derived from:
0006  *  "HP300 Topcat framebuffer support (derived from macfb of all things)
0007  *  Phil Blundell <philb@gnu.org> 1998", the original code can be
0008  *  found in the file hpfb.c in the same directory.
0009  *
0010  *  Based on digital document:
0011  *  "PMAG-BA TURBOchannel Color Frame Buffer
0012  *   Functional Specification", Revision 1.2, August 27, 1990
0013  *
0014  *  DECstation related code Copyright (C) 1999, 2000, 2001 by
0015  *  Michael Engel <engel@unix-ag.org>,
0016  *  Karsten Merker <merker@linuxtag.org> and
0017  *  Harald Koerfgen.
0018  *  Copyright (c) 2005, 2006  Maciej W. Rozycki
0019  *  Copyright (c) 2005  James Simmons
0020  *
0021  *  This file is subject to the terms and conditions of the GNU General
0022  *  Public License.  See the file COPYING in the main directory of this
0023  *  archive for more details.
0024  */
0025 
0026 #include <linux/compiler.h>
0027 #include <linux/errno.h>
0028 #include <linux/fb.h>
0029 #include <linux/init.h>
0030 #include <linux/kernel.h>
0031 #include <linux/module.h>
0032 #include <linux/tc.h>
0033 #include <linux/types.h>
0034 
0035 #include <asm/io.h>
0036 
0037 #include <video/pmag-ba-fb.h>
0038 
0039 
0040 struct pmagbafb_par {
0041     volatile void __iomem *mmio;
0042     volatile u32 __iomem *dac;
0043 };
0044 
0045 
0046 static const struct fb_var_screeninfo pmagbafb_defined = {
0047     .xres       = 1024,
0048     .yres       = 864,
0049     .xres_virtual   = 1024,
0050     .yres_virtual   = 864,
0051     .bits_per_pixel = 8,
0052     .red.length = 8,
0053     .green.length   = 8,
0054     .blue.length    = 8,
0055     .activate   = FB_ACTIVATE_NOW,
0056     .height     = -1,
0057     .width      = -1,
0058     .accel_flags    = FB_ACCEL_NONE,
0059     .pixclock   = 14452,
0060     .left_margin    = 116,
0061     .right_margin   = 12,
0062     .upper_margin   = 34,
0063     .lower_margin   = 0,
0064     .hsync_len  = 128,
0065     .vsync_len  = 3,
0066     .sync       = FB_SYNC_ON_GREEN,
0067     .vmode      = FB_VMODE_NONINTERLACED,
0068 };
0069 
0070 static const struct fb_fix_screeninfo pmagbafb_fix = {
0071     .id     = "PMAG-BA",
0072     .smem_len   = (1024 * 1024),
0073     .type       = FB_TYPE_PACKED_PIXELS,
0074     .visual     = FB_VISUAL_PSEUDOCOLOR,
0075     .line_length    = 1024,
0076     .mmio_len   = PMAG_BA_SIZE - PMAG_BA_BT459,
0077 };
0078 
0079 
0080 static inline void dac_write(struct pmagbafb_par *par, unsigned int reg, u8 v)
0081 {
0082     writeb(v, par->dac + reg / 4);
0083 }
0084 
0085 static inline u8 dac_read(struct pmagbafb_par *par, unsigned int reg)
0086 {
0087     return readb(par->dac + reg / 4);
0088 }
0089 
0090 
0091 /*
0092  * Set the palette.
0093  */
0094 static int pmagbafb_setcolreg(unsigned int regno, unsigned int red,
0095                   unsigned int green, unsigned int blue,
0096                   unsigned int transp, struct fb_info *info)
0097 {
0098     struct pmagbafb_par *par = info->par;
0099 
0100     if (regno >= info->cmap.len)
0101         return 1;
0102 
0103     red   >>= 8;    /* The cmap fields are 16 bits    */
0104     green >>= 8;    /* wide, but the hardware colormap */
0105     blue  >>= 8;    /* registers are only 8 bits wide */
0106 
0107     mb();
0108     dac_write(par, BT459_ADDR_LO, regno);
0109     dac_write(par, BT459_ADDR_HI, 0x00);
0110     wmb();
0111     dac_write(par, BT459_CMAP, red);
0112     wmb();
0113     dac_write(par, BT459_CMAP, green);
0114     wmb();
0115     dac_write(par, BT459_CMAP, blue);
0116 
0117     return 0;
0118 }
0119 
0120 static const struct fb_ops pmagbafb_ops = {
0121     .owner      = THIS_MODULE,
0122     .fb_setcolreg   = pmagbafb_setcolreg,
0123     .fb_fillrect    = cfb_fillrect,
0124     .fb_copyarea    = cfb_copyarea,
0125     .fb_imageblit   = cfb_imageblit,
0126 };
0127 
0128 
0129 /*
0130  * Turn the hardware cursor off.
0131  */
0132 static void pmagbafb_erase_cursor(struct fb_info *info)
0133 {
0134     struct pmagbafb_par *par = info->par;
0135 
0136     mb();
0137     dac_write(par, BT459_ADDR_LO, 0x00);
0138     dac_write(par, BT459_ADDR_HI, 0x03);
0139     wmb();
0140     dac_write(par, BT459_DATA, 0x00);
0141 }
0142 
0143 
0144 static int pmagbafb_probe(struct device *dev)
0145 {
0146     struct tc_dev *tdev = to_tc_dev(dev);
0147     resource_size_t start, len;
0148     struct fb_info *info;
0149     struct pmagbafb_par *par;
0150     int err;
0151 
0152     info = framebuffer_alloc(sizeof(struct pmagbafb_par), dev);
0153     if (!info)
0154         return -ENOMEM;
0155 
0156     par = info->par;
0157     dev_set_drvdata(dev, info);
0158 
0159     if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
0160         printk(KERN_ERR "%s: Cannot allocate color map\n",
0161                dev_name(dev));
0162         err = -ENOMEM;
0163         goto err_alloc;
0164     }
0165 
0166     info->fbops = &pmagbafb_ops;
0167     info->fix = pmagbafb_fix;
0168     info->var = pmagbafb_defined;
0169     info->flags = FBINFO_DEFAULT;
0170 
0171     /* Request the I/O MEM resource.  */
0172     start = tdev->resource.start;
0173     len = tdev->resource.end - start + 1;
0174     if (!request_mem_region(start, len, dev_name(dev))) {
0175         printk(KERN_ERR "%s: Cannot reserve FB region\n",
0176                dev_name(dev));
0177         err = -EBUSY;
0178         goto err_cmap;
0179     }
0180 
0181     /* MMIO mapping setup.  */
0182     info->fix.mmio_start = start;
0183     par->mmio = ioremap(info->fix.mmio_start, info->fix.mmio_len);
0184     if (!par->mmio) {
0185         printk(KERN_ERR "%s: Cannot map MMIO\n", dev_name(dev));
0186         err = -ENOMEM;
0187         goto err_resource;
0188     }
0189     par->dac = par->mmio + PMAG_BA_BT459;
0190 
0191     /* Frame buffer mapping setup.  */
0192     info->fix.smem_start = start + PMAG_BA_FBMEM;
0193     info->screen_base = ioremap(info->fix.smem_start,
0194                         info->fix.smem_len);
0195     if (!info->screen_base) {
0196         printk(KERN_ERR "%s: Cannot map FB\n", dev_name(dev));
0197         err = -ENOMEM;
0198         goto err_mmio_map;
0199     }
0200     info->screen_size = info->fix.smem_len;
0201 
0202     pmagbafb_erase_cursor(info);
0203 
0204     err = register_framebuffer(info);
0205     if (err < 0) {
0206         printk(KERN_ERR "%s: Cannot register framebuffer\n",
0207                dev_name(dev));
0208         goto err_smem_map;
0209     }
0210 
0211     get_device(dev);
0212 
0213     fb_info(info, "%s frame buffer device at %s\n",
0214         info->fix.id, dev_name(dev));
0215 
0216     return 0;
0217 
0218 
0219 err_smem_map:
0220     iounmap(info->screen_base);
0221 
0222 err_mmio_map:
0223     iounmap(par->mmio);
0224 
0225 err_resource:
0226     release_mem_region(start, len);
0227 
0228 err_cmap:
0229     fb_dealloc_cmap(&info->cmap);
0230 
0231 err_alloc:
0232     framebuffer_release(info);
0233     return err;
0234 }
0235 
0236 static int pmagbafb_remove(struct device *dev)
0237 {
0238     struct tc_dev *tdev = to_tc_dev(dev);
0239     struct fb_info *info = dev_get_drvdata(dev);
0240     struct pmagbafb_par *par = info->par;
0241     resource_size_t start, len;
0242 
0243     put_device(dev);
0244     unregister_framebuffer(info);
0245     iounmap(info->screen_base);
0246     iounmap(par->mmio);
0247     start = tdev->resource.start;
0248     len = tdev->resource.end - start + 1;
0249     release_mem_region(start, len);
0250     fb_dealloc_cmap(&info->cmap);
0251     framebuffer_release(info);
0252     return 0;
0253 }
0254 
0255 
0256 /*
0257  * Initialize the framebuffer.
0258  */
0259 static const struct tc_device_id pmagbafb_tc_table[] = {
0260     { "DEC     ", "PMAG-BA " },
0261     { }
0262 };
0263 MODULE_DEVICE_TABLE(tc, pmagbafb_tc_table);
0264 
0265 static struct tc_driver pmagbafb_driver = {
0266     .id_table   = pmagbafb_tc_table,
0267     .driver     = {
0268         .name   = "pmagbafb",
0269         .bus    = &tc_bus_type,
0270         .probe  = pmagbafb_probe,
0271         .remove = pmagbafb_remove,
0272     },
0273 };
0274 
0275 static int __init pmagbafb_init(void)
0276 {
0277 #ifndef MODULE
0278     if (fb_get_options("pmagbafb", NULL))
0279         return -ENXIO;
0280 #endif
0281     return tc_register_driver(&pmagbafb_driver);
0282 }
0283 
0284 static void __exit pmagbafb_exit(void)
0285 {
0286     tc_unregister_driver(&pmagbafb_driver);
0287 }
0288 
0289 
0290 module_init(pmagbafb_init);
0291 module_exit(pmagbafb_exit);
0292 
0293 MODULE_LICENSE("GPL");