ocfs2: Fix a bug found by sparse check.
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / video / bw2.c
CommitLineData
1da177e4
LT
1/* bw2.c: BWTWO frame buffer driver
2 *
50312ce9 3 * Copyright (C) 2003, 2006 David S. Miller (davem@davemloft.net)
1da177e4
LT
4 * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
5 * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
6 * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
7 *
8 * Driver layout based loosely on tgafb.c, see that file for credits.
9 */
10
11#include <linux/module.h>
12#include <linux/kernel.h>
13#include <linux/errno.h>
14#include <linux/string.h>
15#include <linux/slab.h>
16#include <linux/delay.h>
17#include <linux/init.h>
18#include <linux/fb.h>
19#include <linux/mm.h>
6cd5a86b 20#include <linux/of_device.h>
1da177e4
LT
21
22#include <asm/io.h>
1da177e4
LT
23#include <asm/fbio.h>
24
1da177e4
LT
25#include "sbuslib.h"
26
27/*
28 * Local functions.
29 */
30
31static int bw2_blank(int, struct fb_info *);
32
216d526c 33static int bw2_mmap(struct fb_info *, struct vm_area_struct *);
67a6680d 34static int bw2_ioctl(struct fb_info *, unsigned int, unsigned long);
1da177e4
LT
35
36/*
37 * Frame buffer operations
38 */
39
40static struct fb_ops bw2_ops = {
41 .owner = THIS_MODULE,
42 .fb_blank = bw2_blank,
43 .fb_fillrect = cfb_fillrect,
44 .fb_copyarea = cfb_copyarea,
45 .fb_imageblit = cfb_imageblit,
46 .fb_mmap = bw2_mmap,
47 .fb_ioctl = bw2_ioctl,
9ffb83bc
CH
48#ifdef CONFIG_COMPAT
49 .fb_compat_ioctl = sbusfb_compat_ioctl,
50#endif
1da177e4
LT
51};
52
53/* OBio addresses for the bwtwo registers */
54#define BWTWO_REGISTER_OFFSET 0x400000
55
56struct bt_regs {
50312ce9
DM
57 u32 addr;
58 u32 color_map;
59 u32 control;
60 u32 cursor;
1da177e4
LT
61};
62
63struct bw2_regs {
64 struct bt_regs cmap;
50312ce9
DM
65 u8 control;
66 u8 status;
67 u8 cursor_start;
68 u8 cursor_end;
69 u8 h_blank_start;
70 u8 h_blank_end;
71 u8 h_sync_start;
72 u8 h_sync_end;
73 u8 comp_sync_end;
74 u8 v_blank_start_high;
75 u8 v_blank_start_low;
76 u8 v_blank_end;
77 u8 v_sync_start;
78 u8 v_sync_end;
79 u8 xfer_holdoff_start;
80 u8 xfer_holdoff_end;
1da177e4
LT
81};
82
83/* Status Register Constants */
84#define BWTWO_SR_RES_MASK 0x70
85#define BWTWO_SR_1600_1280 0x50
86#define BWTWO_SR_1152_900_76_A 0x40
87#define BWTWO_SR_1152_900_76_B 0x60
88#define BWTWO_SR_ID_MASK 0x0f
89#define BWTWO_SR_ID_MONO 0x02
90#define BWTWO_SR_ID_MONO_ECL 0x03
91#define BWTWO_SR_ID_MSYNC 0x04
92#define BWTWO_SR_ID_NOCONN 0x0a
93
94/* Control Register Constants */
95#define BWTWO_CTL_ENABLE_INTS 0x80
96#define BWTWO_CTL_ENABLE_VIDEO 0x40
97#define BWTWO_CTL_ENABLE_TIMING 0x20
98#define BWTWO_CTL_ENABLE_CURCMP 0x10
99#define BWTWO_CTL_XTAL_MASK 0x0C
100#define BWTWO_CTL_DIVISOR_MASK 0x03
101
102/* Status Register Constants */
103#define BWTWO_STAT_PENDING_INT 0x80
104#define BWTWO_STAT_MSENSE_MASK 0x70
105#define BWTWO_STAT_ID_MASK 0x0f
106
107struct bw2_par {
108 spinlock_t lock;
109 struct bw2_regs __iomem *regs;
110
111 u32 flags;
112#define BW2_FLAG_BLANKED 0x00000001
113
114 unsigned long physbase;
50312ce9 115 unsigned long which_io;
1da177e4 116 unsigned long fbsize;
1da177e4
LT
117};
118
119/**
120 * bw2_blank - Optional function. Blanks the display.
121 * @blank_mode: the blank mode we want.
122 * @info: frame buffer structure that represents a single frame buffer
123 */
124static int
125bw2_blank(int blank, struct fb_info *info)
126{
127 struct bw2_par *par = (struct bw2_par *) info->par;
128 struct bw2_regs __iomem *regs = par->regs;
129 unsigned long flags;
130 u8 val;
131
132 spin_lock_irqsave(&par->lock, flags);
133
134 switch (blank) {
135 case FB_BLANK_UNBLANK: /* Unblanking */
136 val = sbus_readb(&regs->control);
137 val |= BWTWO_CTL_ENABLE_VIDEO;
138 sbus_writeb(val, &regs->control);
139 par->flags &= ~BW2_FLAG_BLANKED;
140 break;
141
142 case FB_BLANK_NORMAL: /* Normal blanking */
143 case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */
144 case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */
145 case FB_BLANK_POWERDOWN: /* Poweroff */
146 val = sbus_readb(&regs->control);
147 val &= ~BWTWO_CTL_ENABLE_VIDEO;
148 sbus_writeb(val, &regs->control);
149 par->flags |= BW2_FLAG_BLANKED;
150 break;
151 }
152
153 spin_unlock_irqrestore(&par->lock, flags);
154
155 return 0;
156}
157
158static struct sbus_mmap_map bw2_mmap_map[] = {
159 {
160 .size = SBUS_MMAP_FBSIZE(1)
161 },
162 { .size = 0 }
163};
164
216d526c 165static int bw2_mmap(struct fb_info *info, struct vm_area_struct *vma)
1da177e4
LT
166{
167 struct bw2_par *par = (struct bw2_par *)info->par;
168
169 return sbusfb_mmap_helper(bw2_mmap_map,
170 par->physbase, par->fbsize,
50312ce9 171 par->which_io,
1da177e4
LT
172 vma);
173}
174
67a6680d 175static int bw2_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
1da177e4
LT
176{
177 struct bw2_par *par = (struct bw2_par *) info->par;
178
179 return sbusfb_ioctl_helper(cmd, arg, info,
180 FBTYPE_SUN2BW, 1, par->fbsize);
181}
182
183/*
184 * Initialisation
185 */
186
63abdcdc 187static void __devinit bw2_init_fix(struct fb_info *info, int linebytes)
1da177e4
LT
188{
189 strlcpy(info->fix.id, "bwtwo", sizeof(info->fix.id));
190
191 info->fix.type = FB_TYPE_PACKED_PIXELS;
192 info->fix.visual = FB_VISUAL_MONO01;
193
194 info->fix.line_length = linebytes;
195
196 info->fix.accel = FB_ACCEL_SUN_BWTWO;
197}
198
63abdcdc 199static u8 bw2regs_1600[] __devinitdata = {
1da177e4
LT
200 0x14, 0x8b, 0x15, 0x28, 0x16, 0x03, 0x17, 0x13,
201 0x18, 0x7b, 0x19, 0x05, 0x1a, 0x34, 0x1b, 0x2e,
202 0x1c, 0x00, 0x1d, 0x0a, 0x1e, 0xff, 0x1f, 0x01,
203 0x10, 0x21, 0
204};
205
63abdcdc 206static u8 bw2regs_ecl[] __devinitdata = {
1da177e4
LT
207 0x14, 0x65, 0x15, 0x1e, 0x16, 0x04, 0x17, 0x0c,
208 0x18, 0x5e, 0x19, 0x03, 0x1a, 0xa7, 0x1b, 0x23,
209 0x1c, 0x00, 0x1d, 0x08, 0x1e, 0xff, 0x1f, 0x01,
210 0x10, 0x20, 0
211};
212
63abdcdc 213static u8 bw2regs_analog[] __devinitdata = {
1da177e4
LT
214 0x14, 0xbb, 0x15, 0x2b, 0x16, 0x03, 0x17, 0x13,
215 0x18, 0xb0, 0x19, 0x03, 0x1a, 0xa6, 0x1b, 0x22,
216 0x1c, 0x01, 0x1d, 0x05, 0x1e, 0xff, 0x1f, 0x01,
217 0x10, 0x20, 0
218};
219
63abdcdc 220static u8 bw2regs_76hz[] __devinitdata = {
1da177e4
LT
221 0x14, 0xb7, 0x15, 0x27, 0x16, 0x03, 0x17, 0x0f,
222 0x18, 0xae, 0x19, 0x03, 0x1a, 0xae, 0x1b, 0x2a,
223 0x1c, 0x01, 0x1d, 0x09, 0x1e, 0xff, 0x1f, 0x01,
224 0x10, 0x24, 0
225};
226
63abdcdc 227static u8 bw2regs_66hz[] __devinitdata = {
1da177e4
LT
228 0x14, 0xbb, 0x15, 0x2b, 0x16, 0x04, 0x17, 0x14,
229 0x18, 0xae, 0x19, 0x03, 0x1a, 0xa8, 0x1b, 0x24,
230 0x1c, 0x01, 0x1d, 0x05, 0x1e, 0xff, 0x1f, 0x01,
231 0x10, 0x20, 0
232};
233
6c8f5b90
DM
234static int __devinit bw2_do_default_mode(struct bw2_par *par,
235 struct fb_info *info,
236 int *linebytes)
1da177e4
LT
237{
238 u8 status, mon;
239 u8 *p;
240
241 status = sbus_readb(&par->regs->status);
242 mon = status & BWTWO_SR_RES_MASK;
243 switch (status & BWTWO_SR_ID_MASK) {
244 case BWTWO_SR_ID_MONO_ECL:
245 if (mon == BWTWO_SR_1600_1280) {
246 p = bw2regs_1600;
247 info->var.xres = info->var.xres_virtual = 1600;
248 info->var.yres = info->var.yres_virtual = 1280;
249 *linebytes = 1600 / 8;
250 } else
251 p = bw2regs_ecl;
252 break;
253
254 case BWTWO_SR_ID_MONO:
255 p = bw2regs_analog;
256 break;
257
258 case BWTWO_SR_ID_MSYNC:
259 if (mon == BWTWO_SR_1152_900_76_A ||
260 mon == BWTWO_SR_1152_900_76_B)
261 p = bw2regs_76hz;
262 else
263 p = bw2regs_66hz;
264 break;
265
266 case BWTWO_SR_ID_NOCONN:
6c8f5b90 267 return 0;
1da177e4
LT
268
269 default:
6c8f5b90
DM
270 printk(KERN_ERR "bw2: can't handle SR %02x\n",
271 status);
272 return -EINVAL;
1da177e4
LT
273 }
274 for ( ; *p; p += 2) {
275 u8 __iomem *regp = &((u8 __iomem *)par->regs)[p[0]];
276 sbus_writeb(p[1], regp);
277 }
6c8f5b90 278 return 0;
1da177e4
LT
279}
280
c7f439b9 281static int __devinit bw2_probe(struct of_device *op, const struct of_device_id *match)
1da177e4 282{
50312ce9 283 struct device_node *dp = op->node;
c7f439b9
DM
284 struct fb_info *info;
285 struct bw2_par *par;
50312ce9 286 int linebytes, err;
1da177e4 287
c7f439b9 288 info = framebuffer_alloc(sizeof(struct bw2_par), &op->dev);
1da177e4 289
c7f439b9
DM
290 err = -ENOMEM;
291 if (!info)
292 goto out_err;
293 par = info->par;
50312ce9 294
c7f439b9 295 spin_lock_init(&par->lock);
50312ce9 296
c7f439b9
DM
297 par->physbase = op->resource[0].start;
298 par->which_io = op->resource[0].flags & IORESOURCE_BITS;
299
6cd5a86b 300 sbusfb_fill_var(&info->var, dp, 1);
50312ce9 301 linebytes = of_getintprop_default(dp, "linebytes",
c7f439b9 302 info->var.xres);
50312ce9 303
c7f439b9
DM
304 info->var.red.length = info->var.green.length =
305 info->var.blue.length = info->var.bits_per_pixel;
306 info->var.red.offset = info->var.green.offset =
307 info->var.blue.offset = 0;
1da177e4 308
c7f439b9
DM
309 par->regs = of_ioremap(&op->resource[0], BWTWO_REGISTER_OFFSET,
310 sizeof(struct bw2_regs), "bw2 regs");
311 if (!par->regs)
312 goto out_release_fb;
1da177e4 313
6c8f5b90
DM
314 if (!of_find_property(dp, "width", NULL)) {
315 err = bw2_do_default_mode(par, info, &linebytes);
316 if (err)
317 goto out_unmap_regs;
318 }
1da177e4 319
c7f439b9 320 par->fbsize = PAGE_ALIGN(linebytes * info->var.yres);
1da177e4 321
c7f439b9
DM
322 info->flags = FBINFO_DEFAULT;
323 info->fbops = &bw2_ops;
50312ce9 324
c7f439b9
DM
325 info->screen_base = of_ioremap(&op->resource[0], 0,
326 par->fbsize, "bw2 ram");
327 if (!info->screen_base)
328 goto out_unmap_regs;
1da177e4 329
59f7137a 330 bw2_blank(FB_BLANK_UNBLANK, info);
1da177e4 331
c7f439b9 332 bw2_init_fix(info, linebytes);
1da177e4 333
c7f439b9
DM
334 err = register_framebuffer(info);
335 if (err < 0)
336 goto out_unmap_screen;
1da177e4 337
c7f439b9 338 dev_set_drvdata(&op->dev, info);
50312ce9 339
194f1a68 340 printk(KERN_INFO "%s: bwtwo at %lx:%lx\n",
c7f439b9 341 dp->full_name, par->which_io, par->physbase);
1da177e4 342
50312ce9 343 return 0;
1da177e4 344
c7f439b9
DM
345out_unmap_screen:
346 of_iounmap(&op->resource[0], info->screen_base, par->fbsize);
347
348out_unmap_regs:
349 of_iounmap(&op->resource[0], par->regs, sizeof(struct bw2_regs));
350
351out_release_fb:
352 framebuffer_release(info);
1da177e4 353
c7f439b9
DM
354out_err:
355 return err;
50312ce9 356}
1da177e4 357
e3a411a3 358static int __devexit bw2_remove(struct of_device *op)
50312ce9 359{
c7f439b9
DM
360 struct fb_info *info = dev_get_drvdata(&op->dev);
361 struct bw2_par *par = info->par;
50312ce9 362
c7f439b9 363 unregister_framebuffer(info);
50312ce9 364
c7f439b9
DM
365 of_iounmap(&op->resource[0], par->regs, sizeof(struct bw2_regs));
366 of_iounmap(&op->resource[0], info->screen_base, par->fbsize);
50312ce9 367
c7f439b9 368 framebuffer_release(info);
50312ce9 369
e3a411a3 370 dev_set_drvdata(&op->dev, NULL);
1da177e4
LT
371
372 return 0;
373}
374
fd098316 375static const struct of_device_id bw2_match[] = {
50312ce9
DM
376 {
377 .name = "bwtwo",
378 },
379 {},
380};
381MODULE_DEVICE_TABLE(of, bw2_match);
1da177e4 382
50312ce9
DM
383static struct of_platform_driver bw2_driver = {
384 .name = "bw2",
385 .match_table = bw2_match,
386 .probe = bw2_probe,
387 .remove = __devexit_p(bw2_remove),
388};
1da177e4 389
50312ce9
DM
390static int __init bw2_init(void)
391{
392 if (fb_get_options("bw2fb", NULL))
393 return -ENODEV;
394
395 return of_register_driver(&bw2_driver, &of_bus_type);
1da177e4
LT
396}
397
50312ce9 398static void __exit bw2_exit(void)
1da177e4 399{
2556bf12 400 of_unregister_driver(&bw2_driver);
1da177e4
LT
401}
402
50312ce9 403module_init(bw2_init);
1da177e4 404module_exit(bw2_exit);
1da177e4
LT
405
406MODULE_DESCRIPTION("framebuffer driver for BWTWO chipsets");
50312ce9
DM
407MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
408MODULE_VERSION("2.0");
1da177e4 409MODULE_LICENSE("GPL");