2 * newport_con.c: Abscon for newport hardware
4 * (C) 1998 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
5 * (C) 1999 Ulf Carlsson (ulfc@thepuffingruop.com)
7 * This driver is based on sgicons.c and cons_newport.
9 * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
10 * Copyright (C) 1997 Miguel de Icaza (miguel@nuclecu.unam.mx)
12 #include <linux/init.h>
13 #include <linux/kernel.h>
14 #include <linux/errno.h>
15 #include <linux/tty.h>
17 #include <linux/selection.h>
18 #include <linux/console.h>
19 #include <linux/console_struct.h>
20 #include <linux/vt_kern.h>
22 #include <linux/module.h>
24 #include <asm/uaccess.h>
25 #include <asm/system.h>
27 #include <asm/pgtable.h>
28 #include <video/newport.h>
29 #define INCLUDE_LINUX_LOGO_DATA
30 #include <asm/linux_logo.h>
32 #include <video/font.h>
37 extern struct fbcon_font_desc font_vga_8x16
;
39 #define FONT_DATA ((unsigned char *)font_vga_8x16.data)
41 extern struct newport_regs
*npregs
;
43 static int logo_active
;
45 static int xcurs_correction
= 29;
46 static int newport_xsize
;
47 static int newport_ysize
;
49 #define BMASK(c) (c << 24)
51 #define RENDER(regs, cp) do { \
52 (regs)->go.zpattern = BMASK((cp)[0x0]); (regs)->go.zpattern = BMASK((cp)[0x1]); \
53 (regs)->go.zpattern = BMASK((cp)[0x2]); (regs)->go.zpattern = BMASK((cp)[0x3]); \
54 (regs)->go.zpattern = BMASK((cp)[0x4]); (regs)->go.zpattern = BMASK((cp)[0x5]); \
55 (regs)->go.zpattern = BMASK((cp)[0x6]); (regs)->go.zpattern = BMASK((cp)[0x7]); \
56 (regs)->go.zpattern = BMASK((cp)[0x8]); (regs)->go.zpattern = BMASK((cp)[0x9]); \
57 (regs)->go.zpattern = BMASK((cp)[0xa]); (regs)->go.zpattern = BMASK((cp)[0xb]); \
58 (regs)->go.zpattern = BMASK((cp)[0xc]); (regs)->go.zpattern = BMASK((cp)[0xd]); \
59 (regs)->go.zpattern = BMASK((cp)[0xe]); (regs)->go.zpattern = BMASK((cp)[0xf]); \
62 #define TESTVAL 0xdeadbeef
63 #define XSTI_TO_FXSTART(val) (((val) & 0xffff) << 11)
65 static inline void newport_render_background(int xstart
, int ystart
,
66 int xend
, int yend
, int ci
)
69 npregs
->set
.wrmask
= 0xffffffff;
70 npregs
->set
.drawmode0
= (NPORT_DMODE0_DRAW
| NPORT_DMODE0_BLOCK
|
71 NPORT_DMODE0_DOSETUP
| NPORT_DMODE0_STOPX
|
73 npregs
->set
.colori
= ci
;
74 npregs
->set
.xystarti
= (xstart
<< 16) | ((ystart
+ topscan
) & 0x3ff);
75 npregs
->go
.xyendi
= ((xend
+ 7) << 16) | ((yend
+ topscan
+ 15) & 0x3ff);
78 static inline void newport_init_cmap(void)
82 for(i
= 0; i
< 16; i
++) {
84 newport_cmap_setaddr(npregs
, color_table
[i
]);
85 newport_cmap_setrgb(npregs
,
92 static inline void newport_show_logo(void)
96 for(i
= 0; i
< LINUX_LOGO_COLORS
; i
++) {
98 newport_cmap_setaddr(npregs
, i
+ 0x20);
99 newport_cmap_setrgb(npregs
,
106 npregs
->set
.drawmode0
= (NPORT_DMODE0_DRAW
| NPORT_DMODE0_BLOCK
|
109 npregs
->set
.xystarti
= ((newport_xsize
- LOGO_W
) << 16) | (0);
110 npregs
->set
.xyendi
= ((newport_xsize
- 1) << 16);
113 for (i
= 0; i
< LOGO_W
* LOGO_H
; i
++)
114 npregs
->go
.hostrw0
= linux_logo
[i
] << 24;
117 static inline void newport_clear_screen(int xstart
, int ystart
, int xend
,
123 npregs
->set
.wrmask
= 0xffffffff;
124 npregs
->set
.drawmode0
= (NPORT_DMODE0_DRAW
| NPORT_DMODE0_BLOCK
|
125 NPORT_DMODE0_DOSETUP
| NPORT_DMODE0_STOPX
|
127 npregs
->set
.colori
= ci
;
128 npregs
->set
.xystarti
= (xstart
<< 16) | ystart
;
129 npregs
->go
.xyendi
= (xend
<< 16) | yend
;
132 static inline void newport_clear_lines(int ystart
, int yend
, int ci
)
134 ystart
= ((ystart
<< 4) + topscan
) & 0x3ff;
135 yend
= ((yend
<< 4) + topscan
+ 15) & 0x3ff;
136 newport_clear_screen (0, ystart
, 1280+63, yend
, ci
);
139 void newport_reset (void)
145 treg
= newport_vc2_get(npregs
, VC2_IREG_CONTROL
);
146 newport_vc2_set(npregs
, VC2_IREG_CONTROL
, (treg
| VC2_CTRL_EVIDEO
));
148 treg
= newport_vc2_get(npregs
, VC2_IREG_CENTRY
);
149 newport_vc2_set(npregs
, VC2_IREG_RADDR
, treg
);
150 npregs
->set
.dcbmode
= (NPORT_DMODE_AVC2
| VC2_REGADDR_RAM
|
151 NPORT_DMODE_W2
| VC2_PROTOCOL
);
152 for(i
= 0; i
< 128; i
++) {
154 if (i
== 92 || i
== 94)
155 npregs
->set
.dcbdata0
.byshort
.s1
= 0xff00;
157 npregs
->set
.dcbdata0
.byshort
.s1
= 0x0000;
162 /* turn off popup plane */
163 npregs
->set
.dcbmode
= (DCB_XMAP0
| R_DCB_XMAP9_PROTOCOL
|
164 XM9_CRS_CONFIG
| NPORT_DMODE_W1
);
165 npregs
->set
.dcbdata0
.bybytes
.b3
&= ~XM9_PUPMODE
;
166 npregs
->set
.dcbmode
= (DCB_XMAP1
| R_DCB_XMAP9_PROTOCOL
|
167 XM9_CRS_CONFIG
| NPORT_DMODE_W1
);
168 npregs
->set
.dcbdata0
.bybytes
.b3
&= ~XM9_PUPMODE
;
171 npregs
->cset
.topscan
= 0x3ff;
172 npregs
->cset
.xywin
= (4096 << 16) | 4096;
174 /* Clear the screen. */
175 newport_clear_screen(0,0,1280+63,1024,0);
179 * calculate the actual screen size by reading
180 * the video timing out of the VC2
182 void newport_get_screensize(void)
185 unsigned short ventry
,treg
;
186 unsigned short linetable
[128]; /* should be enough */
188 ventry
= newport_vc2_get (npregs
, VC2_IREG_VENTRY
);
189 newport_vc2_set(npregs
, VC2_IREG_RADDR
, ventry
);
190 npregs
->set
.dcbmode
= (NPORT_DMODE_AVC2
| VC2_REGADDR_RAM
|
191 NPORT_DMODE_W2
| VC2_PROTOCOL
);
192 for(i
= 0; i
< 128; i
++) {
194 linetable
[i
] = npregs
->set
.dcbdata0
.byshort
.s1
;
197 newport_xsize
= newport_ysize
= 0;
198 for (i
= 0; linetable
[i
+1] && (i
< sizeof(linetable
)); i
+=2) {
200 newport_vc2_set(npregs
, VC2_IREG_RADDR
, linetable
[i
]);
201 npregs
->set
.dcbmode
= (NPORT_DMODE_AVC2
| VC2_REGADDR_RAM
|
202 NPORT_DMODE_W2
| VC2_PROTOCOL
);
205 treg
= npregs
->set
.dcbdata0
.byshort
.s1
;
207 cols
+= (treg
>> 7) & 0xfe;
208 if ((treg
& 0x80) == 0) {
210 treg
= npregs
->set
.dcbdata0
.byshort
.s1
;
212 } while ((treg
& 0x8000) == 0);
214 if (cols
> newport_xsize
)
215 newport_xsize
= cols
;
216 newport_ysize
+= linetable
[i
+1];
219 printk ("NG1: Screensize %dx%d\n",newport_xsize
,newport_ysize
);
222 static void newport_get_revisions(void)
225 unsigned int board_rev
;
226 unsigned int rex3_rev
;
227 unsigned int vc2_rev
;
228 unsigned int cmap_rev
;
229 unsigned int xmap9_rev
;
230 unsigned int bt445_rev
;
231 unsigned int bitplanes
;
233 rex3_rev
= npregs
->cset
.status
& NPORT_STAT_VERS
;
235 npregs
->set
.dcbmode
= (DCB_CMAP0
| NCMAP_PROTOCOL
|
236 NCMAP_REGADDR_RREG
| NPORT_DMODE_W1
);
237 tmp
= npregs
->set
.dcbdata0
.bybytes
.b3
;
239 board_rev
= (tmp
>> 4) & 7;
240 bitplanes
= ((board_rev
> 1) && (tmp
& 0x80)) ? 8 : 24;
242 npregs
->set
.dcbmode
= (DCB_CMAP1
| NCMAP_PROTOCOL
|
243 NCMAP_REGADDR_RREG
| NPORT_DMODE_W1
);
244 tmp
= npregs
->set
.dcbdata0
.bybytes
.b3
;
245 if ((tmp
& 7) < cmap_rev
)
246 cmap_rev
= (tmp
& 7);
248 vc2_rev
= (newport_vc2_get(npregs
, VC2_IREG_CONFIG
) >> 5) & 7;
250 npregs
->set
.dcbmode
= (DCB_XMAP0
| R_DCB_XMAP9_PROTOCOL
|
251 XM9_CRS_REVISION
| NPORT_DMODE_W1
);
252 xmap9_rev
= npregs
->set
.dcbdata0
.bybytes
.b3
& 7;
254 npregs
->set
.dcbmode
= (DCB_BT445
| BT445_PROTOCOL
|
255 BT445_CSR_ADDR_REG
| NPORT_DMODE_W1
);
256 npregs
->set
.dcbdata0
.bybytes
.b3
= BT445_REVISION_REG
;
257 npregs
->set
.dcbmode
= (DCB_BT445
| BT445_PROTOCOL
|
258 BT445_CSR_REVISION
| NPORT_DMODE_W1
);
259 bt445_rev
= (npregs
->set
.dcbdata0
.bybytes
.b3
>> 4) - 0x0a;
261 #define L(a) (char)('A'+(a))
262 printk ("NG1: Revision %d, %d bitplanes, REX3 revision %c, VC2 revision %c, xmap9 revision %c, cmap revision %c, bt445 revision %c\n",
263 board_rev
,bitplanes
,L(rex3_rev
),L(vc2_rev
), L(xmap9_rev
),
264 L(cmap_rev
? (cmap_rev
+1):0),L(bt445_rev
));
267 if (board_rev
== 3) /* I don't know all affected revisions */
268 xcurs_correction
= 21;
272 static const char *newport_startup(void)
274 static const char * __init
newport_startup(void)
277 struct newport_regs
*p
;
279 npregs
= (struct newport_regs
*) (KSEG1
+ 0x1f0f0000);
282 p
->cset
.config
= NPORT_CFG_GD0
;
288 p
->set
.xstarti
= TESTVAL
; if(p
->set
._xstart
.word
!= XSTI_TO_FXSTART(TESTVAL
)) {
293 newport_get_revisions();
294 newport_get_screensize();
296 // gfx_init (display_desc);
298 return "SGI Newport";
301 static void newport_init(struct vc_data
*vc
, int init
)
303 vc
->vc_cols
= newport_xsize
/ 8;
304 vc
->vc_rows
= newport_ysize
/ 16;
305 vc
->vc_can_do_color
= 1;
308 static void newport_clear(struct vc_data
*vc
, int sy
, int sx
, int height
, int width
)
310 int xend
= ((sx
+ width
) << 3) - 1;
311 int ystart
= ((sy
<< 4) + topscan
) & 0x3ff;
312 int yend
= (((sy
+ height
) << 4) + topscan
- 1) & 0x3ff;
318 newport_clear_screen(sx
<< 3, ystart
, xend
, yend
,
319 (vc
->vc_color
& 0xf0) >> 4);
321 newport_clear_screen(sx
<< 3, ystart
, xend
, 1023,
322 (vc
->vc_color
& 0xf0) >> 4);
323 newport_clear_screen(sx
<< 3, 0, xend
, yend
,
324 (vc
->vc_color
& 0xf0) >> 4);
328 static void newport_putc(struct vc_data
*vc
, int charattr
, int ypos
, int xpos
)
332 p
= &FONT_DATA
[(charattr
& 0xff) << 4];
333 charattr
= (charattr
>> 8) & 0xff;
337 newport_render_background(xpos
, ypos
, xpos
, ypos
, (charattr
& 0xf0) >> 4);
339 /* Set the color and drawing mode. */
341 npregs
->set
.colori
= charattr
& 0xf;
342 npregs
->set
.drawmode0
= (NPORT_DMODE0_DRAW
| NPORT_DMODE0_BLOCK
|
343 NPORT_DMODE0_STOPX
| NPORT_DMODE0_ZPENAB
|
346 /* Set coordinates for bitmap operation. */
347 npregs
->set
.xystarti
= (xpos
<< 16) | ((ypos
+ topscan
) & 0x3ff);
348 npregs
->set
.xyendi
= ((xpos
+ 7) << 16);
351 /* Go, baby, go... */
355 static void newport_putcs(struct vc_data
*vc
, const unsigned short *s
,
356 int count
, int ypos
, int xpos
)
362 charattr
= (*s
>> 8) & 0xff;
368 /* Clear the area behing the string */
369 newport_render_background(xpos
, ypos
, xpos
+ ((count
-1) << 3), ypos
,
370 (charattr
& 0xf0) >> 4);
374 /* Set the color and drawing mode. */
375 npregs
->set
.colori
= charattr
& 0xf;
376 npregs
->set
.drawmode0
= (NPORT_DMODE0_DRAW
| NPORT_DMODE0_BLOCK
|
377 NPORT_DMODE0_STOPX
| NPORT_DMODE0_ZPENAB
|
380 for (i
= 0; i
< count
; i
++, xpos
+= 8) {
381 p
= &FONT_DATA
[(s
[i
] & 0xff) << 4];
385 /* Set coordinates for bitmap operation. */
386 npregs
->set
.xystarti
= (xpos
<< 16) | ((ypos
+ topscan
) & 0x3ff);
387 npregs
->set
.xyendi
= ((xpos
+ 7) << 16);
389 /* Go, baby, go... */
394 static void newport_cursor(struct vc_data
*vc
, int mode
)
401 treg
= newport_vc2_get(npregs
, VC2_IREG_CONTROL
);
402 newport_vc2_set(npregs
, VC2_IREG_CONTROL
, (treg
& ~(VC2_CTRL_ECDISP
)));
407 treg
= newport_vc2_get(npregs
, VC2_IREG_CONTROL
);
408 newport_vc2_set(npregs
, VC2_IREG_CONTROL
, (treg
| VC2_CTRL_ECDISP
));
409 xcurs
= (vc
->vc_pos
- vc
->vc_visible_origin
) / 2;
410 ycurs
= ((xcurs
/ vc
->vc_cols
) << 4) + 31;
411 xcurs
= ((xcurs
% vc
->vc_cols
) << 3) + xcurs_correction
;
412 newport_vc2_set(npregs
, VC2_IREG_CURSX
, xcurs
);
413 newport_vc2_set(npregs
, VC2_IREG_CURSY
, ycurs
);
417 static int newport_switch(struct vc_data
*vc
)
419 static int logo_drawn
= 0;
422 npregs
->cset
.topscan
= 0x3ff;
433 static int newport_blank(struct vc_data
*c
, int blank
)
438 /* unblank console */
439 treg
= newport_vc2_get(npregs
, VC2_IREG_CONTROL
);
440 newport_vc2_set(npregs
, VC2_IREG_CONTROL
, (treg
| VC2_CTRL_EDISP
));
443 treg
= newport_vc2_get(npregs
, VC2_IREG_CONTROL
);
444 newport_vc2_set(npregs
, VC2_IREG_CONTROL
, (treg
& ~(VC2_CTRL_EDISP
)));
449 static int newport_font_op(struct vc_data
*vc
, struct console_font_op
*f
)
454 static int newport_set_palette(struct vc_data
*vc
, unsigned char *table
)
459 static int newport_scrolldelta(struct vc_data
*vc
, int lines
)
461 /* there is (nearly) no off-screen memory, so we can't scroll back */
465 static int newport_scroll(struct vc_data
*vc
, int t
, int b
, int dir
, int lines
)
468 unsigned short *s
, *d
;
469 unsigned short chattr
;
471 logo_active
= 0; /* it's time to disable the logo now.. */
473 if (t
== 0 && b
== vc
->vc_rows
) {
475 topscan
= (topscan
+ (lines
<< 4)) & 0x3ff;
476 newport_clear_lines (vc
->vc_rows
-lines
,vc
->vc_rows
-1,
477 (vc
->vc_color
& 0xf0) >> 4);
479 topscan
= (topscan
+ (-lines
<< 4)) & 0x3ff;
480 newport_clear_lines (0,lines
-1, (vc
->vc_color
& 0xf0) >> 4);
482 npregs
->cset
.topscan
= (topscan
- 1) & 0x3ff;
486 count
= (b
-t
-lines
) * vc
->vc_cols
;
489 s
= (unsigned short *)(vc
->vc_origin
+ vc
->vc_size_row
*(t
+lines
));
490 d
= (unsigned short *)(vc
->vc_origin
+ vc
->vc_size_row
*t
);
492 chattr
= scr_readw (s
++);
493 if (chattr
!= scr_readw(d
)) {
494 newport_putc (vc
, chattr
, y
, x
);
495 scr_writew (chattr
, d
);
498 if (++x
== vc
->vc_cols
) {
502 d
= (unsigned short *)(vc
->vc_origin
+ vc
->vc_size_row
*(b
-lines
));
504 for (count
= 0; count
< (lines
* vc
->vc_cols
); count
++) {
505 if (scr_readw(d
) != vc
->vc_video_erase_char
) {
506 newport_putc (vc
, vc
->vc_video_erase_char
, y
, x
);
507 scr_writew (vc
->vc_video_erase_char
, d
);
510 if (++x
== vc
->vc_cols
) {
515 x
= vc
->vc_cols
-1; y
= b
-1;
516 s
= (unsigned short *)(vc
->vc_origin
+ vc
->vc_size_row
*(b
-lines
)-2);
517 d
= (unsigned short *)(vc
->vc_origin
+ vc
->vc_size_row
*b
-2);
519 chattr
= scr_readw (s
--);
520 if (chattr
!= scr_readw(d
)) {
521 newport_putc (vc
, chattr
, y
, x
);
522 scr_writew (chattr
, d
);
526 x
= vc
->vc_cols
-1; y
--;
529 d
= (unsigned short *)(vc
->vc_origin
+ vc
->vc_size_row
*t
);
531 for (count
= 0; count
< (lines
* vc
->vc_cols
); count
++) {
532 if (scr_readw(d
) != vc
->vc_video_erase_char
) {
533 newport_putc (vc
, vc
->vc_video_erase_char
, y
, x
);
534 scr_writew (vc
->vc_video_erase_char
, d
);
537 if (++x
== vc
->vc_cols
) {
545 static void newport_bmove(struct vc_data
*vc
, int sy
, int sx
, int dy
, int dx
, int h
, int w
)
547 short xs
, ys
, xe
, ye
, xoffs
, yoffs
, tmp
;
549 xs
= sx
<< 3; xe
= ((sx
+w
) << 3)-1;
551 * as bmove is only used to move stuff around in the same line
552 * (h == 1), we don't care about wrap arounds caused by topscan != 0
554 ys
= ((sy
<< 4) + topscan
) & 0x3ff; ye
= (((sy
+h
) << 4)-1+topscan
) & 0x3ff;
555 xoffs
= (dx
- sx
) << 3;
556 yoffs
= (dy
- sy
) << 4;
558 /* move to the right, exchange starting points */
559 tmp
= xe
; xe
= xs
; xs
= tmp
;
562 npregs
->set
.drawmode0
= (NPORT_DMODE0_S2S
| NPORT_DMODE0_BLOCK
|
563 NPORT_DMODE0_DOSETUP
| NPORT_DMODE0_STOPX
|
565 npregs
->set
.xystarti
= (xs
<< 16) | ys
;
566 npregs
->set
.xyendi
= (xe
<< 16) | ye
;
567 npregs
->go
.xymove
= (xoffs
<< 16) | yoffs
;
570 static int newport_dummy(struct vc_data
*c
)
575 #define DUMMY (void *) newport_dummy
577 const struct consw newport_con
= {
578 con_startup
: newport_startup
,
579 con_init
: newport_init
,
581 con_clear
: newport_clear
,
582 con_putc
: newport_putc
,
583 con_putcs
: newport_putcs
,
584 con_cursor
: newport_cursor
,
585 con_scroll
: newport_scroll
,
586 con_bmove
: newport_bmove
,
587 con_switch
: newport_switch
,
588 con_blank
: newport_blank
,
589 con_font_op
: newport_font_op
,
590 con_set_palette
: newport_set_palette
,
591 con_scrolldelta
: newport_scrolldelta
,
592 con_set_origin
: DUMMY
,
593 con_save_screen
: DUMMY
,
598 int init_module(void) {
599 if (!newport_startup())
600 printk("Error loading SGI Newport Console driver\n");
602 printk("Loading SGI Newport Console Driver\n");
604 take_over_console(&newport_con
,0,MAX_NR_CONSOLES
-1,1);
609 int cleanup_module(void) {
610 printk("Unloading SGI Newport Console Driver\n");