1 /* $Id: newport_con.c,v 1.13 1999/04/11 10:37:08 ulfc Exp $
3 * newport_con.c: Abscon for newport hardware
5 * (C) 1998 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
6 * (C) 1999 Ulf Carlsson (ulfc@bun.falkenberg.se)
8 * This driver is based on sgicons.c and cons_newport.
10 * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
11 * Copyright (C) 1997 Miguel de Icaza (miguel@nuclecu.unam.mx)
13 #include <linux/init.h>
14 #include <linux/kernel.h>
15 #include <linux/errno.h>
16 #include <linux/tty.h>
18 #include <linux/selection.h>
19 #include <linux/console.h>
20 #include <linux/console_struct.h>
21 #include <linux/vt_kern.h>
23 #include <linux/module.h>
25 #include <asm/uaccess.h>
26 #include <asm/system.h>
28 #include <asm/pgtable.h>
29 #include <asm/newport.h>
30 #define INCLUDE_LINUX_LOGO_DATA
31 #include <asm/linux_logo.h>
36 extern unsigned char vga_font
[];
37 extern struct newport_regs
*npregs
;
39 static int logo_active
;
41 static int xcurs_correction
= 29;
42 static int newport_xsize
;
43 static int newport_ysize
;
45 #define BMASK(c) (c << 24)
47 #define RENDER(regs, cp) do { \
48 (regs)->go.zpattern = BMASK((cp)[0x0]); (regs)->go.zpattern = BMASK((cp)[0x1]); \
49 (regs)->go.zpattern = BMASK((cp)[0x2]); (regs)->go.zpattern = BMASK((cp)[0x3]); \
50 (regs)->go.zpattern = BMASK((cp)[0x4]); (regs)->go.zpattern = BMASK((cp)[0x5]); \
51 (regs)->go.zpattern = BMASK((cp)[0x6]); (regs)->go.zpattern = BMASK((cp)[0x7]); \
52 (regs)->go.zpattern = BMASK((cp)[0x8]); (regs)->go.zpattern = BMASK((cp)[0x9]); \
53 (regs)->go.zpattern = BMASK((cp)[0xa]); (regs)->go.zpattern = BMASK((cp)[0xb]); \
54 (regs)->go.zpattern = BMASK((cp)[0xc]); (regs)->go.zpattern = BMASK((cp)[0xd]); \
55 (regs)->go.zpattern = BMASK((cp)[0xe]); (regs)->go.zpattern = BMASK((cp)[0xf]); \
58 #define TESTVAL 0xdeadbeef
59 #define XSTI_TO_FXSTART(val) (((val) & 0xffff) << 11)
61 static inline void newport_render_background(int xstart
, int ystart
,
62 int xend
, int yend
, int ci
)
65 npregs
->set
.wrmask
= 0xffffffff;
66 npregs
->set
.drawmode0
= (NPORT_DMODE0_DRAW
| NPORT_DMODE0_BLOCK
|
67 NPORT_DMODE0_DOSETUP
| NPORT_DMODE0_STOPX
|
69 npregs
->set
.colori
= ci
;
70 npregs
->set
.xystarti
= (xstart
<< 16) | ((ystart
+ topscan
) & 0x3ff);
71 npregs
->go
.xyendi
= ((xend
+ 7) << 16) | ((yend
+ topscan
+ 15) & 0x3ff);
74 static inline void newport_init_cmap(void)
78 for(i
= 0; i
< 16; i
++) {
80 newport_cmap_setaddr(npregs
, color_table
[i
]);
81 newport_cmap_setrgb(npregs
,
88 static inline void newport_show_logo(void)
92 for(i
= 0; i
< LINUX_LOGO_COLORS
; i
++) {
94 newport_cmap_setaddr(npregs
, i
+ 0x20);
95 newport_cmap_setrgb(npregs
,
102 npregs
->set
.drawmode0
= (NPORT_DMODE0_DRAW
| NPORT_DMODE0_BLOCK
|
105 npregs
->set
.xystarti
= ((newport_xsize
- LOGO_W
) << 16) | (0);
106 npregs
->set
.xyendi
= ((newport_xsize
- 1) << 16);
109 for (i
= 0; i
< LOGO_W
* LOGO_H
; i
++)
110 npregs
->go
.hostrw0
= linux_logo
[i
] << 24;
113 static inline void newport_clear_screen(int xstart
, int ystart
, int xend
,
119 npregs
->set
.wrmask
= 0xffffffff;
120 npregs
->set
.drawmode0
= (NPORT_DMODE0_DRAW
| NPORT_DMODE0_BLOCK
|
121 NPORT_DMODE0_DOSETUP
| NPORT_DMODE0_STOPX
|
123 npregs
->set
.colori
= ci
;
124 npregs
->set
.xystarti
= (xstart
<< 16) | ystart
;
125 npregs
->go
.xyendi
= (xend
<< 16) | yend
;
128 static inline void newport_clear_lines(int ystart
, int yend
, int ci
)
130 ystart
= ((ystart
<< 4) + topscan
) & 0x3ff;
131 yend
= ((yend
<< 4) + topscan
+ 15) & 0x3ff;
132 newport_clear_screen (0, ystart
, 1280+63, yend
, ci
);
135 void newport_reset (void)
141 treg
= newport_vc2_get(npregs
, VC2_IREG_CONTROL
);
142 newport_vc2_set(npregs
, VC2_IREG_CONTROL
, (treg
| VC2_CTRL_EVIDEO
));
144 treg
= newport_vc2_get(npregs
, VC2_IREG_CENTRY
);
145 newport_vc2_set(npregs
, VC2_IREG_RADDR
, treg
);
146 npregs
->set
.dcbmode
= (NPORT_DMODE_AVC2
| VC2_REGADDR_RAM
|
147 NPORT_DMODE_W2
| VC2_PROTOCOL
);
148 for(i
= 0; i
< 128; i
++) {
150 if (i
== 92 || i
== 94)
151 npregs
->set
.dcbdata0
.hwords
.s1
= 0xff00;
153 npregs
->set
.dcbdata0
.hwords
.s1
= 0x0000;
158 /* turn off popup plane */
159 npregs
->set
.dcbmode
= (DCB_XMAP0
| R_DCB_XMAP9_PROTOCOL
|
160 XM9_CRS_CONFIG
| NPORT_DMODE_W1
);
161 npregs
->set
.dcbdata0
.bytes
.b3
&= ~XM9_PUPMODE
;
162 npregs
->set
.dcbmode
= (DCB_XMAP1
| R_DCB_XMAP9_PROTOCOL
|
163 XM9_CRS_CONFIG
| NPORT_DMODE_W1
);
164 npregs
->set
.dcbdata0
.bytes
.b3
&= ~XM9_PUPMODE
;
167 npregs
->cset
.topscan
= 0x3ff;
168 npregs
->cset
.xywin
= (4096 << 16) | 4096;
170 /* Clear the screen. */
171 newport_clear_screen(0,0,1280+63,1024,0);
175 * calculate the actual screen size by reading
176 * the video timing out of the VC2
178 void newport_get_screensize(void)
181 unsigned short ventry
,treg
;
182 unsigned short linetable
[128]; /* should be enough */
184 ventry
= newport_vc2_get (npregs
, VC2_IREG_VENTRY
);
185 newport_vc2_set(npregs
, VC2_IREG_RADDR
, ventry
);
186 npregs
->set
.dcbmode
= (NPORT_DMODE_AVC2
| VC2_REGADDR_RAM
|
187 NPORT_DMODE_W2
| VC2_PROTOCOL
);
188 for(i
= 0; i
< 128; i
++) {
190 linetable
[i
] = npregs
->set
.dcbdata0
.hwords
.s1
;
193 newport_xsize
= newport_ysize
= 0;
194 for (i
= 0; linetable
[i
+1] && (i
< sizeof(linetable
)); i
+=2) {
196 newport_vc2_set(npregs
, VC2_IREG_RADDR
, linetable
[i
]);
197 npregs
->set
.dcbmode
= (NPORT_DMODE_AVC2
| VC2_REGADDR_RAM
|
198 NPORT_DMODE_W2
| VC2_PROTOCOL
);
201 treg
= npregs
->set
.dcbdata0
.hwords
.s1
;
203 cols
+= (treg
>> 7) & 0xfe;
204 if ((treg
& 0x80) == 0) {
206 treg
= npregs
->set
.dcbdata0
.hwords
.s1
;
208 } while ((treg
& 0x8000) == 0);
210 if (cols
> newport_xsize
)
211 newport_xsize
= cols
;
212 newport_ysize
+= linetable
[i
+1];
215 printk ("NG1: Screensize %dx%d\n",newport_xsize
,newport_ysize
);
218 static void newport_get_revisions(void)
221 unsigned int board_rev
;
222 unsigned int rex3_rev
;
223 unsigned int vc2_rev
;
224 unsigned int cmap_rev
;
225 unsigned int xmap9_rev
;
226 unsigned int bt445_rev
;
227 unsigned int bitplanes
;
229 rex3_rev
= npregs
->cset
.stat
& NPORT_STAT_VERS
;
231 npregs
->set
.dcbmode
= (DCB_CMAP0
| NCMAP_PROTOCOL
|
232 NCMAP_REGADDR_RREG
| NPORT_DMODE_W1
);
233 tmp
= npregs
->set
.dcbdata0
.bytes
.b3
;
235 board_rev
= (tmp
>> 4) & 7;
236 bitplanes
= ((board_rev
> 1) && (tmp
& 0x80)) ? 8 : 24;
238 npregs
->set
.dcbmode
= (DCB_CMAP1
| NCMAP_PROTOCOL
|
239 NCMAP_REGADDR_RREG
| NPORT_DMODE_W1
);
240 tmp
= npregs
->set
.dcbdata0
.bytes
.b3
;
241 if ((tmp
& 7) < cmap_rev
)
242 cmap_rev
= (tmp
& 7);
244 vc2_rev
= (newport_vc2_get(npregs
, VC2_IREG_CONFIG
) >> 5) & 7;
246 npregs
->set
.dcbmode
= (DCB_XMAP0
| R_DCB_XMAP9_PROTOCOL
|
247 XM9_CRS_REVISION
| NPORT_DMODE_W1
);
248 xmap9_rev
= npregs
->set
.dcbdata0
.bytes
.b3
& 7;
250 npregs
->set
.dcbmode
= (DCB_BT445
| BT445_PROTOCOL
|
251 BT445_CSR_ADDR_REG
| NPORT_DMODE_W1
);
252 npregs
->set
.dcbdata0
.bytes
.b3
= BT445_REVISION_REG
;
253 npregs
->set
.dcbmode
= (DCB_BT445
| BT445_PROTOCOL
|
254 BT445_CSR_REVISION
| NPORT_DMODE_W1
);
255 bt445_rev
= (npregs
->set
.dcbdata0
.bytes
.b3
>> 4) - 0x0a;
257 #define L(a) (char)('A'+(a))
258 printk ("NG1: Revision %d, %d bitplanes, REX3 revision %c, VC2 revision %c, xmap9 revision %c, cmap revision %c, bt445 revision %c\n",
259 board_rev
,bitplanes
,L(rex3_rev
),L(vc2_rev
), L(xmap9_rev
),
260 L(cmap_rev
? (cmap_rev
+1):0),L(bt445_rev
));
263 if (board_rev
== 3) /* I don't know all affected revisions */
264 xcurs_correction
= 21;
268 static const char *newport_startup(void)
270 __initfunc(static const char *newport_startup(void))
273 struct newport_regs
*p
;
275 npregs
= (struct newport_regs
*) (KSEG1
+ 0x1f0f0000);
278 p
->cset
.config
= NPORT_CFG_GD0
;
284 p
->set
.xstarti
= TESTVAL
; if(p
->set
._xstart
.i
!= XSTI_TO_FXSTART(TESTVAL
)) {
289 newport_get_revisions();
290 newport_get_screensize();
292 // gfx_init (display_desc);
294 return "SGI Newport";
297 static void newport_init(struct vc_data
*vc
, int init
)
299 vc
->vc_cols
= newport_xsize
/ 8;
300 vc
->vc_rows
= newport_ysize
/ 16;
301 vc
->vc_can_do_color
= 1;
304 static void newport_clear(struct vc_data
*vc
, int sy
, int sx
, int height
, int width
)
306 int xend
= ((sx
+ width
) << 3) - 1;
307 int ystart
= ((sy
<< 4) + topscan
) & 0x3ff;
308 int yend
= (((sy
+ height
) << 4) + topscan
- 1) & 0x3ff;
314 newport_clear_screen(sx
<< 3, ystart
, xend
, yend
,
315 (vc
->vc_color
& 0xf0) >> 4);
317 newport_clear_screen(sx
<< 3, ystart
, xend
, 1023,
318 (vc
->vc_color
& 0xf0) >> 4);
319 newport_clear_screen(sx
<< 3, 0, xend
, yend
,
320 (vc
->vc_color
& 0xf0) >> 4);
324 static void newport_putc(struct vc_data
*vc
, int charattr
, int ypos
, int xpos
)
328 p
= &vga_font
[(charattr
& 0xff) << 4];
329 charattr
= (charattr
>> 8) & 0xff;
333 newport_render_background(xpos
, ypos
, xpos
, ypos
, (charattr
& 0xf0) >> 4);
335 /* Set the color and drawing mode. */
337 npregs
->set
.colori
= charattr
& 0xf;
338 npregs
->set
.drawmode0
= (NPORT_DMODE0_DRAW
| NPORT_DMODE0_BLOCK
|
339 NPORT_DMODE0_STOPX
| NPORT_DMODE0_ZPENAB
|
342 /* Set coordinates for bitmap operation. */
343 npregs
->set
.xystarti
= (xpos
<< 16) | ((ypos
+ topscan
) & 0x3ff);
344 npregs
->set
.xyendi
= ((xpos
+ 7) << 16);
347 /* Go, baby, go... */
351 static void newport_putcs(struct vc_data
*vc
, const unsigned short *s
,
352 int count
, int ypos
, int xpos
)
358 charattr
= (*s
>> 8) & 0xff;
364 /* Clear the area behing the string */
365 newport_render_background(xpos
, ypos
, xpos
+ ((count
-1) << 3), ypos
,
366 (charattr
& 0xf0) >> 4);
370 /* Set the color and drawing mode. */
371 npregs
->set
.colori
= charattr
& 0xf;
372 npregs
->set
.drawmode0
= (NPORT_DMODE0_DRAW
| NPORT_DMODE0_BLOCK
|
373 NPORT_DMODE0_STOPX
| NPORT_DMODE0_ZPENAB
|
376 for (i
= 0; i
< count
; i
++, xpos
+= 8) {
377 p
= &vga_font
[(s
[i
] & 0xff) << 4];
381 /* Set coordinates for bitmap operation. */
382 npregs
->set
.xystarti
= (xpos
<< 16) | ((ypos
+ topscan
) & 0x3ff);
383 npregs
->set
.xyendi
= ((xpos
+ 7) << 16);
385 /* Go, baby, go... */
390 static void newport_cursor(struct vc_data
*vc
, int mode
)
397 treg
= newport_vc2_get(npregs
, VC2_IREG_CONTROL
);
398 newport_vc2_set(npregs
, VC2_IREG_CONTROL
, (treg
& ~(VC2_CTRL_ECDISP
)));
403 treg
= newport_vc2_get(npregs
, VC2_IREG_CONTROL
);
404 newport_vc2_set(npregs
, VC2_IREG_CONTROL
, (treg
| VC2_CTRL_ECDISP
));
405 xcurs
= (vc
->vc_pos
- vc
->vc_visible_origin
) / 2;
406 ycurs
= ((xcurs
/ vc
->vc_cols
) << 4) + 31;
407 xcurs
= ((xcurs
% vc
->vc_cols
) << 3) + xcurs_correction
;
408 newport_vc2_set(npregs
, VC2_IREG_CURSX
, xcurs
);
409 newport_vc2_set(npregs
, VC2_IREG_CURSY
, ycurs
);
413 static int newport_switch(struct vc_data
*vc
)
415 static int logo_drawn
= 0;
418 npregs
->cset
.topscan
= 0x3ff;
429 static int newport_blank(struct vc_data
*c
, int blank
)
434 /* unblank console */
435 treg
= newport_vc2_get(npregs
, VC2_IREG_CONTROL
);
436 newport_vc2_set(npregs
, VC2_IREG_CONTROL
, (treg
| VC2_CTRL_EDISP
));
439 treg
= newport_vc2_get(npregs
, VC2_IREG_CONTROL
);
440 newport_vc2_set(npregs
, VC2_IREG_CONTROL
, (treg
& ~(VC2_CTRL_EDISP
)));
445 static int newport_font_op(struct vc_data
*vc
, struct console_font_op
*f
)
450 static int newport_set_palette(struct vc_data
*vc
, unsigned char *table
)
455 static int newport_scrolldelta(struct vc_data
*vc
, int lines
)
457 /* there is (nearly) no off-screen memory, so we can't scroll back */
461 static int newport_scroll(struct vc_data
*vc
, int t
, int b
, int dir
, int lines
)
464 unsigned short *s
, *d
;
465 unsigned short chattr
;
467 logo_active
= 0; /* it's time to disable the logo now.. */
469 if (t
== 0 && b
== vc
->vc_rows
) {
471 topscan
= (topscan
+ (lines
<< 4)) & 0x3ff;
472 newport_clear_lines (vc
->vc_rows
-lines
,vc
->vc_rows
-1,
473 (vc
->vc_color
& 0xf0) >> 4);
475 topscan
= (topscan
+ (-lines
<< 4)) & 0x3ff;
476 newport_clear_lines (0,lines
-1, (vc
->vc_color
& 0xf0) >> 4);
478 npregs
->cset
.topscan
= (topscan
- 1) & 0x3ff;
482 count
= (b
-t
-lines
) * vc
->vc_cols
;
485 s
= (unsigned short *)(vc
->vc_origin
+ vc
->vc_size_row
*(t
+lines
));
486 d
= (unsigned short *)(vc
->vc_origin
+ vc
->vc_size_row
*t
);
488 chattr
= scr_readw (s
++);
489 if (chattr
!= scr_readw(d
)) {
490 newport_putc (vc
, chattr
, y
, x
);
491 scr_writew (chattr
, d
);
494 if (++x
== vc
->vc_cols
) {
498 d
= (unsigned short *)(vc
->vc_origin
+ vc
->vc_size_row
*(b
-lines
));
500 for (count
= 0; count
< (lines
* vc
->vc_cols
); count
++) {
501 if (scr_readw(d
) != vc
->vc_video_erase_char
) {
502 newport_putc (vc
, chattr
, y
, x
);
503 scr_writew (vc
->vc_video_erase_char
, d
);
506 if (++x
== vc
->vc_cols
) {
511 x
= vc
->vc_cols
-1; y
= b
-1;
512 s
= (unsigned short *)(vc
->vc_origin
+ vc
->vc_size_row
*(b
-lines
)-2);
513 d
= (unsigned short *)(vc
->vc_origin
+ vc
->vc_size_row
*b
-2);
515 chattr
= scr_readw (s
--);
516 if (chattr
!= scr_readw(d
)) {
517 newport_putc (vc
, chattr
, y
, x
);
518 scr_writew (chattr
, d
);
522 x
= vc
->vc_cols
-1; y
--;
525 d
= (unsigned short *)(vc
->vc_origin
+ vc
->vc_size_row
*t
);
527 for (count
= 0; count
< (lines
* vc
->vc_cols
); count
++) {
528 if (scr_readw(d
) != vc
->vc_video_erase_char
) {
529 newport_putc (vc
, vc
->vc_video_erase_char
, y
, x
);
530 scr_writew (vc
->vc_video_erase_char
, d
);
533 if (++x
== vc
->vc_cols
) {
541 static void newport_bmove(struct vc_data
*vc
, int sy
, int sx
, int dy
, int dx
, int h
, int w
)
543 short xs
, ys
, xe
, ye
, xoffs
, yoffs
, tmp
;
545 xs
= sx
<< 3; xe
= ((sx
+w
) << 3)-1;
547 * as bmove is only used to move stuff around in the same line
548 * (h == 1), we don't care about wrap arounds caused by topscan != 0
550 ys
= ((sy
<< 4) + topscan
) & 0x3ff; ye
= (((sy
+h
) << 4)-1+topscan
) & 0x3ff;
551 xoffs
= (dx
- sx
) << 3;
552 yoffs
= (dy
- sy
) << 4;
554 /* move to the right, exchange starting points */
555 tmp
= xe
; xe
= xs
; xs
= tmp
;
558 npregs
->set
.drawmode0
= (NPORT_DMODE0_S2S
| NPORT_DMODE0_BLOCK
|
559 NPORT_DMODE0_DOSETUP
| NPORT_DMODE0_STOPX
|
561 npregs
->set
.xystarti
= (xs
<< 16) | ys
;
562 npregs
->set
.xyendi
= (xe
<< 16) | ye
;
563 npregs
->go
.xymove
= (xoffs
<< 16) | yoffs
;
566 static int newport_dummy(struct vc_data
*c
)
571 #define DUMMY (void *) newport_dummy
573 struct consw newport_con
= {
576 DUMMY
, /* con_deinit */
588 DUMMY
, /* newport_set_origin, */
589 DUMMY
, /* newport_save_screen */
590 NULL
, /* newport_build_attr */
591 NULL
/* newport_invert_region */
596 int init_module(void) {
597 if (!newport_startup())
598 printk("Error loading SGI Newport Console driver\n");
600 printk("Loading SGI Newport Console Driver\n");
602 take_over_console(&newport_con
,0,MAX_NR_CONSOLES
-1,1);
607 int cleanup_module(void) {
608 printk("Unloading SGI Newport Console Driver\n");