]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - drivers/video/bw2.c
Merge branch 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jlbec...
[mirror_ubuntu-bionic-kernel.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
50312ce9 114 unsigned long which_io;
1da177e4
LT
115};
116
117/**
118 * bw2_blank - Optional function. Blanks the display.
119 * @blank_mode: the blank mode we want.
120 * @info: frame buffer structure that represents a single frame buffer
121 */
122static int
123bw2_blank(int blank, struct fb_info *info)
124{
125 struct bw2_par *par = (struct bw2_par *) info->par;
126 struct bw2_regs __iomem *regs = par->regs;
127 unsigned long flags;
128 u8 val;
129
130 spin_lock_irqsave(&par->lock, flags);
131
132 switch (blank) {
133 case FB_BLANK_UNBLANK: /* Unblanking */
134 val = sbus_readb(&regs->control);
135 val |= BWTWO_CTL_ENABLE_VIDEO;
136 sbus_writeb(val, &regs->control);
137 par->flags &= ~BW2_FLAG_BLANKED;
138 break;
139
140 case FB_BLANK_NORMAL: /* Normal blanking */
141 case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */
142 case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */
143 case FB_BLANK_POWERDOWN: /* Poweroff */
144 val = sbus_readb(&regs->control);
145 val &= ~BWTWO_CTL_ENABLE_VIDEO;
146 sbus_writeb(val, &regs->control);
147 par->flags |= BW2_FLAG_BLANKED;
148 break;
149 }
150
151 spin_unlock_irqrestore(&par->lock, flags);
152
153 return 0;
154}
155
156static struct sbus_mmap_map bw2_mmap_map[] = {
157 {
158 .size = SBUS_MMAP_FBSIZE(1)
159 },
160 { .size = 0 }
161};
162
216d526c 163static int bw2_mmap(struct fb_info *info, struct vm_area_struct *vma)
1da177e4
LT
164{
165 struct bw2_par *par = (struct bw2_par *)info->par;
166
167 return sbusfb_mmap_helper(bw2_mmap_map,
3f06cd29 168 info->fix.smem_start, info->fix.smem_len,
50312ce9 169 par->which_io,
1da177e4
LT
170 vma);
171}
172
67a6680d 173static int bw2_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
1da177e4 174{
1da177e4 175 return sbusfb_ioctl_helper(cmd, arg, info,
3f06cd29 176 FBTYPE_SUN2BW, 1, info->fix.smem_len);
1da177e4
LT
177}
178
179/*
180 * Initialisation
181 */
182
63abdcdc 183static void __devinit bw2_init_fix(struct fb_info *info, int linebytes)
1da177e4
LT
184{
185 strlcpy(info->fix.id, "bwtwo", sizeof(info->fix.id));
186
187 info->fix.type = FB_TYPE_PACKED_PIXELS;
188 info->fix.visual = FB_VISUAL_MONO01;
189
190 info->fix.line_length = linebytes;
191
192 info->fix.accel = FB_ACCEL_SUN_BWTWO;
193}
194
63abdcdc 195static u8 bw2regs_1600[] __devinitdata = {
1da177e4
LT
196 0x14, 0x8b, 0x15, 0x28, 0x16, 0x03, 0x17, 0x13,
197 0x18, 0x7b, 0x19, 0x05, 0x1a, 0x34, 0x1b, 0x2e,
198 0x1c, 0x00, 0x1d, 0x0a, 0x1e, 0xff, 0x1f, 0x01,
199 0x10, 0x21, 0
200};
201
63abdcdc 202static u8 bw2regs_ecl[] __devinitdata = {
1da177e4
LT
203 0x14, 0x65, 0x15, 0x1e, 0x16, 0x04, 0x17, 0x0c,
204 0x18, 0x5e, 0x19, 0x03, 0x1a, 0xa7, 0x1b, 0x23,
205 0x1c, 0x00, 0x1d, 0x08, 0x1e, 0xff, 0x1f, 0x01,
206 0x10, 0x20, 0
207};
208
63abdcdc 209static u8 bw2regs_analog[] __devinitdata = {
1da177e4
LT
210 0x14, 0xbb, 0x15, 0x2b, 0x16, 0x03, 0x17, 0x13,
211 0x18, 0xb0, 0x19, 0x03, 0x1a, 0xa6, 0x1b, 0x22,
212 0x1c, 0x01, 0x1d, 0x05, 0x1e, 0xff, 0x1f, 0x01,
213 0x10, 0x20, 0
214};
215
63abdcdc 216static u8 bw2regs_76hz[] __devinitdata = {
1da177e4
LT
217 0x14, 0xb7, 0x15, 0x27, 0x16, 0x03, 0x17, 0x0f,
218 0x18, 0xae, 0x19, 0x03, 0x1a, 0xae, 0x1b, 0x2a,
219 0x1c, 0x01, 0x1d, 0x09, 0x1e, 0xff, 0x1f, 0x01,
220 0x10, 0x24, 0
221};
222
63abdcdc 223static u8 bw2regs_66hz[] __devinitdata = {
1da177e4
LT
224 0x14, 0xbb, 0x15, 0x2b, 0x16, 0x04, 0x17, 0x14,
225 0x18, 0xae, 0x19, 0x03, 0x1a, 0xa8, 0x1b, 0x24,
226 0x1c, 0x01, 0x1d, 0x05, 0x1e, 0xff, 0x1f, 0x01,
227 0x10, 0x20, 0
228};
229
6c8f5b90
DM
230static int __devinit bw2_do_default_mode(struct bw2_par *par,
231 struct fb_info *info,
232 int *linebytes)
1da177e4
LT
233{
234 u8 status, mon;
235 u8 *p;
236
237 status = sbus_readb(&par->regs->status);
238 mon = status & BWTWO_SR_RES_MASK;
239 switch (status & BWTWO_SR_ID_MASK) {
240 case BWTWO_SR_ID_MONO_ECL:
241 if (mon == BWTWO_SR_1600_1280) {
242 p = bw2regs_1600;
243 info->var.xres = info->var.xres_virtual = 1600;
244 info->var.yres = info->var.yres_virtual = 1280;
245 *linebytes = 1600 / 8;
246 } else
247 p = bw2regs_ecl;
248 break;
249
250 case BWTWO_SR_ID_MONO:
251 p = bw2regs_analog;
252 break;
253
254 case BWTWO_SR_ID_MSYNC:
255 if (mon == BWTWO_SR_1152_900_76_A ||
256 mon == BWTWO_SR_1152_900_76_B)
257 p = bw2regs_76hz;
258 else
259 p = bw2regs_66hz;
260 break;
261
262 case BWTWO_SR_ID_NOCONN:
6c8f5b90 263 return 0;
1da177e4
LT
264
265 default:
6c8f5b90
DM
266 printk(KERN_ERR "bw2: can't handle SR %02x\n",
267 status);
268 return -EINVAL;
1da177e4
LT
269 }
270 for ( ; *p; p += 2) {
271 u8 __iomem *regp = &((u8 __iomem *)par->regs)[p[0]];
272 sbus_writeb(p[1], regp);
273 }
6c8f5b90 274 return 0;
1da177e4
LT
275}
276
c7f439b9 277static int __devinit bw2_probe(struct of_device *op, const struct of_device_id *match)
1da177e4 278{
50312ce9 279 struct device_node *dp = op->node;
c7f439b9
DM
280 struct fb_info *info;
281 struct bw2_par *par;
50312ce9 282 int linebytes, err;
1da177e4 283
c7f439b9 284 info = framebuffer_alloc(sizeof(struct bw2_par), &op->dev);
1da177e4 285
c7f439b9
DM
286 err = -ENOMEM;
287 if (!info)
288 goto out_err;
289 par = info->par;
50312ce9 290
c7f439b9 291 spin_lock_init(&par->lock);
50312ce9 292
3f06cd29 293 info->fix.smem_start = op->resource[0].start;
c7f439b9
DM
294 par->which_io = op->resource[0].flags & IORESOURCE_BITS;
295
6cd5a86b 296 sbusfb_fill_var(&info->var, dp, 1);
50312ce9 297 linebytes = of_getintprop_default(dp, "linebytes",
c7f439b9 298 info->var.xres);
50312ce9 299
c7f439b9
DM
300 info->var.red.length = info->var.green.length =
301 info->var.blue.length = info->var.bits_per_pixel;
302 info->var.red.offset = info->var.green.offset =
303 info->var.blue.offset = 0;
1da177e4 304
c7f439b9
DM
305 par->regs = of_ioremap(&op->resource[0], BWTWO_REGISTER_OFFSET,
306 sizeof(struct bw2_regs), "bw2 regs");
307 if (!par->regs)
308 goto out_release_fb;
1da177e4 309
6c8f5b90
DM
310 if (!of_find_property(dp, "width", NULL)) {
311 err = bw2_do_default_mode(par, info, &linebytes);
312 if (err)
313 goto out_unmap_regs;
314 }
1da177e4 315
3f06cd29 316 info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres);
1da177e4 317
c7f439b9
DM
318 info->flags = FBINFO_DEFAULT;
319 info->fbops = &bw2_ops;
50312ce9 320
c7f439b9 321 info->screen_base = of_ioremap(&op->resource[0], 0,
3f06cd29 322 info->fix.smem_len, "bw2 ram");
c7f439b9
DM
323 if (!info->screen_base)
324 goto out_unmap_regs;
1da177e4 325
59f7137a 326 bw2_blank(FB_BLANK_UNBLANK, info);
1da177e4 327
c7f439b9 328 bw2_init_fix(info, linebytes);
1da177e4 329
c7f439b9
DM
330 err = register_framebuffer(info);
331 if (err < 0)
332 goto out_unmap_screen;
1da177e4 333
c7f439b9 334 dev_set_drvdata(&op->dev, info);
50312ce9 335
194f1a68 336 printk(KERN_INFO "%s: bwtwo at %lx:%lx\n",
3f06cd29 337 dp->full_name, par->which_io, info->fix.smem_start);
1da177e4 338
50312ce9 339 return 0;
1da177e4 340
c7f439b9 341out_unmap_screen:
3f06cd29 342 of_iounmap(&op->resource[0], info->screen_base, info->fix.smem_len);
c7f439b9
DM
343
344out_unmap_regs:
345 of_iounmap(&op->resource[0], par->regs, sizeof(struct bw2_regs));
346
347out_release_fb:
348 framebuffer_release(info);
1da177e4 349
c7f439b9
DM
350out_err:
351 return err;
50312ce9 352}
1da177e4 353
e3a411a3 354static int __devexit bw2_remove(struct of_device *op)
50312ce9 355{
c7f439b9
DM
356 struct fb_info *info = dev_get_drvdata(&op->dev);
357 struct bw2_par *par = info->par;
50312ce9 358
c7f439b9 359 unregister_framebuffer(info);
50312ce9 360
c7f439b9 361 of_iounmap(&op->resource[0], par->regs, sizeof(struct bw2_regs));
3f06cd29 362 of_iounmap(&op->resource[0], info->screen_base, info->fix.smem_len);
50312ce9 363
c7f439b9 364 framebuffer_release(info);
50312ce9 365
e3a411a3 366 dev_set_drvdata(&op->dev, NULL);
1da177e4
LT
367
368 return 0;
369}
370
fd098316 371static const struct of_device_id bw2_match[] = {
50312ce9
DM
372 {
373 .name = "bwtwo",
374 },
375 {},
376};
377MODULE_DEVICE_TABLE(of, bw2_match);
1da177e4 378
50312ce9
DM
379static struct of_platform_driver bw2_driver = {
380 .name = "bw2",
381 .match_table = bw2_match,
382 .probe = bw2_probe,
383 .remove = __devexit_p(bw2_remove),
384};
1da177e4 385
50312ce9
DM
386static int __init bw2_init(void)
387{
388 if (fb_get_options("bw2fb", NULL))
389 return -ENODEV;
390
391 return of_register_driver(&bw2_driver, &of_bus_type);
1da177e4
LT
392}
393
50312ce9 394static void __exit bw2_exit(void)
1da177e4 395{
2556bf12 396 of_unregister_driver(&bw2_driver);
1da177e4
LT
397}
398
50312ce9 399module_init(bw2_init);
1da177e4 400module_exit(bw2_exit);
1da177e4
LT
401
402MODULE_DESCRIPTION("framebuffer driver for BWTWO chipsets");
50312ce9
DM
403MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
404MODULE_VERSION("2.0");
1da177e4 405MODULE_LICENSE("GPL");