0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
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
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;
0104 green >>= 8;
0105 blue >>= 8;
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
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
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
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
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
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");