make oldconfig will rebuild these...
[linux-2.4.21-pre4.git] / drivers / video / leofb.c
1 /* $Id: leofb.c,v 1.1.1.1 2005/04/11 02:50:42 jack Exp $
2  * leofb.c: Leo (ZX) 24/8bit frame buffer driver
3  *
4  * Copyright (C) 1996-1999 Jakub Jelinek (jj@ultra.linux.cz)
5  * Copyright (C) 1997 Michal Rehacek (Michal.Rehacek@st.mff.cuni.cz)
6  */
7
8 #include <linux/module.h>
9 #include <linux/sched.h>
10 #include <linux/kernel.h>
11 #include <linux/errno.h>
12 #include <linux/string.h>
13 #include <linux/mm.h>
14 #include <linux/tty.h>
15 #include <linux/slab.h>
16 #include <linux/vmalloc.h>
17 #include <linux/delay.h>
18 #include <linux/interrupt.h>
19 #include <linux/fb.h>
20 #include <linux/init.h>
21 #include <linux/selection.h>
22
23 #include <video/sbusfb.h>
24 #include <asm/io.h>
25
26 #define LEO_OFF_LC_SS0_KRN      0x00200000UL
27 #define LEO_OFF_LC_SS0_USR      0x00201000UL
28 #define LEO_OFF_LC_SS1_KRN      0x01200000UL
29 #define LEO_OFF_LC_SS1_USR      0x01201000UL
30 #define LEO_OFF_LD_SS0          0x00400000UL
31 #define LEO_OFF_LD_SS1          0x01400000UL
32 #define LEO_OFF_LD_GBL          0x00401000UL
33 #define LEO_OFF_LX_KRN          0x00600000UL
34 #define LEO_OFF_LX_CURSOR       0x00601000UL
35 #define LEO_OFF_SS0             0x00800000UL
36 #define LEO_OFF_SS1             0x01800000UL
37 #define LEO_OFF_UNK             0x00602000UL
38 #define LEO_OFF_UNK2            0x00000000UL
39
40 #define LEO_CUR_ENABLE          0x00000080
41 #define LEO_CUR_UPDATE          0x00000030
42 #define LEO_CUR_PROGRESS        0x00000006
43 #define LEO_CUR_UPDATECMAP      0x00000003
44
45 #define LEO_CUR_TYPE_MASK       0x00000000
46 #define LEO_CUR_TYPE_IMAGE      0x00000020
47 #define LEO_CUR_TYPE_CMAP       0x00000050
48
49 struct leo_cursor {
50         u8              xxx0[16];
51         volatile u32    cur_type;
52         volatile u32    cur_misc;
53         volatile u32    cur_cursxy;
54         volatile u32    cur_data;
55 };
56
57 #define LEO_KRN_TYPE_CLUT0      0x00001000
58 #define LEO_KRN_TYPE_CLUT1      0x00001001
59 #define LEO_KRN_TYPE_CLUT2      0x00001002
60 #define LEO_KRN_TYPE_WID        0x00001003
61 #define LEO_KRN_TYPE_UNK        0x00001006
62 #define LEO_KRN_TYPE_VIDEO      0x00002003
63 #define LEO_KRN_TYPE_CLUTDATA   0x00004000
64 #define LEO_KRN_CSR_ENABLE      0x00000008
65 #define LEO_KRN_CSR_PROGRESS    0x00000004
66 #define LEO_KRN_CSR_UNK         0x00000002
67 #define LEO_KRN_CSR_UNK2        0x00000001
68
69 struct leo_lx_krn {
70         volatile u32    krn_type;
71         volatile u32    krn_csr;
72         volatile u32    krn_value;
73 };
74
75 struct leo_lc_ss0_krn {
76         volatile u32    misc;
77         u8              xxx0[0x800-4];
78         volatile u32    rev;
79 };
80
81 struct leo_lc_ss0_usr {
82         volatile u32    csr;
83         volatile u32    addrspace;
84         volatile u32    fontmsk;
85         volatile u32    fontt;
86         volatile u32    extent;
87         volatile u32    src;
88         u32             dst;
89         volatile u32    copy;
90         volatile u32    fill;
91 };
92
93 struct leo_lc_ss1_krn {
94         u8      unknown;
95 };
96
97 struct leo_lc_ss1_usr {
98         u8      unknown;
99 };
100
101 struct leo_ld {
102         u8              xxx0[0xe00];
103         volatile u32    csr;
104         volatile u32    wid;
105         volatile u32    wmask;
106         volatile u32    widclip;
107         volatile u32    vclipmin;
108         volatile u32    vclipmax;
109         volatile u32    pickmin;        /* SS1 only */
110         volatile u32    pickmax;        /* SS1 only */
111         volatile u32    fg;
112         volatile u32    bg;
113         volatile u32    src;            /* Copy/Scroll (SS0 only) */
114         volatile u32    dst;            /* Copy/Scroll/Fill (SS0 only) */
115         volatile u32    extent;         /* Copy/Scroll/Fill size (SS0 only) */
116         u32             xxx1[3];
117         volatile u32    setsem;         /* SS1 only */
118         volatile u32    clrsem;         /* SS1 only */
119         volatile u32    clrpick;        /* SS1 only */
120         volatile u32    clrdat;         /* SS1 only */
121         volatile u32    alpha;          /* SS1 only */
122         u8              xxx2[0x2c];
123         volatile u32    winbg;
124         volatile u32    planemask;
125         volatile u32    rop;
126         volatile u32    z;
127         volatile u32    dczf;           /* SS1 only */
128         volatile u32    dczb;           /* SS1 only */
129         volatile u32    dcs;            /* SS1 only */
130         volatile u32    dczs;           /* SS1 only */
131         volatile u32    pickfb;         /* SS1 only */
132         volatile u32    pickbb;         /* SS1 only */
133         volatile u32    dcfc;           /* SS1 only */
134         volatile u32    forcecol;       /* SS1 only */
135         volatile u32    door[8];        /* SS1 only */
136         volatile u32    pick[5];        /* SS1 only */
137 };
138
139 #define LEO_SS1_MISC_ENABLE     0x00000001
140 #define LEO_SS1_MISC_STEREO     0x00000002
141 struct leo_ld_ss1 {
142         u8              xxx0[0xef4];
143         volatile u32    ss1_misc;
144 };
145
146 struct leo_ld_gbl {
147         u8      unknown;
148 };
149
150 static struct sbus_mmap_map leo_mmap_map[] = {
151         { LEO_SS0_MAP,          LEO_OFF_SS0,            0x800000        },
152         { LEO_LC_SS0_USR_MAP,   LEO_OFF_LC_SS0_USR,     0x1000          },
153         { LEO_LD_SS0_MAP,       LEO_OFF_LD_SS0,         0x1000          },
154         { LEO_LX_CURSOR_MAP,    LEO_OFF_LX_CURSOR,      0x1000          },
155         { LEO_SS1_MAP,          LEO_OFF_SS1,            0x800000        },
156         { LEO_LC_SS1_USR_MAP,   LEO_OFF_LC_SS1_USR,     0x1000          },
157         { LEO_LD_SS1_MAP,       LEO_OFF_LD_SS1,         0x1000          },
158         { LEO_UNK_MAP,          LEO_OFF_UNK,            0x1000          },
159         { LEO_LX_KRN_MAP,       LEO_OFF_LX_KRN,         0x1000          },
160         { LEO_LC_SS0_KRN_MAP,   LEO_OFF_LC_SS0_KRN,     0x1000          },
161         { LEO_LC_SS1_KRN_MAP,   LEO_OFF_LC_SS1_KRN,     0x1000          },
162         { LEO_LD_GBL_MAP,       LEO_OFF_LD_GBL,         0x1000          },
163         { LEO_UNK2_MAP,         LEO_OFF_UNK2,           0x100000        },
164         { 0,                    0,                      0               }
165 };
166
167 static void leo_setup(struct display *p)
168 {
169         p->next_line = 8192;
170         p->next_plane = 0;
171 }
172
173 static void leo_clear(struct vc_data *conp, struct display *p, int sy, int sx,
174                       int height, int width)
175 {
176         struct fb_info_sbusfb *fb = (struct fb_info_sbusfb *)p->fb_info;
177         register struct leo_lc_ss0_usr *us = fb->s.leo.lc_ss0_usr;
178         register struct leo_ld *ss = (struct leo_ld *) fb->s.leo.ld_ss0;
179         unsigned long flags;
180         int x, y, w, h;
181         int i;
182
183         spin_lock_irqsave(&fb->lock, flags);
184         do {
185                 i = sbus_readl(&us->csr);
186         } while (i & 0x20000000);
187         sbus_writel((attr_bgcol_ec(p,conp)<<24), &ss->fg);
188         if (fontheightlog(p)) {
189                 y = sy << fontheightlog(p); h = height << fontheightlog(p);
190         } else {
191                 y = sy * fontheight(p); h = height * fontheight(p);
192         }
193         if (fontwidthlog(p)) {
194                 x = sx << fontwidthlog(p); w = width << fontwidthlog(p);
195         } else {
196                 x = sx * fontwidth(p); w = width * fontwidth(p);
197         }
198         sbus_writel((w - 1) | ((h - 1) << 11), &us->extent);
199         sbus_writel((x + fb->x_margin) | ((y + fb->y_margin) << 11) | 0x80000000,
200                     &us->fill);
201         spin_unlock_irqrestore(&fb->lock, flags);
202 }
203
204 static void leo_fill(struct fb_info_sbusfb *fb, struct display *p, int s,
205                      int count, unsigned short *boxes)
206 {
207         int i;
208         register struct leo_lc_ss0_usr *us = fb->s.leo.lc_ss0_usr;
209         register struct leo_ld *ss = (struct leo_ld *) fb->s.leo.ld_ss0;
210         unsigned long flags;
211         
212         spin_lock_irqsave(&fb->lock, flags);
213         sbus_writel((attr_bgcol(p,s)<<24), &ss->fg);
214         while (count-- > 0) {
215                 do {
216                         i = sbus_readl(&us->csr);
217                 } while (i & 0x20000000);
218                 sbus_writel((boxes[2] - boxes[0] - 1) | 
219                             ((boxes[3] - boxes[1] - 1) << 11),
220                             &us->extent);
221                 sbus_writel(boxes[0] | (boxes[1] << 11) | 0x80000000,
222                             &us->fill);
223                 boxes += 4;
224         }
225         spin_unlock_irqrestore(&fb->lock, flags);
226 }
227
228 static void leo_putc(struct vc_data *conp, struct display *p, int c, int yy, int xx)
229 {
230         struct fb_info_sbusfb *fb = (struct fb_info_sbusfb *)p->fb_info;
231         register struct leo_lc_ss0_usr *us = fb->s.leo.lc_ss0_usr;
232         register struct leo_ld *ss = (struct leo_ld *) fb->s.leo.ld_ss0;
233         unsigned long flags;
234         int i, x, y;
235         u8 *fd;
236         u32 *u;
237
238         spin_lock_irqsave(&fb->lock, flags);
239         if (fontheightlog(p)) {
240                 y = yy << (fontheightlog(p) + 11);
241                 i = (c & p->charmask) << fontheightlog(p);
242         } else {
243                 y = (yy * fontheight(p)) << 11;
244                 i = (c & p->charmask) * fontheight(p);
245         }
246         if (fontwidth(p) <= 8)
247                 fd = p->fontdata + i;
248         else
249                 fd = p->fontdata + (i << 1);
250         if (fontwidthlog(p))
251                 x = xx << fontwidthlog(p);
252         else
253                 x = xx * fontwidth(p);
254         do {
255                 i = sbus_readl(&us->csr);
256         } while (i & 0x20000000);
257         sbus_writel(attr_fgcol(p,c) << 24, &ss->fg);
258         sbus_writel(attr_bgcol(p,c) << 24, &ss->bg);
259         sbus_writel(0xFFFFFFFF<<(32-fontwidth(p)),
260                     &us->fontmsk);
261         u = ((u32 *)p->screen_base) + y + x;
262         if (fontwidth(p) <= 8) {
263                 for (i = 0; i < fontheight(p); i++, u += 2048) {
264                         u32 val = *fd++ << 24;
265
266                         sbus_writel(val, u);
267                 }
268         } else {
269                 for (i = 0; i < fontheight(p); i++, u += 2048) {
270                         u32 val = *(u16 *)fd << 16;
271
272                         sbus_writel(val, u);
273                         fd += 2;
274                 }
275         }
276         spin_unlock_irqrestore(&fb->lock, flags);
277 }
278
279 static void leo_putcs(struct vc_data *conp, struct display *p, const unsigned short *s,
280                       int count, int yy, int xx)
281 {
282         struct fb_info_sbusfb *fb = (struct fb_info_sbusfb *)p->fb_info;
283         register struct leo_lc_ss0_usr *us = fb->s.leo.lc_ss0_usr;
284         register struct leo_ld *ss = (struct leo_ld *) fb->s.leo.ld_ss0;
285         unsigned long flags;
286         int i, x, y;
287         u8 *fd1, *fd2, *fd3, *fd4;
288         u16 c;
289         u32 *u;
290
291         spin_lock_irqsave(&fb->lock, flags);
292         do {
293                 i = sbus_readl(&us->csr);
294         } while (i & 0x20000000);
295         c = scr_readw(s);
296         sbus_writel(attr_fgcol(p, c) << 24, &ss->fg);
297         sbus_writel(attr_bgcol(p, c) << 24, &ss->bg);
298         sbus_writel(0xFFFFFFFF<<(32-fontwidth(p)), &us->fontmsk);
299         if (fontwidthlog(p))
300                 x = (xx << fontwidthlog(p));
301         else
302                 x = xx * fontwidth(p);
303         if (fontheightlog(p))
304                 y = yy << (fontheightlog(p) + 11);
305         else
306                 y = (yy * fontheight(p)) << 11;
307         u = ((u32 *)p->screen_base) + y + x;
308         if (fontwidth(p) <= 8) {
309                 sbus_writel(0xFFFFFFFF<<(32-4*fontwidth(p)), &us->fontmsk);
310                 x = 4*fontwidth(p) - fontheight(p)*2048;
311                 while (count >= 4) {
312                         count -= 4;
313                         if (fontheightlog(p)) {
314                                 fd1 = p->fontdata + ((scr_readw(s++) & p->charmask) << fontheightlog(p));
315                                 fd2 = p->fontdata + ((scr_readw(s++) & p->charmask) << fontheightlog(p));
316                                 fd3 = p->fontdata + ((scr_readw(s++) & p->charmask) << fontheightlog(p));
317                                 fd4 = p->fontdata + ((scr_readw(s++) & p->charmask) << fontheightlog(p));
318                         } else {
319                                 fd1 = p->fontdata + ((scr_readw(s++) & p->charmask) * fontheight(p));
320                                 fd2 = p->fontdata + ((scr_readw(s++) & p->charmask) * fontheight(p));
321                                 fd3 = p->fontdata + ((scr_readw(s++) & p->charmask) * fontheight(p));
322                                 fd4 = p->fontdata + ((scr_readw(s++) & p->charmask) * fontheight(p));
323                         }
324                         if (fontwidth(p) == 8) {
325                                 for (i = 0; i < fontheight(p); i++, u += 2048) {
326                                         u32 val;
327
328                                         val = ((u32)*fd4++) | ((((u32)*fd3++) | ((((u32)*fd2++) | (((u32)*fd1++) 
329                                                 << 8)) << 8)) << 8);
330                                         sbus_writel(val, u);
331                                 }
332                                 u += x;
333                         } else {
334                                 for (i = 0; i < fontheight(p); i++, u += 2048) {
335                                         u32 val;
336
337                                         val = (((u32)*fd4++) | ((((u32)*fd3++) | ((((u32)*fd2++) | (((u32)*fd1++) 
338                                                 << fontwidth(p))) << fontwidth(p))) << fontwidth(p))) << (24 - 3 * fontwidth(p));
339                                         sbus_writel(val, u);
340                                 }
341                                 u += x;
342                         }
343                 }
344         } else {
345                 sbus_writel(0xFFFFFFFF<<(32-2*fontwidth(p)), &us->fontmsk);
346                 x = 2*fontwidth(p) - fontheight(p)*2048;
347                 while (count >= 2) {
348                         count -= 2;
349                         if (fontheightlog(p)) {
350                                 fd1 = p->fontdata + ((scr_readw(s++) & p->charmask) << (fontheightlog(p) + 1));
351                                 fd2 = p->fontdata + ((scr_readw(s++) & p->charmask) << (fontheightlog(p) + 1));
352                         } else {
353                                 fd1 = p->fontdata + (((scr_readw(s++) & p->charmask) * fontheight(p)) << 1);
354                                 fd2 = p->fontdata + (((scr_readw(s++) & p->charmask) * fontheight(p)) << 1);
355                         }
356                         for (i = 0; i < fontheight(p); i++, u += 2048) {
357                                 u32 val;
358
359                                 val = ((((u32)*(u16 *)fd1) << fontwidth(p)) | ((u32)*(u16 *)fd2)) << (16 - fontwidth(p));
360                                 sbus_writel(val, u);
361                                 fd1 += 2; fd2 += 2;
362                         }
363                         u += x;
364                 }
365         }
366         sbus_writel(0xFFFFFFFF<<(32-fontwidth(p)), &us->fontmsk);
367         x = fontwidth(p) - fontheight(p)*2048;
368         while (count) {
369                 count--;
370                 if (fontheightlog(p))
371                         i = ((scr_readw(s++) & p->charmask) << fontheightlog(p));
372                 else
373                         i = ((scr_readw(s++) & p->charmask) * fontheight(p));
374                 if (fontwidth(p) <= 8) {
375                         fd1 = p->fontdata + i;
376                         for (i = 0; i < fontheight(p); i++, u += 2048) {
377                                 u32 val = *fd1++ << 24;
378
379                                 sbus_writel(val, u);
380                         }
381                 } else {
382                         fd1 = p->fontdata + (i << 1);
383                         for (i = 0; i < fontheight(p); i++, u += 2048) {
384                                 u32 val = *(u16 *)fd1 << 16;
385
386                                 sbus_writel(val, u);
387                                 fd1 += 2;
388                         }
389                 }
390                 u += x;
391         }
392         spin_unlock_irqrestore(&fb->lock, flags);
393 }
394
395 static void leo_revc(struct display *p, int xx, int yy)
396 {
397         /* Not used if hw cursor */
398 }
399
400 static int leo_wait (struct leo_lx_krn *lx_krn)
401 {
402         int i;
403         
404         for (i = 0; (sbus_readl(&lx_krn->krn_csr) & LEO_KRN_CSR_PROGRESS) && i < 300000; i++)
405                 udelay (1); /* Busy wait at most 0.3 sec */
406         if (i == 300000)
407                 return -EFAULT; /* Timed out - should we print some message? */
408         return 0;
409 }
410
411 static void leo_loadcmap (struct fb_info_sbusfb *fb, struct display *p, int index, int count)
412 {
413         struct leo_lx_krn *lx_krn = fb->s.leo.lx_krn;
414         unsigned long flags;
415         u32 tmp;
416         int i;
417         
418         spin_lock_irqsave(&fb->lock, flags);
419         sbus_writel(LEO_KRN_TYPE_CLUT0, &lx_krn->krn_type);
420         i = leo_wait (lx_krn);
421         if (i)
422                 goto out;
423         sbus_writel(LEO_KRN_TYPE_CLUTDATA, &lx_krn->krn_type);
424         for (i = 0; i < 256; i++) {
425                 u32 val;
426
427                 val = fb->color_map CM(i,0) |
428                         (fb->color_map CM(i,1) << 8) |
429                         (fb->color_map CM(i,2) << 16);
430
431                 sbus_writel(val, &lx_krn->krn_value); /* Throw colors there :)) */
432         }
433         sbus_writel(LEO_KRN_TYPE_CLUT0, &lx_krn->krn_type);
434         tmp = sbus_readl(&lx_krn->krn_csr);
435         tmp |= (LEO_KRN_CSR_UNK|LEO_KRN_CSR_UNK2);
436         sbus_writel(tmp, &lx_krn->krn_csr);
437 out:
438         spin_unlock_irqrestore(&fb->lock, flags);
439 }
440
441 static void leo_restore_palette (struct fb_info_sbusfb *fb)
442 {
443         u32 tmp;
444         unsigned long flags;
445
446         spin_lock_irqsave(&fb->lock, flags);
447         tmp = sbus_readl(&fb->s.leo.ld_ss1->ss1_misc);
448         tmp &= ~(LEO_SS1_MISC_ENABLE);
449         sbus_writel(tmp, &fb->s.leo.ld_ss1->ss1_misc);
450         spin_unlock_irqrestore(&fb->lock, flags);
451 }
452
453 static struct display_switch leo_dispsw __initdata = {
454         setup:          leo_setup,
455         bmove:          fbcon_redraw_bmove,
456         clear:          leo_clear,
457         putc:           leo_putc,
458         putcs:          leo_putcs,
459         revc:           leo_revc, 
460         fontwidthmask:  FONTWIDTHRANGE(1,16) /* Allow fontwidths up to 16 */
461 };
462
463 static void leo_setcursormap (struct fb_info_sbusfb *fb, u8 *red, u8 *green, u8 *blue)
464 {
465         struct leo_cursor *l = fb->s.leo.cursor;
466         unsigned long flags;
467         int i;
468
469         spin_lock_irqsave(&fb->lock, flags);
470         for (i = 0; (sbus_readl(&l->cur_misc) & LEO_CUR_PROGRESS) && i < 300000; i++)
471                 udelay (1); /* Busy wait at most 0.3 sec */
472         if (i == 300000)
473                 goto out; /* Timed out - should we print some message? */
474         sbus_writel(LEO_CUR_TYPE_CMAP, &l->cur_type);
475         sbus_writel((red[0] | (green[0]<<8) | (blue[0]<<16)), &l->cur_data);
476         sbus_writel((red[1] | (green[1]<<8) | (blue[1]<<16)), &l->cur_data);
477         sbus_writel(LEO_CUR_UPDATECMAP, &l->cur_misc);
478 out:
479         spin_unlock_irqrestore(&fb->lock, flags);
480 }
481
482 /* Set cursor shape */
483 static void leo_setcurshape (struct fb_info_sbusfb *fb)
484 {
485         int i, j, k;
486         u32 m, n, mask;
487         struct leo_cursor *l = fb->s.leo.cursor;
488         u32 tmp;
489         unsigned long flags;
490
491         spin_lock_irqsave(&fb->lock, flags);
492         tmp = sbus_readl(&l->cur_misc);
493         tmp &= ~LEO_CUR_ENABLE;
494         sbus_writel(tmp, &l->cur_misc);
495         for (k = 0; k < 2; k ++) {
496                 sbus_writel((k * LEO_CUR_TYPE_IMAGE), &l->cur_type);
497                 for (i = 0; i < 32; i++) {
498                         mask = 0;
499                         m = fb->cursor.bits[k][i];
500                         /* mask = m with reversed bit order */
501                         for (j = 0, n = 1; j < 32; j++, n <<= 1)
502                                 if (m & n)
503                                         mask |= (0x80000000 >> j);
504                         sbus_writel(mask, &l->cur_data);
505                 }
506         }
507         tmp = sbus_readl(&l->cur_misc);
508         tmp |= LEO_CUR_ENABLE;
509         sbus_writel(tmp, &l->cur_misc);
510         spin_unlock_irqrestore(&fb->lock, flags);
511 }
512
513 /* Load cursor information */
514 static void leo_setcursor (struct fb_info_sbusfb *fb)
515 {
516         struct cg_cursor *c = &fb->cursor;
517         struct leo_cursor *l = fb->s.leo.cursor;
518         unsigned long flags;
519         u32 tmp;
520
521         spin_lock_irqsave(&fb->lock, flags);
522         tmp = sbus_readl(&l->cur_misc);
523         tmp &= ~LEO_CUR_ENABLE;
524         sbus_writel(tmp, &l->cur_misc);
525
526         sbus_writel(((c->cpos.fbx - c->chot.fbx) & 0x7ff) |
527                     (((c->cpos.fby - c->chot.fby) & 0x7ff) << 11),
528                     &l->cur_cursxy);
529
530         tmp = sbus_readl(&l->cur_misc);
531         tmp |= LEO_CUR_UPDATE;
532         if (c->enable)
533                 tmp |= LEO_CUR_ENABLE;
534         sbus_writel(tmp, &l->cur_misc);
535         spin_unlock_irqrestore(&fb->lock, flags);
536 }
537
538 static void leo_blank (struct fb_info_sbusfb *fb)
539 {
540         unsigned long flags;
541         u32 tmp;
542
543         spin_lock_irqsave(&fb->lock, flags);
544         sbus_writel(LEO_KRN_TYPE_VIDEO, &fb->s.leo.lx_krn->krn_type);
545
546         tmp = sbus_readl(&fb->s.leo.lx_krn->krn_csr);
547         tmp &= ~LEO_KRN_CSR_ENABLE;
548         sbus_writel(tmp, &fb->s.leo.lx_krn->krn_csr);
549         spin_unlock_irqrestore(&fb->lock, flags);
550 }
551
552 static void leo_unblank (struct fb_info_sbusfb *fb)
553 {
554         unsigned long flags;
555         u32 tmp;
556
557         spin_lock_irqsave(&fb->lock, flags);
558         sbus_writel(LEO_KRN_TYPE_VIDEO, &fb->s.leo.lx_krn->krn_type);
559
560         tmp = sbus_readl(&fb->s.leo.lx_krn->krn_csr);
561         if (!(tmp & LEO_KRN_CSR_ENABLE)) {
562                 tmp |= LEO_KRN_CSR_ENABLE;
563                 sbus_writel(tmp, &fb->s.leo.lx_krn->krn_csr);
564         }
565         spin_unlock_irqrestore(&fb->lock, flags);
566 }
567
568 static int __init
569 leo_wid_put (struct fb_info_sbusfb *fb, struct fb_wid_list *wl)
570 {
571         struct leo_lx_krn *lx_krn = fb->s.leo.lx_krn;
572         struct fb_wid_item *wi;
573         int i, j;
574
575         sbus_writel(LEO_KRN_TYPE_WID, &lx_krn->krn_type);
576         i = leo_wait (lx_krn);
577         if (i)
578                 return i;
579         for (i = 0, wi = wl->wl_list; i < wl->wl_count; i++, wi++) {
580                 switch (wi->wi_type) {
581                 case FB_WID_DBL_8: j = (wi->wi_index & 0xf) + 0x40; break;
582                 case FB_WID_DBL_24: j = wi->wi_index & 0x3f; break;
583                 default: return -EINVAL;
584                 }
585                 sbus_writel(0x5800 + j, &lx_krn->krn_type);
586                 sbus_writel(wi->wi_values[0], &lx_krn->krn_value);
587         }
588         sbus_writel(LEO_KRN_TYPE_WID, &lx_krn->krn_type);
589         sbus_writel(3, &lx_krn->krn_csr);
590         return 0;
591 }
592
593 static void leo_margins (struct fb_info_sbusfb *fb, struct display *p, int x_margin, int y_margin)
594 {
595         p->screen_base += 8192 * (y_margin - fb->y_margin) + 4 * (x_margin - fb->x_margin);
596 }
597
598 static void leo_switch_from_graph (struct fb_info_sbusfb *fb)
599 {
600         register struct leo_lc_ss0_usr *us = fb->s.leo.lc_ss0_usr;
601         register struct leo_ld *ss = (struct leo_ld *) fb->s.leo.ld_ss0;
602         unsigned long flags;
603
604         spin_lock_irqsave(&fb->lock, flags);
605         sbus_writel(0xffffffff, &ss->wid);
606         sbus_writel(0xffff, &ss->wmask);
607         sbus_writel(0, &ss->vclipmin);
608         sbus_writel(fb->s.leo.extent, &ss->vclipmax);
609         sbus_writel(0xff000000, &ss->planemask);
610         sbus_writel(0x310850, &ss->rop);
611         sbus_writel(0, &ss->widclip);
612         sbus_writel(4, &us->addrspace);
613         sbus_writel(0, &us->fontt);
614         spin_unlock_irqrestore(&fb->lock, flags);
615 }
616
617 static int __init leo_rasterimg (struct fb_info *info, int start)
618 {
619         struct fb_info_sbusfb *fb = sbusfbinfo(info);
620         register struct leo_lc_ss0_usr *us = fb->s.leo.lc_ss0_usr;
621         register struct leo_ld *ss = (struct leo_ld *) fb->s.leo.ld_ss0;
622
623         if (start) {
624                 sbus_writel(1, &ss->wid);
625                 sbus_writel(0xffffff, &ss->planemask); 
626                 sbus_writel(0x310b90, &ss->rop);
627                 sbus_writel(0, &us->addrspace);
628         } else {
629                 sbus_writel(0xffffffff, &ss->wid);
630                 sbus_writel(0xff000000, &ss->planemask);
631                 sbus_writel(0x310850, &ss->rop);
632                 sbus_writel(4, &us->addrspace);
633         }
634         return 0;
635 }
636
637 static char idstring[40] __initdata = { 0 };
638
639 char * __init leofb_init(struct fb_info_sbusfb *fb)
640 {
641         struct fb_fix_screeninfo *fix = &fb->fix;
642         struct fb_var_screeninfo *var = &fb->var;
643         struct display *disp = &fb->disp;
644         struct fbtype *type = &fb->type;
645         struct sbus_dev *sdev = fb->sbdp;
646         unsigned long phys = sdev->reg_addrs[0].phys_addr;
647         struct fb_wid_item wi;
648         struct fb_wid_list wl;
649         int i;
650         register struct leo_lc_ss0_usr *us;
651         register struct leo_ld *ss;
652         struct fb_ops *fbops;
653         u32 tmp;
654
655         strcpy(fb->info.modename, "Leo");
656                 
657         strcpy(fix->id, "Leo");
658         fix->visual = FB_VISUAL_TRUECOLOR;
659         fix->line_length = 8192;
660         fix->accel = FB_ACCEL_SUN_LEO;
661         
662         var->bits_per_pixel = 32;
663         var->green.offset = 8;
664         var->blue.offset = 16;
665         var->accel_flags = FB_ACCELF_TEXT;
666         
667         fbops = kmalloc(sizeof(*fbops), GFP_KERNEL);
668         if (fbops == NULL)
669                 return NULL;
670         
671         *fbops = *fb->info.fbops;
672         fbops->fb_rasterimg = leo_rasterimg;
673         fb->info.fbops = fbops;
674         
675         disp->scrollmode = SCROLL_YREDRAW;
676         if (!disp->screen_base) {
677                 disp->screen_base = (char *)
678                         sbus_ioremap(&sdev->resource[0], LEO_OFF_SS0,
679                                      0x800000, "leo ram");
680         }
681         disp->screen_base += 8192 * fb->y_margin + 4 * fb->x_margin;
682         us = fb->s.leo.lc_ss0_usr = (struct leo_lc_ss0_usr *)
683                 sbus_ioremap(&sdev->resource[0], LEO_OFF_LC_SS0_USR,
684                              0x1000, "leolc ss0usr");
685         fb->s.leo.ld_ss0 = (struct leo_ld_ss0 *)
686                 sbus_ioremap(&sdev->resource[0], LEO_OFF_LD_SS0,
687                              0x1000, "leold ss0");
688         ss = (struct leo_ld *) fb->s.leo.ld_ss0;
689         fb->s.leo.ld_ss1 = (struct leo_ld_ss1 *)
690                 sbus_ioremap(&sdev->resource[0], LEO_OFF_LD_SS1,
691                              0x1000, "leold ss1");
692         fb->s.leo.lx_krn = (struct leo_lx_krn *)
693                 sbus_ioremap(&sdev->resource[0], LEO_OFF_LX_KRN,
694                              0x1000, "leolx krn");
695         fb->s.leo.cursor = (struct leo_cursor *)
696                 sbus_ioremap(&sdev->resource[0], LEO_OFF_LX_CURSOR,
697                              sizeof(struct leo_cursor), "leolx cursor");
698         fb->dispsw = leo_dispsw;
699         
700         fb->s.leo.extent = (type->fb_width-1) | ((type->fb_height-1) << 16);
701
702         wl.wl_count = 1;
703         wl.wl_list = &wi;
704         wi.wi_type = FB_WID_DBL_8;
705         wi.wi_index = 0;
706         wi.wi_values [0] = 0x2c0;
707         leo_wid_put (fb, &wl);
708         wi.wi_index = 1;
709         wi.wi_values [0] = 0x30;
710         leo_wid_put (fb, &wl);
711         wi.wi_index = 2;
712         wi.wi_values [0] = 0x20;
713         leo_wid_put (fb, &wl);
714         wi.wi_type = FB_WID_DBL_24;
715         wi.wi_index = 1;
716         wi.wi_values [0] = 0x30;
717         leo_wid_put (fb, &wl);
718
719         tmp = sbus_readl(&fb->s.leo.ld_ss1->ss1_misc);
720         tmp |= LEO_SS1_MISC_ENABLE;
721         sbus_writel(tmp, &fb->s.leo.ld_ss1->ss1_misc);
722
723         sbus_writel(0xffffffff, &ss->wid);
724         sbus_writel(0xffff, &ss->wmask);
725         sbus_writel(0, &ss->vclipmin);
726         sbus_writel(fb->s.leo.extent, &ss->vclipmax);
727         sbus_writel(0, &ss->fg);
728         sbus_writel(0xff000000, &ss->planemask);
729         sbus_writel(0x310850, &ss->rop);
730         sbus_writel(0, &ss->widclip);
731         sbus_writel((type->fb_width-1) | ((type->fb_height-1) << 11), &us->extent);
732         sbus_writel(4, &us->addrspace);
733         sbus_writel(0x80000000, &us->fill);
734         sbus_writel(0, &us->fontt);
735         do {
736                 i = sbus_readl(&us->csr);
737         } while (i & 0x20000000);
738
739         fb->margins = leo_margins;
740         fb->loadcmap = leo_loadcmap;
741         fb->setcursor = leo_setcursor;
742         fb->setcursormap = leo_setcursormap;
743         fb->setcurshape = leo_setcurshape;
744         fb->restore_palette = leo_restore_palette;
745         fb->switch_from_graph = leo_switch_from_graph;
746         fb->fill = leo_fill;
747         fb->blank = leo_blank;
748         fb->unblank = leo_unblank;
749         
750         fb->physbase = phys;
751         fb->mmap_map = leo_mmap_map;
752         
753 #ifdef __sparc_v9__
754         sprintf(idstring, "leo at %016lx", phys);
755 #else   
756         sprintf(idstring, "leo at %x.%08lx", fb->iospace, phys);
757 #endif
758                     
759         return idstring;
760 }
761
762 MODULE_LICENSE("GPL");