Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pmag-ba-fb.c
Go to the documentation of this file.
1 /*
2  * linux/drivers/video/pmag-ba-fb.c
3  *
4  * PMAG-BA TURBOchannel Color Frame Buffer (CFB) card support,
5  * derived from:
6  * "HP300 Topcat framebuffer support (derived from macfb of all things)
7  * Phil Blundell <[email protected]> 1998", the original code can be
8  * found in the file hpfb.c in the same directory.
9  *
10  * Based on digital document:
11  * "PMAG-BA TURBOchannel Color Frame Buffer
12  * Functional Specification", Revision 1.2, August 27, 1990
13  *
14  * DECstation related code Copyright (C) 1999, 2000, 2001 by
15  * Michael Engel <[email protected]>,
16  * Karsten Merker <[email protected]> and
17  * Harald Koerfgen.
18  * Copyright (c) 2005, 2006 Maciej W. Rozycki
19  * Copyright (c) 2005 James Simmons
20  *
21  * This file is subject to the terms and conditions of the GNU General
22  * Public License. See the file COPYING in the main directory of this
23  * archive for more details.
24  */
25 
26 #include <linux/compiler.h>
27 #include <linux/errno.h>
28 #include <linux/fb.h>
29 #include <linux/init.h>
30 #include <linux/kernel.h>
31 #include <linux/module.h>
32 #include <linux/tc.h>
33 #include <linux/types.h>
34 
35 #include <asm/io.h>
36 
37 #include <video/pmag-ba-fb.h>
38 
39 
40 struct pmagbafb_par {
41  volatile void __iomem *mmio;
42  volatile u32 __iomem *dac;
43 };
44 
45 
46 static struct fb_var_screeninfo pmagbafb_defined __devinitdata = {
47  .xres = 1024,
48  .yres = 864,
49  .xres_virtual = 1024,
50  .yres_virtual = 864,
51  .bits_per_pixel = 8,
52  .red.length = 8,
53  .green.length = 8,
54  .blue.length = 8,
55  .activate = FB_ACTIVATE_NOW,
56  .height = -1,
57  .width = -1,
58  .accel_flags = FB_ACCEL_NONE,
59  .pixclock = 14452,
60  .left_margin = 116,
61  .right_margin = 12,
62  .upper_margin = 34,
63  .lower_margin = 12,
64  .hsync_len = 128,
65  .vsync_len = 3,
66  .sync = FB_SYNC_ON_GREEN,
67  .vmode = FB_VMODE_NONINTERLACED,
68 };
69 
70 static struct fb_fix_screeninfo pmagbafb_fix __devinitdata = {
71  .id = "PMAG-BA",
72  .smem_len = (1024 * 1024),
75  .line_length = 1024,
77 };
78 
79 
80 static inline void dac_write(struct pmagbafb_par *par, unsigned int reg, u8 v)
81 {
82  writeb(v, par->dac + reg / 4);
83 }
84 
85 static inline u8 dac_read(struct pmagbafb_par *par, unsigned int reg)
86 {
87  return readb(par->dac + reg / 4);
88 }
89 
90 
91 /*
92  * Set the palette.
93  */
94 static int pmagbafb_setcolreg(unsigned int regno, unsigned int red,
95  unsigned int green, unsigned int blue,
96  unsigned int transp, struct fb_info *info)
97 {
98  struct pmagbafb_par *par = info->par;
99 
100  if (regno >= info->cmap.len)
101  return 1;
102 
103  red >>= 8; /* The cmap fields are 16 bits */
104  green >>= 8; /* wide, but the hardware colormap */
105  blue >>= 8; /* registers are only 8 bits wide */
106 
107  mb();
108  dac_write(par, BT459_ADDR_LO, regno);
109  dac_write(par, BT459_ADDR_HI, 0x00);
110  wmb();
111  dac_write(par, BT459_CMAP, red);
112  wmb();
113  dac_write(par, BT459_CMAP, green);
114  wmb();
115  dac_write(par, BT459_CMAP, blue);
116 
117  return 0;
118 }
119 
120 static struct fb_ops pmagbafb_ops = {
121  .owner = THIS_MODULE,
122  .fb_setcolreg = pmagbafb_setcolreg,
123  .fb_fillrect = cfb_fillrect,
124  .fb_copyarea = cfb_copyarea,
125  .fb_imageblit = cfb_imageblit,
126 };
127 
128 
129 /*
130  * Turn the hardware cursor off.
131  */
132 static void __init pmagbafb_erase_cursor(struct fb_info *info)
133 {
134  struct pmagbafb_par *par = info->par;
135 
136  mb();
137  dac_write(par, BT459_ADDR_LO, 0x00);
138  dac_write(par, BT459_ADDR_HI, 0x03);
139  wmb();
140  dac_write(par, BT459_DATA, 0x00);
141 }
142 
143 
144 static int __devinit pmagbafb_probe(struct device *dev)
145 {
146  struct tc_dev *tdev = to_tc_dev(dev);
148  struct fb_info *info;
149  struct pmagbafb_par *par;
150  int err;
151 
152  info = framebuffer_alloc(sizeof(struct pmagbafb_par), dev);
153  if (!info) {
154  printk(KERN_ERR "%s: Cannot allocate memory\n", dev_name(dev));
155  return -ENOMEM;
156  }
157 
158  par = info->par;
159  dev_set_drvdata(dev, info);
160 
161  if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
162  printk(KERN_ERR "%s: Cannot allocate color map\n",
163  dev_name(dev));
164  err = -ENOMEM;
165  goto err_alloc;
166  }
167 
168  info->fbops = &pmagbafb_ops;
169  info->fix = pmagbafb_fix;
170  info->var = pmagbafb_defined;
171  info->flags = FBINFO_DEFAULT;
172 
173  /* Request the I/O MEM resource. */
174  start = tdev->resource.start;
175  len = tdev->resource.end - start + 1;
176  if (!request_mem_region(start, len, dev_name(dev))) {
177  printk(KERN_ERR "%s: Cannot reserve FB region\n",
178  dev_name(dev));
179  err = -EBUSY;
180  goto err_cmap;
181  }
182 
183  /* MMIO mapping setup. */
184  info->fix.mmio_start = start;
185  par->mmio = ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len);
186  if (!par->mmio) {
187  printk(KERN_ERR "%s: Cannot map MMIO\n", dev_name(dev));
188  err = -ENOMEM;
189  goto err_resource;
190  }
191  par->dac = par->mmio + PMAG_BA_BT459;
192 
193  /* Frame buffer mapping setup. */
194  info->fix.smem_start = start + PMAG_BA_FBMEM;
195  info->screen_base = ioremap_nocache(info->fix.smem_start,
196  info->fix.smem_len);
197  if (!info->screen_base) {
198  printk(KERN_ERR "%s: Cannot map FB\n", dev_name(dev));
199  err = -ENOMEM;
200  goto err_mmio_map;
201  }
202  info->screen_size = info->fix.smem_len;
203 
204  pmagbafb_erase_cursor(info);
205 
206  err = register_framebuffer(info);
207  if (err < 0) {
208  printk(KERN_ERR "%s: Cannot register framebuffer\n",
209  dev_name(dev));
210  goto err_smem_map;
211  }
212 
213  get_device(dev);
214 
215  pr_info("fb%d: %s frame buffer device at %s\n",
216  info->node, info->fix.id, dev_name(dev));
217 
218  return 0;
219 
220 
221 err_smem_map:
222  iounmap(info->screen_base);
223 
224 err_mmio_map:
225  iounmap(par->mmio);
226 
227 err_resource:
228  release_mem_region(start, len);
229 
230 err_cmap:
231  fb_dealloc_cmap(&info->cmap);
232 
233 err_alloc:
234  framebuffer_release(info);
235  return err;
236 }
237 
238 static int __exit pmagbafb_remove(struct device *dev)
239 {
240  struct tc_dev *tdev = to_tc_dev(dev);
241  struct fb_info *info = dev_get_drvdata(dev);
242  struct pmagbafb_par *par = info->par;
243  resource_size_t start, len;
244 
245  put_device(dev);
247  iounmap(info->screen_base);
248  iounmap(par->mmio);
249  start = tdev->resource.start;
250  len = tdev->resource.end - start + 1;
251  release_mem_region(start, len);
252  fb_dealloc_cmap(&info->cmap);
253  framebuffer_release(info);
254  return 0;
255 }
256 
257 
258 /*
259  * Initialize the framebuffer.
260  */
261 static const struct tc_device_id pmagbafb_tc_table[] = {
262  { "DEC ", "PMAG-BA " },
263  { }
264 };
265 MODULE_DEVICE_TABLE(tc, pmagbafb_tc_table);
266 
267 static struct tc_driver pmagbafb_driver = {
268  .id_table = pmagbafb_tc_table,
269  .driver = {
270  .name = "pmagbafb",
271  .bus = &tc_bus_type,
272  .probe = pmagbafb_probe,
273  .remove = __exit_p(pmagbafb_remove),
274  },
275 };
276 
277 static int __init pmagbafb_init(void)
278 {
279 #ifndef MODULE
280  if (fb_get_options("pmagbafb", NULL))
281  return -ENXIO;
282 #endif
283  return tc_register_driver(&pmagbafb_driver);
284 }
285 
286 static void __exit pmagbafb_exit(void)
287 {
288  tc_unregister_driver(&pmagbafb_driver);
289 }
290 
291 
292 module_init(pmagbafb_init);
293 module_exit(pmagbafb_exit);
294 
295 MODULE_LICENSE("GPL");