Merge tag 'fbdev-v4.15' of git://github.com/bzolnier/linux
[sfrench/cifs-2.6.git] / drivers / video / fbdev / pmag-aa-fb.c
1 /*
2  *      linux/drivers/video/pmag-aa-fb.c
3  *      Copyright 2002 Karsten Merker <merker@debian.org>
4  *
5  *      PMAG-AA TurboChannel framebuffer card support ... derived from
6  *      pmag-ba-fb.c, which is Copyright (C) 1999, 2000, 2001 by
7  *      Michael Engel <engel@unix-ag.org>, Karsten Merker <merker@debian.org>
8  *      and Harald Koerfgen <hkoerfg@web.de>, which itself is derived from
9  *      "HP300 Topcat framebuffer support (derived from macfb of all things)
10  *      Phil Blundell <philb@gnu.org> 1998"
11  *      Copyright (c) 2016  Maciej W. Rozycki
12  *
13  *      This file is subject to the terms and conditions of the GNU General
14  *      Public License.  See the file COPYING in the main directory of this
15  *      archive for more details.
16  *
17  *      2002-09-28  Karsten Merker <merker@linuxtag.org>
18  *              Version 0.01: First try to get a PMAG-AA running.
19  *
20  *      2003-02-24  Thiemo Seufer  <seufer@csv.ica.uni-stuttgart.de>
21  *              Version 0.02: Major code cleanup.
22  *
23  *      2003-09-21  Thiemo Seufer  <seufer@csv.ica.uni-stuttgart.de>
24  *              Hardware cursor support.
25  *
26  *      2016-02-21  Maciej W. Rozycki  <macro@linux-mips.org>
27  *              Version 0.03: Rewritten for the new FB and TC APIs.
28  */
29
30 #include <linux/compiler.h>
31 #include <linux/errno.h>
32 #include <linux/fb.h>
33 #include <linux/init.h>
34 #include <linux/io.h>
35 #include <linux/kernel.h>
36 #include <linux/module.h>
37 #include <linux/tc.h>
38 #include <linux/timer.h>
39
40 #include "bt455.h"
41 #include "bt431.h"
42
43 /* Version information */
44 #define DRIVER_VERSION "0.03"
45 #define DRIVER_AUTHOR "Karsten Merker <merker@linuxtag.org>"
46 #define DRIVER_DESCRIPTION "PMAG-AA Framebuffer Driver"
47
48 /*
49  * Bt455 RAM DAC register base offset (rel. to TC slot base address).
50  */
51 #define PMAG_AA_BT455_OFFSET            0x100000
52
53 /*
54  * Bt431 cursor generator offset (rel. to TC slot base address).
55  */
56 #define PMAG_AA_BT431_OFFSET            0x180000
57
58 /*
59  * Begin of PMAG-AA framebuffer memory relative to TC slot address,
60  * resolution is 1280x1024x1 (8 bits deep, but only LSB is used).
61  */
62 #define PMAG_AA_ONBOARD_FBMEM_OFFSET    0x200000
63
64 struct aafb_par {
65         void __iomem *mmio;
66         struct bt455_regs __iomem *bt455;
67         struct bt431_regs __iomem *bt431;
68 };
69
70 static const struct fb_var_screeninfo aafb_defined = {
71         .xres           = 1280,
72         .yres           = 1024,
73         .xres_virtual   = 2048,
74         .yres_virtual   = 1024,
75         .bits_per_pixel = 8,
76         .grayscale      = 1,
77         .red.length     = 0,
78         .green.length   = 1,
79         .blue.length    = 0,
80         .activate       = FB_ACTIVATE_NOW,
81         .accel_flags    = FB_ACCEL_NONE,
82         .pixclock       = 7645,
83         .left_margin    = 224,
84         .right_margin   = 32,
85         .upper_margin   = 33,
86         .lower_margin   = 3,
87         .hsync_len      = 160,
88         .vsync_len      = 3,
89         .sync           = FB_SYNC_ON_GREEN,
90         .vmode          = FB_VMODE_NONINTERLACED,
91 };
92
93 static const struct fb_fix_screeninfo aafb_fix = {
94         .id             = "PMAG-AA",
95         .smem_len       = (2048 * 1024),
96         .type           = FB_TYPE_PACKED_PIXELS,
97         .visual         = FB_VISUAL_MONO10,
98         .ypanstep       = 1,
99         .ywrapstep      = 1,
100         .line_length    = 2048,
101         .mmio_len       = PMAG_AA_ONBOARD_FBMEM_OFFSET - PMAG_AA_BT455_OFFSET,
102 };
103
104 static int aafb_cursor(struct fb_info *info, struct fb_cursor *cursor)
105 {
106         struct aafb_par *par = info->par;
107
108         if (cursor->image.height > BT431_CURSOR_SIZE ||
109             cursor->image.width > BT431_CURSOR_SIZE) {
110                 bt431_erase_cursor(par->bt431);
111                 return -EINVAL;
112         }
113
114         if (!cursor->enable)
115                 bt431_erase_cursor(par->bt431);
116
117         if (cursor->set & FB_CUR_SETPOS)
118                 bt431_position_cursor(par->bt431,
119                                       cursor->image.dx, cursor->image.dy);
120         if (cursor->set & FB_CUR_SETCMAP) {
121                 u8 fg = cursor->image.fg_color ? 0xf : 0x0;
122                 u8 bg = cursor->image.bg_color ? 0xf : 0x0;
123
124                 bt455_write_cmap_entry(par->bt455, 8, bg);
125                 bt455_write_cmap_next(par->bt455, bg);
126                 bt455_write_ovly_next(par->bt455, fg);
127         }
128         if (cursor->set & (FB_CUR_SETSIZE | FB_CUR_SETSHAPE | FB_CUR_SETIMAGE))
129                 bt431_set_cursor(par->bt431,
130                                  cursor->image.data, cursor->mask, cursor->rop,
131                                  cursor->image.width, cursor->image.height);
132
133         if (cursor->enable)
134                 bt431_enable_cursor(par->bt431);
135
136         return 0;
137 }
138
139 /* 0 unblanks, any other blanks. */
140
141 static int aafb_blank(int blank, struct fb_info *info)
142 {
143         struct aafb_par *par = info->par;
144         u8 val = blank ? 0x00 : 0x0f;
145
146         bt455_write_cmap_entry(par->bt455, 1, val);
147         return 0;
148 }
149
150 static struct fb_ops aafb_ops = {
151         .owner          = THIS_MODULE,
152         .fb_blank       = aafb_blank,
153         .fb_fillrect    = cfb_fillrect,
154         .fb_copyarea    = cfb_copyarea,
155         .fb_imageblit   = cfb_imageblit,
156         .fb_cursor      = aafb_cursor,
157 };
158
159 static int pmagaafb_probe(struct device *dev)
160 {
161         struct tc_dev *tdev = to_tc_dev(dev);
162         resource_size_t start, len;
163         struct fb_info *info;
164         struct aafb_par *par;
165         int err;
166
167         info = framebuffer_alloc(sizeof(struct aafb_par), dev);
168         if (!info) {
169                 printk(KERN_ERR "%s: Cannot allocate memory\n", dev_name(dev));
170                 return -ENOMEM;
171         }
172
173         par = info->par;
174         dev_set_drvdata(dev, info);
175
176         info->fbops = &aafb_ops;
177         info->fix = aafb_fix;
178         info->var = aafb_defined;
179         info->flags = FBINFO_DEFAULT;
180
181         /* Request the I/O MEM resource. */
182         start = tdev->resource.start;
183         len = tdev->resource.end - start + 1;
184         if (!request_mem_region(start, len, dev_name(dev))) {
185                 printk(KERN_ERR "%s: Cannot reserve FB region\n",
186                        dev_name(dev));
187                 err = -EBUSY;
188                 goto err_alloc;
189         }
190
191         /* MMIO mapping setup. */
192         info->fix.mmio_start = start + PMAG_AA_BT455_OFFSET;
193         par->mmio = ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len);
194         if (!par->mmio) {
195                 printk(KERN_ERR "%s: Cannot map MMIO\n", dev_name(dev));
196                 err = -ENOMEM;
197                 goto err_resource;
198         }
199         par->bt455 = par->mmio - PMAG_AA_BT455_OFFSET + PMAG_AA_BT455_OFFSET;
200         par->bt431 = par->mmio - PMAG_AA_BT455_OFFSET + PMAG_AA_BT431_OFFSET;
201
202         /* Frame buffer mapping setup. */
203         info->fix.smem_start = start + PMAG_AA_ONBOARD_FBMEM_OFFSET;
204         info->screen_base = ioremap_nocache(info->fix.smem_start,
205                                             info->fix.smem_len);
206         if (!info->screen_base) {
207                 printk(KERN_ERR "%s: Cannot map FB\n", dev_name(dev));
208                 err = -ENOMEM;
209                 goto err_mmio_map;
210         }
211         info->screen_size = info->fix.smem_len;
212
213         /* Init colormap. */
214         bt455_write_cmap_entry(par->bt455, 0, 0x0);
215         bt455_write_cmap_next(par->bt455, 0xf);
216
217         /* Init hardware cursor. */
218         bt431_erase_cursor(par->bt431);
219         bt431_init_cursor(par->bt431);
220
221         err = register_framebuffer(info);
222         if (err < 0) {
223                 printk(KERN_ERR "%s: Cannot register framebuffer\n",
224                        dev_name(dev));
225                 goto err_smem_map;
226         }
227
228         get_device(dev);
229
230         pr_info("fb%d: %s frame buffer device at %s\n",
231                 info->node, info->fix.id, dev_name(dev));
232
233         return 0;
234
235
236 err_smem_map:
237         iounmap(info->screen_base);
238
239 err_mmio_map:
240         iounmap(par->mmio);
241
242 err_resource:
243         release_mem_region(start, len);
244
245 err_alloc:
246         framebuffer_release(info);
247         return err;
248 }
249
250 static int pmagaafb_remove(struct device *dev)
251 {
252         struct tc_dev *tdev = to_tc_dev(dev);
253         struct fb_info *info = dev_get_drvdata(dev);
254         struct aafb_par *par = info->par;
255         resource_size_t start, len;
256
257         put_device(dev);
258         unregister_framebuffer(info);
259         iounmap(info->screen_base);
260         iounmap(par->mmio);
261         start = tdev->resource.start;
262         len = tdev->resource.end - start + 1;
263         release_mem_region(start, len);
264         framebuffer_release(info);
265         return 0;
266 }
267
268 /*
269  * Initialise the framebuffer.
270  */
271 static const struct tc_device_id pmagaafb_tc_table[] = {
272         { "DEC     ", "PMAG-AA " },
273         { }
274 };
275 MODULE_DEVICE_TABLE(tc, pmagaafb_tc_table);
276
277 static struct tc_driver pmagaafb_driver = {
278         .id_table       = pmagaafb_tc_table,
279         .driver         = {
280                 .name   = "pmagaafb",
281                 .bus    = &tc_bus_type,
282                 .probe  = pmagaafb_probe,
283                 .remove = pmagaafb_remove,
284         },
285 };
286
287 static int __init pmagaafb_init(void)
288 {
289 #ifndef MODULE
290         if (fb_get_options("pmagaafb", NULL))
291                 return -ENXIO;
292 #endif
293         return tc_register_driver(&pmagaafb_driver);
294 }
295
296 static void __exit pmagaafb_exit(void)
297 {
298         tc_unregister_driver(&pmagaafb_driver);
299 }
300
301 module_init(pmagaafb_init);
302 module_exit(pmagaafb_exit);
303
304 MODULE_AUTHOR(DRIVER_AUTHOR);
305 MODULE_DESCRIPTION(DRIVER_DESCRIPTION);
306 MODULE_LICENSE("GPL");