newport.c revision 1.11 1 /* $NetBSD: newport.c,v 1.11 2009/02/10 03:40:26 macallan Exp $ */
2
3 /*
4 * Copyright (c) 2003 Ilpo Ruotsalainen
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 * <<Id: LICENSE_GC,v 1.1 2001/10/01 23:24:05 cgd Exp>>
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: newport.c,v 1.11 2009/02/10 03:40:26 macallan Exp $");
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/device.h>
38 #include <sys/malloc.h>
39
40 #include <machine/sysconf.h>
41
42 #include <dev/wscons/wsconsio.h>
43 #include <dev/wscons/wsdisplayvar.h>
44 #include <dev/wsfont/wsfont.h>
45
46 #include <sgimips/gio/giovar.h>
47 #include <sgimips/gio/newportvar.h>
48 #include <sgimips/gio/newportreg.h>
49
50 struct newport_softc {
51 struct device sc_dev;
52
53 struct newport_devconfig *sc_dc;
54 };
55
56 struct newport_devconfig {
57 uint32_t dc_addr;
58
59 bus_space_tag_t dc_st;
60 bus_space_handle_t dc_sh;
61
62 int dc_boardrev;
63 int dc_vc2rev;
64 int dc_cmaprev;
65 int dc_xmaprev;
66 int dc_rexrev;
67 int dc_xres;
68 int dc_yres;
69 int dc_depth;
70
71 int dc_font;
72 struct wsdisplay_font *dc_fontdata;
73 };
74
75 static int newport_match(struct device *, struct cfdata *, void *);
76 static void newport_attach(struct device *, struct device *, void *);
77
78 CFATTACH_DECL(newport, sizeof(struct newport_softc),
79 newport_match, newport_attach, NULL, NULL);
80
81 /* textops */
82 static void newport_cursor(void *, int, int, int);
83 static int newport_mapchar(void *, int, unsigned int *);
84 static void newport_putchar(void *, int, int, u_int, long);
85 static void newport_copycols(void *, int, int, int, int);
86 static void newport_erasecols(void *, int, int, int, long);
87 static void newport_copyrows(void *, int, int, int);
88 static void newport_eraserows(void *, int, int, long);
89 static int newport_allocattr(void *, int, int, int, long *);
90
91 /* accessops */
92 static int newport_ioctl(void *, void *, u_long, void *, int,
93 struct lwp *);
94 static paddr_t newport_mmap(void *, void *, off_t, int);
95 static int newport_alloc_screen(void *, const struct wsscreen_descr *,
96 void **, int *, int *, long *);
97 static void newport_free_screen(void *, void *);
98 static int newport_show_screen(void *, void *, int,
99 void (*)(void *, int, int), void *);
100
101 static const struct wsdisplay_emulops newport_textops = {
102 .cursor = newport_cursor,
103 .mapchar = newport_mapchar,
104 .putchar = newport_putchar,
105 .copycols = newport_copycols,
106 .erasecols = newport_erasecols,
107 .copyrows = newport_copyrows,
108 .eraserows = newport_eraserows,
109 .allocattr = newport_allocattr
110 };
111
112 static const struct wsdisplay_accessops newport_accessops = {
113 .ioctl = newport_ioctl,
114 .mmap = newport_mmap,
115 .alloc_screen = newport_alloc_screen,
116 .free_screen = newport_free_screen,
117 .show_screen = newport_show_screen,
118 };
119
120 static const struct wsscreen_descr newport_screen_1024x768 = {
121 .name = "1024x768",
122 .ncols = 128,
123 .nrows = 48,
124 .textops = &newport_textops,
125 .fontwidth = 8,
126 .fontheight = 16,
127 .capabilities = WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_REVERSE
128 };
129
130 static const struct wsscreen_descr newport_screen_1280x1024 = {
131 .name = "1280x1024",
132 .ncols = 160,
133 .nrows = 64,
134 .textops = &newport_textops,
135 .fontwidth = 8,
136 .fontheight = 16,
137 .capabilities = WSSCREEN_WSCOLORS | WSSCREEN_HILIT | WSSCREEN_REVERSE
138 };
139
140 static const struct wsscreen_descr *_newport_screenlist[] = {
141 &newport_screen_1024x768,
142 &newport_screen_1280x1024
143 };
144
145 static const struct wsscreen_list newport_screenlist = {
146 sizeof(_newport_screenlist) / sizeof(struct wsscreen_descr *),
147 _newport_screenlist
148 };
149
150 static struct newport_devconfig newport_console_dc;
151 static int newport_is_console = 0;
152
153 #define NEWPORT_ATTR_ENCODE(fg,bg) (((fg) << 8) | (bg))
154 #define NEWPORT_ATTR_BG(a) ((a) & 0xff)
155 #define NEWPORT_ATTR_FG(a) (((a) >> 8) & 0xff)
156
157 static const uint16_t newport_cursor_data[128] = {
158 /* Bit 0 */
159 0xff00, 0x0000,
160 0xff00, 0x0000,
161 0xff00, 0x0000,
162 0xff00, 0x0000,
163 0xff00, 0x0000,
164 0xff00, 0x0000,
165 0xff00, 0x0000,
166 0xff00, 0x0000,
167 0xff00, 0x0000,
168 0xff00, 0x0000,
169 0xff00, 0x0000,
170 0xff00, 0x0000,
171 0xff00, 0x0000,
172 0xff00, 0x0000,
173 0xff00, 0x0000,
174 0xff00, 0x0000,
175 0x0000, 0x0000,
176 0x0000, 0x0000,
177 0x0000, 0x0000,
178 0x0000, 0x0000,
179 0x0000, 0x0000,
180 0x0000, 0x0000,
181 0x0000, 0x0000,
182 0x0000, 0x0000,
183 0x0000, 0x0000,
184 0x0000, 0x0000,
185 0x0000, 0x0000,
186 0x0000, 0x0000,
187 0x0000, 0x0000,
188 0x0000, 0x0000,
189 0x0000, 0x0000,
190 0x0000, 0x0000,
191
192 /* Bit 1 */
193 0x0000, 0x0000,
194 0x0000, 0x0000,
195 0x0000, 0x0000,
196 0x0000, 0x0000,
197 0x0000, 0x0000,
198 0x0000, 0x0000,
199 0x0000, 0x0000,
200 0x0000, 0x0000,
201 0x0000, 0x0000,
202 0x0000, 0x0000,
203 0x0000, 0x0000,
204 0x0000, 0x0000,
205 0x0000, 0x0000,
206 0x0000, 0x0000,
207 0x0000, 0x0000,
208 0x0000, 0x0000,
209 0x0000, 0x0000,
210 0x0000, 0x0000,
211 0x0000, 0x0000,
212 0x0000, 0x0000,
213 0x0000, 0x0000,
214 0x0000, 0x0000,
215 0x0000, 0x0000,
216 0x0000, 0x0000,
217 0x0000, 0x0000,
218 0x0000, 0x0000,
219 0x0000, 0x0000,
220 0x0000, 0x0000,
221 0x0000, 0x0000,
222 0x0000, 0x0000,
223 0x0000, 0x0000,
224 0x0000, 0x0000,
225 };
226
227 static const uint8_t newport_defcmap[16*3] = {
228 /* Normal colors */
229 0x00, 0x00, 0x00, /* black */
230 0x7f, 0x00, 0x00, /* red */
231 0x00, 0x7f, 0x00, /* green */
232 0x7f, 0x7f, 0x00, /* brown */
233 0x00, 0x00, 0x7f, /* blue */
234 0x7f, 0x00, 0x7f, /* magenta */
235 0x00, 0x7f, 0x7f, /* cyan */
236 0xc7, 0xc7, 0xc7, /* white - XXX too dim? */
237
238 /* Hilite colors */
239 0x7f, 0x7f, 0x7f, /* black */
240 0xff, 0x00, 0x00, /* red */
241 0x00, 0xff, 0x00, /* green */
242 0xff, 0xff, 0x00, /* brown */
243 0x00, 0x00, 0xff, /* blue */
244 0xff, 0x00, 0xff, /* magenta */
245 0x00, 0xff, 0xff, /* cyan */
246 0xff, 0xff, 0xff, /* white */
247 };
248
249 /**** Low-level hardware register groveling functions ****/
250 static void
251 rex3_write(struct newport_devconfig *dc, bus_size_t rexreg, uint32_t val)
252 {
253 bus_space_write_4(dc->dc_st, dc->dc_sh, NEWPORT_REX3_OFFSET + rexreg,
254 val);
255 }
256
257 static void
258 rex3_write_go(struct newport_devconfig *dc, bus_size_t rexreg, uint32_t val)
259 {
260 rex3_write(dc, rexreg + REX3_REG_GO, val);
261 }
262
263 static uint32_t
264 rex3_read(struct newport_devconfig *dc, bus_size_t rexreg)
265 {
266 return bus_space_read_4(dc->dc_st, dc->dc_sh, NEWPORT_REX3_OFFSET +
267 rexreg);
268 }
269
270 static void
271 rex3_wait_gfifo(struct newport_devconfig *dc)
272 {
273 while (rex3_read(dc, REX3_REG_STATUS) & REX3_STATUS_GFXBUSY)
274 ;
275 }
276
277 static void
278 vc2_write_ireg(struct newport_devconfig *dc, uint8_t ireg, uint16_t val)
279 {
280 rex3_write(dc, REX3_REG_DCBMODE,
281 REX3_DCBMODE_DW_3 |
282 REX3_DCBMODE_ENCRSINC |
283 (NEWPORT_DCBADDR_VC2 << REX3_DCBMODE_DCBADDR_SHIFT) |
284 (VC2_DCBCRS_INDEX << REX3_DCBMODE_DCBCRS_SHIFT) |
285 REX3_DCBMODE_ENASYNCACK |
286 (1 << REX3_DCBMODE_CSSETUP_SHIFT));
287
288 rex3_write(dc, REX3_REG_DCBDATA0, (ireg << 24) | (val << 8));
289 }
290
291 static uint16_t
292 vc2_read_ireg(struct newport_devconfig *dc, uint8_t ireg)
293 {
294 rex3_write(dc, REX3_REG_DCBMODE,
295 REX3_DCBMODE_DW_1 |
296 REX3_DCBMODE_ENCRSINC |
297 (NEWPORT_DCBADDR_VC2 << REX3_DCBMODE_DCBADDR_SHIFT) |
298 (VC2_DCBCRS_INDEX << REX3_DCBMODE_DCBCRS_SHIFT) |
299 REX3_DCBMODE_ENASYNCACK |
300 (1 << REX3_DCBMODE_CSSETUP_SHIFT));
301
302 rex3_write(dc, REX3_REG_DCBDATA0, ireg << 24);
303
304 rex3_write(dc, REX3_REG_DCBMODE,
305 REX3_DCBMODE_DW_2 |
306 REX3_DCBMODE_ENCRSINC |
307 (NEWPORT_DCBADDR_VC2 << REX3_DCBMODE_DCBADDR_SHIFT) |
308 (VC2_DCBCRS_IREG << REX3_DCBMODE_DCBCRS_SHIFT) |
309 REX3_DCBMODE_ENASYNCACK |
310 (1 << REX3_DCBMODE_CSSETUP_SHIFT));
311
312 return (uint16_t)(rex3_read(dc, REX3_REG_DCBDATA0) >> 16);
313 }
314
315 static uint16_t
316 vc2_read_ram(struct newport_devconfig *dc, uint16_t addr)
317 {
318 vc2_write_ireg(dc, VC2_IREG_RAM_ADDRESS, addr);
319
320 rex3_write(dc, REX3_REG_DCBMODE,
321 REX3_DCBMODE_DW_2 |
322 (NEWPORT_DCBADDR_VC2 << REX3_DCBMODE_DCBADDR_SHIFT) |
323 (VC2_DCBCRS_RAM << REX3_DCBMODE_DCBCRS_SHIFT) |
324 REX3_DCBMODE_ENASYNCACK |
325 (1 << REX3_DCBMODE_CSSETUP_SHIFT));
326
327 return (uint16_t)(rex3_read(dc, REX3_REG_DCBDATA0) >> 16);
328 }
329
330 static void
331 vc2_write_ram(struct newport_devconfig *dc, uint16_t addr, uint16_t val)
332 {
333 vc2_write_ireg(dc, VC2_IREG_RAM_ADDRESS, addr);
334
335 rex3_write(dc, REX3_REG_DCBMODE,
336 REX3_DCBMODE_DW_2 |
337 (NEWPORT_DCBADDR_VC2 << REX3_DCBMODE_DCBADDR_SHIFT) |
338 (VC2_DCBCRS_RAM << REX3_DCBMODE_DCBCRS_SHIFT) |
339 REX3_DCBMODE_ENASYNCACK |
340 (1 << REX3_DCBMODE_CSSETUP_SHIFT));
341
342 rex3_write(dc, REX3_REG_DCBDATA0, val << 16);
343 }
344
345 static u_int32_t
346 xmap9_read(struct newport_devconfig *dc, int crs)
347 {
348 rex3_write(dc, REX3_REG_DCBMODE,
349 REX3_DCBMODE_DW_1 |
350 (NEWPORT_DCBADDR_XMAP_0 << REX3_DCBMODE_DCBADDR_SHIFT) |
351 (crs << REX3_DCBMODE_DCBCRS_SHIFT) |
352 (3 << REX3_DCBMODE_CSWIDTH_SHIFT) |
353 (2 << REX3_DCBMODE_CSHOLD_SHIFT) |
354 (1 << REX3_DCBMODE_CSSETUP_SHIFT));
355 return rex3_read(dc, REX3_REG_DCBDATA0);
356 }
357
358 static void
359 xmap9_write(struct newport_devconfig *dc, int crs, uint8_t val)
360 {
361 rex3_write(dc, REX3_REG_DCBMODE,
362 REX3_DCBMODE_DW_1 |
363 (NEWPORT_DCBADDR_XMAP_BOTH << REX3_DCBMODE_DCBADDR_SHIFT) |
364 (crs << REX3_DCBMODE_DCBCRS_SHIFT) |
365 (3 << REX3_DCBMODE_CSWIDTH_SHIFT) |
366 (2 << REX3_DCBMODE_CSHOLD_SHIFT) |
367 (1 << REX3_DCBMODE_CSSETUP_SHIFT));
368
369 rex3_write(dc, REX3_REG_DCBDATA0, val << 24);
370 }
371
372 static void
373 xmap9_write_mode(struct newport_devconfig *dc, uint8_t index, uint32_t mode)
374 {
375 rex3_write(dc, REX3_REG_DCBMODE,
376 REX3_DCBMODE_DW_4 |
377 (NEWPORT_DCBADDR_XMAP_BOTH << REX3_DCBMODE_DCBADDR_SHIFT) |
378 (XMAP9_DCBCRS_MODE_SETUP << REX3_DCBMODE_DCBCRS_SHIFT) |
379 (3 << REX3_DCBMODE_CSWIDTH_SHIFT) |
380 (2 << REX3_DCBMODE_CSHOLD_SHIFT) |
381 (1 << REX3_DCBMODE_CSSETUP_SHIFT));
382
383 rex3_write(dc, REX3_REG_DCBDATA0, (index << 24) | mode);
384 }
385
386 /**** Helper functions ****/
387 static void
388 newport_fill_rectangle(struct newport_devconfig *dc, int x1, int y1, int x2,
389 int y2, uint8_t color)
390 {
391 rex3_wait_gfifo(dc);
392
393 rex3_write(dc, REX3_REG_DRAWMODE0, REX3_DRAWMODE0_OPCODE_DRAW |
394 REX3_DRAWMODE0_ADRMODE_BLOCK | REX3_DRAWMODE0_DOSETUP |
395 REX3_DRAWMODE0_STOPONX | REX3_DRAWMODE0_STOPONY);
396 rex3_write(dc, REX3_REG_WRMASK, 0xffffffff);
397 rex3_write(dc, REX3_REG_COLORI, color);
398 rex3_write(dc, REX3_REG_XYSTARTI, (x1 << REX3_XYSTARTI_XSHIFT) | y1);
399
400 rex3_write_go(dc, REX3_REG_XYENDI, (x2 << REX3_XYENDI_XSHIFT) | y2);
401 }
402
403 static void
404 newport_copy_rectangle(struct newport_devconfig *dc, int x1, int y1, int x2,
405 int y2, int dx, int dy)
406 {
407 uint32_t tmp;
408
409 rex3_wait_gfifo(dc);
410 if (dy > y1) {
411 /* need to copy bottom up */
412 dy += (y2 - y1);
413 tmp = y2;
414 y2 = y1;
415 y1 = tmp;
416 }
417
418 if (dx > x1) {
419 /* need to copy right to left */
420 dx += (x2 - x1);
421 tmp = x2;
422 x2 = x1;
423 x1 = tmp;
424 }
425
426 rex3_write(dc, REX3_REG_DRAWMODE0, REX3_DRAWMODE0_OPCODE_SCR2SCR |
427 REX3_DRAWMODE0_ADRMODE_BLOCK | REX3_DRAWMODE0_DOSETUP |
428 REX3_DRAWMODE0_STOPONX | REX3_DRAWMODE0_STOPONY);
429 rex3_write(dc, REX3_REG_XYSTARTI, (x1 << REX3_XYSTARTI_XSHIFT) | y1);
430 rex3_write(dc, REX3_REG_XYENDI, (x2 << REX3_XYENDI_XSHIFT) | y2);
431
432 tmp = (dy - y1) & 0xffff;
433 tmp |= (dx - x1) << REX3_XYMOVE_XSHIFT;
434
435 rex3_write_go(dc, REX3_REG_XYMOVE, tmp);
436 }
437
438 static void
439 newport_cmap_setrgb(struct newport_devconfig *dc, int index, uint8_t r,
440 uint8_t g, uint8_t b)
441 {
442 rex3_write(dc, REX3_REG_DCBMODE,
443 REX3_DCBMODE_DW_2 |
444 REX3_DCBMODE_ENCRSINC |
445 (NEWPORT_DCBADDR_CMAP_BOTH << REX3_DCBMODE_DCBADDR_SHIFT) |
446 (CMAP_DCBCRS_ADDRESS_LOW << REX3_DCBMODE_DCBCRS_SHIFT) |
447 (1 << REX3_DCBMODE_CSWIDTH_SHIFT) |
448 (1 << REX3_DCBMODE_CSHOLD_SHIFT) |
449 (1 << REX3_DCBMODE_CSSETUP_SHIFT) |
450 REX3_DCBMODE_SWAPENDIAN);
451
452 rex3_write(dc, REX3_REG_DCBDATA0, index << 16);
453
454 rex3_write(dc, REX3_REG_DCBMODE,
455 REX3_DCBMODE_DW_3 |
456 (NEWPORT_DCBADDR_CMAP_BOTH << REX3_DCBMODE_DCBADDR_SHIFT) |
457 (CMAP_DCBCRS_PALETTE << REX3_DCBMODE_DCBCRS_SHIFT) |
458 (1 << REX3_DCBMODE_CSWIDTH_SHIFT) |
459 (1 << REX3_DCBMODE_CSHOLD_SHIFT) |
460 (1 << REX3_DCBMODE_CSSETUP_SHIFT));
461
462 rex3_write(dc, REX3_REG_DCBDATA0, (r << 24) + (g << 16) + (b << 8));
463 }
464
465 static void
466 newport_get_resolution(struct newport_devconfig *dc)
467 {
468 uint16_t vep,lines;
469 uint16_t linep,cols;
470 uint16_t data;
471
472 vep = vc2_read_ireg(dc, VC2_IREG_VIDEO_ENTRY);
473
474 dc->dc_xres = 0;
475 dc->dc_yres = 0;
476
477 for (;;) {
478 /* Iterate over runs in video timing table */
479
480 cols = 0;
481
482 linep = vc2_read_ram(dc, vep++);
483 lines = vc2_read_ram(dc, vep++);
484
485 if (lines == 0)
486 break;
487
488 do {
489 /* Iterate over state runs in line sequence table */
490
491 data = vc2_read_ram(dc, linep++);
492
493 if ((data & 0x0001) == 0)
494 cols += (data >> 7) & 0xfe;
495
496 if ((data & 0x0080) == 0)
497 data = vc2_read_ram(dc, linep++);
498 } while ((data & 0x8000) == 0);
499
500 if (cols != 0) {
501 if (cols > dc->dc_xres)
502 dc->dc_xres = cols;
503
504 dc->dc_yres += lines;
505 }
506 }
507 }
508
509 static void
510 newport_setup_hw(struct newport_devconfig *dc)
511 {
512 uint16_t curp,tmp;
513 int i;
514 uint32_t scratch;
515
516 /* Get various revisions */
517 rex3_write(dc, REX3_REG_DCBMODE,
518 REX3_DCBMODE_DW_1 |
519 (NEWPORT_DCBADDR_CMAP_0 << REX3_DCBMODE_DCBADDR_SHIFT) |
520 (CMAP_DCBCRS_REVISION << REX3_DCBMODE_DCBCRS_SHIFT) |
521 (1 << REX3_DCBMODE_CSWIDTH_SHIFT) |
522 (1 << REX3_DCBMODE_CSHOLD_SHIFT) |
523 (1 << REX3_DCBMODE_CSSETUP_SHIFT));
524
525 scratch = vc2_read_ireg(dc, VC2_IREG_CONFIG);
526 dc->dc_vc2rev = (scratch & VC2_IREG_CONFIG_REVISION) >> 5;
527
528 scratch = rex3_read(dc, REX3_REG_DCBDATA0);
529
530 dc->dc_boardrev = (scratch >> 28) & 0x07;
531 dc->dc_cmaprev = scratch & 0x07;
532 dc->dc_xmaprev = xmap9_read(dc, XMAP9_DCBCRS_REVISION) & 0x07;
533 dc->dc_depth = ( (dc->dc_boardrev > 1) && (scratch & 0x80)) ? 8 : 24;
534
535 /* Setup cursor glyph */
536 curp = vc2_read_ireg(dc, VC2_IREG_CURSOR_ENTRY);
537
538 for (i=0; i<128; i++)
539 vc2_write_ram(dc, curp + i, newport_cursor_data[i]);
540
541 /* Setup VC2 to a known state */
542 tmp = vc2_read_ireg(dc, VC2_IREG_CONTROL) & VC2_CONTROL_INTERLACE;
543 vc2_write_ireg(dc, VC2_IREG_CONTROL, tmp |
544 VC2_CONTROL_DISPLAY_ENABLE |
545 VC2_CONTROL_VTIMING_ENABLE |
546 VC2_CONTROL_DID_ENABLE |
547 VC2_CONTROL_CURSORFUNC_ENABLE |
548 VC2_CONTROL_CURSOR_ENABLE);
549
550 /* Setup XMAP9s */
551 xmap9_write(dc, XMAP9_DCBCRS_CONFIG,
552 XMAP9_CONFIG_8BIT_SYSTEM | XMAP9_CONFIG_RGBMAP_CI);
553
554 xmap9_write(dc, XMAP9_DCBCRS_CURSOR_CMAP, 0);
555
556 xmap9_write_mode(dc, 0,
557 XMAP9_MODE_GAMMA_BYPASS |
558 XMAP9_MODE_PIXSIZE_8BPP);
559 xmap9_write(dc, XMAP9_DCBCRS_MODE_SELECT, 0);
560
561 /* Setup REX3 */
562 rex3_write(dc, REX3_REG_DRAWMODE1,
563 REX3_DRAWMODE1_PLANES_CI |
564 REX3_DRAWMODE1_DD_DD8 |
565 REX3_DRAWMODE1_RWPACKED |
566 REX3_DRAWMODE1_HD_HD8 |
567 REX3_DRAWMODE1_COMPARE_LT |
568 REX3_DRAWMODE1_COMPARE_EQ |
569 REX3_DRAWMODE1_COMPARE_GT |
570 REX3_DRAWMODE1_LO_SRC);
571 rex3_write(dc, REX3_REG_XYWIN, (4096 << 16) | 4096);
572 rex3_write(dc, REX3_REG_TOPSCAN, 0x3ff); /* XXX Why? XXX */
573
574 /* Setup CMAP */
575 for (i=0; i<16; i++)
576 newport_cmap_setrgb(dc, i, newport_defcmap[i*3],
577 newport_defcmap[i*3 + 1], newport_defcmap[i*3 + 2]);
578 }
579
580 /**** Attach routines ****/
581 static int
582 newport_match(struct device *parent, struct cfdata *self, void *aux)
583 {
584 struct gio_attach_args *ga = aux;
585
586 /* newport doesn't decode all addresses */
587 if (ga->ga_addr != 0x1f000000 && ga->ga_addr != 0x1f400000 &&
588 ga->ga_addr != 0x1f800000 && ga->ga_addr != 0x1fc00000)
589 return 0;
590
591 /* Don't do the destructive probe if we're already attached */
592 if (newport_is_console && ga->ga_addr == newport_console_dc.dc_addr)
593 return 1;
594
595 if (platform.badaddr(
596 (void *)(ga->ga_ioh + NEWPORT_REX3_OFFSET + REX3_REG_XSTARTI),
597 sizeof(uint32_t)))
598 return 0;
599 if (platform.badaddr(
600 (void *)(ga->ga_ioh + NEWPORT_REX3_OFFSET + REX3_REG_XSTART),
601 sizeof(uint32_t)))
602 return 0;
603
604 /* Ugly, this probe is destructive, blame SGI... */
605 /* XXX Should be bus_space_peek/bus_space_poke XXX */
606 bus_space_write_4(ga->ga_iot, ga->ga_ioh,
607 NEWPORT_REX3_OFFSET + REX3_REG_XSTARTI, 0x12345678);
608 if (bus_space_read_4(ga->ga_iot, ga->ga_ioh,
609 NEWPORT_REX3_OFFSET + REX3_REG_XSTART)
610 != ((0x12345678 & 0xffff) << 11))
611 return 0;
612
613 return 1;
614 }
615
616 static void
617 newport_attach_common(struct newport_devconfig *dc, struct gio_attach_args *ga)
618 {
619 dc->dc_addr = ga->ga_addr;
620
621 dc->dc_st = ga->ga_iot;
622 dc->dc_sh = ga->ga_ioh;
623
624 wsfont_init();
625
626 dc->dc_font = wsfont_find(NULL, 8, 16, 0, WSDISPLAY_FONTORDER_L2R,
627 WSDISPLAY_FONTORDER_L2R);
628 if (dc->dc_font < 0)
629 panic("newport_attach_common: no suitable fonts");
630
631 if (wsfont_lock(dc->dc_font, &dc->dc_fontdata))
632 panic("newport_attach_common: unable to lock font data");
633
634 newport_setup_hw(dc);
635
636 newport_get_resolution(dc);
637
638 newport_fill_rectangle(dc, 0, 0, dc->dc_xres, dc->dc_yres, 0);
639 }
640
641 static void
642 newport_attach(struct device *parent, struct device *self, void *aux)
643 {
644 struct gio_attach_args *ga = aux;
645 struct newport_softc *sc = (void *)self;
646 struct wsemuldisplaydev_attach_args wa;
647
648 if (newport_is_console && ga->ga_addr == newport_console_dc.dc_addr) {
649 wa.console = 1;
650 sc->sc_dc = &newport_console_dc;
651 } else {
652 wa.console = 0;
653 sc->sc_dc = malloc(sizeof(struct newport_devconfig),
654 M_DEVBUF, M_WAITOK | M_ZERO);
655 if (sc->sc_dc == NULL)
656 panic("newport_attach: out of memory");
657
658 newport_attach_common(sc->sc_dc, ga);
659 }
660
661 aprint_naive(": Display adapter\n");
662
663 aprint_normal(": SGI NG1 (board revision %d, cmap revision %d, xmap revision %d, vc2 revision %d), depth %d\n",
664 sc->sc_dc->dc_boardrev, sc->sc_dc->dc_cmaprev,
665 sc->sc_dc->dc_xmaprev, sc->sc_dc->dc_vc2rev, sc->sc_dc->dc_depth);
666
667 wa.scrdata = &newport_screenlist;
668 wa.accessops = &newport_accessops;
669 wa.accesscookie = sc->sc_dc;
670
671 config_found(&sc->sc_dev, &wa, wsemuldisplaydevprint);
672 }
673
674 int
675 newport_cnattach(struct gio_attach_args *ga)
676 {
677 long defattr = NEWPORT_ATTR_ENCODE(WSCOL_WHITE, WSCOL_BLACK);
678 const struct wsscreen_descr *screen;
679
680 if (!newport_match(NULL, NULL, ga)) {
681 return ENXIO;
682 }
683
684 newport_attach_common(&newport_console_dc, ga);
685
686 if (newport_console_dc.dc_xres >= 1280 &&
687 newport_console_dc.dc_yres >= 1024)
688 screen = &newport_screen_1280x1024;
689 else
690 screen = &newport_screen_1024x768;
691
692 wsdisplay_cnattach(screen, &newport_console_dc, 0, 0, defattr);
693
694 newport_is_console = 1;
695
696 return 0;
697 }
698
699 /**** wsdisplay textops ****/
700 static void
701 newport_cursor(void *c, int on, int row, int col)
702 {
703 struct newport_devconfig *dc = (void *)c;
704 uint16_t control;
705 int x_offset;
706
707 control = vc2_read_ireg(dc, VC2_IREG_CONTROL);
708
709 if (!on) {
710 vc2_write_ireg(dc, VC2_IREG_CONTROL,
711 control & ~VC2_CONTROL_CURSOR_ENABLE);
712 } else {
713 /* Work around bug in some board revisions */
714 if (dc->dc_vc2rev == 0)
715 x_offset = 29;
716 else if (dc->dc_boardrev < 6)
717 x_offset = 21;
718 else
719 x_offset = 31;
720
721 vc2_write_ireg(dc, VC2_IREG_CURSOR_X,
722 col * dc->dc_fontdata->fontwidth + x_offset);
723 vc2_write_ireg(dc, VC2_IREG_CURSOR_Y,
724 row * dc->dc_fontdata->fontheight + 31);
725
726 vc2_write_ireg(dc, VC2_IREG_CONTROL,
727 control | VC2_CONTROL_CURSOR_ENABLE);
728 }
729 }
730
731 static int
732 newport_mapchar(void *c, int ch, unsigned int *cp)
733 {
734 struct newport_devconfig *dc = (void *)c;
735
736 if (dc->dc_fontdata->encoding != WSDISPLAY_FONTENC_ISO) {
737 ch = wsfont_map_unichar(dc->dc_fontdata, ch);
738
739 if (ch < 0)
740 goto fail;
741 }
742
743 if (ch < dc->dc_fontdata->firstchar ||
744 ch >= dc->dc_fontdata->firstchar + dc->dc_fontdata->numchars)
745 goto fail;
746
747 *cp = ch;
748 return 5;
749
750 fail:
751 *cp = ' ';
752 return 0;
753 }
754
755 static void
756 newport_putchar(void *c, int row, int col, u_int ch, long attr)
757 {
758 struct newport_devconfig *dc = (void *)c;
759 struct wsdisplay_font *font = dc->dc_fontdata;
760 uint8_t *bitmap = (u_int8_t *)font->data + (ch - font->firstchar) *
761 font->fontheight * font->stride;
762 uint32_t pattern;
763 int i;
764 int x = col * font->fontwidth;
765 int y = row * font->fontheight;
766
767 rex3_wait_gfifo(dc);
768
769 rex3_write(dc, REX3_REG_DRAWMODE0, REX3_DRAWMODE0_OPCODE_DRAW |
770 REX3_DRAWMODE0_ADRMODE_BLOCK | REX3_DRAWMODE0_STOPONX |
771 REX3_DRAWMODE0_ENZPATTERN | REX3_DRAWMODE0_ZPOPAQUE);
772
773 rex3_write(dc, REX3_REG_XYSTARTI, (x << REX3_XYSTARTI_XSHIFT) | y);
774 rex3_write(dc, REX3_REG_XYENDI,
775 (x + font->fontwidth - 1) << REX3_XYENDI_XSHIFT);
776
777 rex3_write(dc, REX3_REG_COLORI, NEWPORT_ATTR_FG(attr));
778 rex3_write(dc, REX3_REG_COLORBACK, NEWPORT_ATTR_BG(attr));
779
780 rex3_write(dc, REX3_REG_WRMASK, 0xffffffff);
781
782 for (i=0; i<font->fontheight; i++) {
783 /* XXX Works only with font->fontwidth == 8 XXX */
784 pattern = *bitmap << 24;
785
786 rex3_write_go(dc, REX3_REG_ZPATTERN, pattern);
787
788 bitmap += font->stride;
789 }
790 }
791
792 static void
793 newport_copycols(void *c, int row, int srccol, int dstcol, int ncols)
794 {
795 struct newport_devconfig *dc = (void *)c;
796 struct wsdisplay_font *font = dc->dc_fontdata;
797
798 newport_copy_rectangle(dc,
799 srccol * font->fontwidth, /* x1 */
800 row * font->fontheight, /* y1 */
801 (srccol + ncols) * font->fontwidth - 1, /* x2 */
802 (row + 1) * font->fontheight - 1, /* y2 */
803 dstcol * font->fontheight, /* dx */
804 row * font->fontheight); /* dy */
805 }
806
807 static void
808 newport_erasecols(void *c, int row, int startcol, int ncols,
809 long attr)
810 {
811 struct newport_devconfig *dc = (void *)c;
812 struct wsdisplay_font *font = dc->dc_fontdata;
813
814 newport_fill_rectangle(dc,
815 startcol * font->fontwidth, /* x1 */
816 row * font->fontheight, /* y1 */
817 (startcol + ncols) * font->fontwidth - 1, /* x2 */
818 (row + 1) * font->fontheight - 1, /* y2 */
819 NEWPORT_ATTR_BG(attr));
820 }
821
822 static void
823 newport_copyrows(void *c, int srcrow, int dstrow, int nrows)
824 {
825 struct newport_devconfig *dc = (void *)c;
826 struct wsdisplay_font *font = dc->dc_fontdata;
827
828 newport_copy_rectangle(dc,
829 0, /* x1 */
830 srcrow * font->fontheight, /* y1 */
831 dc->dc_xres, /* x2 */
832 (srcrow + nrows) * font->fontheight - 1, /* y2 */
833 0, /* dx */
834 dstrow * font->fontheight); /* dy */
835 }
836
837 static void
838 newport_eraserows(void *c, int startrow, int nrows, long attr)
839 {
840 struct newport_devconfig *dc = (void *)c;
841 struct wsdisplay_font *font = dc->dc_fontdata;
842
843 newport_fill_rectangle(dc,
844 0, /* x1 */
845 startrow * font->fontheight, /* y1 */
846 dc->dc_xres, /* x2 */
847 (startrow + nrows) * font->fontheight - 1, /* y2 */
848 NEWPORT_ATTR_BG(attr));
849 }
850
851 static int
852 newport_allocattr(void *c, int fg, int bg, int flags, long *attr)
853 {
854 if (flags & WSATTR_BLINK)
855 return EINVAL;
856
857 if ((flags & WSATTR_WSCOLORS) == 0) {
858 fg = WSCOL_WHITE;
859 bg = WSCOL_BLACK;
860 }
861
862 if (flags & WSATTR_HILIT)
863 fg += 8;
864
865 if (flags & WSATTR_REVERSE) {
866 int tmp = fg;
867 fg = bg;
868 bg = tmp;
869 }
870
871 *attr = NEWPORT_ATTR_ENCODE(fg, bg);
872
873 return 0;
874 }
875
876 /**** wsdisplay accessops ****/
877
878 static int
879 newport_ioctl(void *c, void *vs, u_long cmd, void *data, int flag,
880 struct lwp *l)
881 {
882 struct newport_softc *sc = c;
883
884 #define FBINFO (*(struct wsdisplay_fbinfo*)data)
885
886 switch (cmd) {
887 case WSDISPLAYIO_GINFO:
888 FBINFO.width = sc->sc_dc->dc_xres;
889 FBINFO.height = sc->sc_dc->dc_yres;
890 FBINFO.depth = sc->sc_dc->dc_depth;
891 FBINFO.cmsize = 1 << FBINFO.depth;
892 return 0;
893 case WSDISPLAYIO_GTYPE:
894 *(u_int *)data = WSDISPLAY_TYPE_NEWPORT;
895 return 0;
896 }
897 return EPASSTHROUGH;
898 }
899
900 static paddr_t
901 newport_mmap(void *c, void *vs, off_t offset, int prot)
902 {
903 struct newport_devconfig *dc = c;
904
905 if ( offset >= 0xfffff)
906 return -1;
907
908 return mips_btop(dc->dc_addr + offset);
909 }
910
911 static int
912 newport_alloc_screen(void *c, const struct wsscreen_descr *type, void **cookiep,
913 int *cursxp, int *cursyp, long *attrp)
914 {
915 /* This won't get called for console screen and we don't support
916 * virtual screens */
917
918 return ENOMEM;
919 }
920
921 static void
922 newport_free_screen(void *c, void *cookie)
923 {
924 panic("newport_free_screen");
925 }
926 static int
927 newport_show_screen(void *c, void *cookie, int waitok,
928 void (*cb)(void *, int, int), void *cbarg)
929 {
930 return 0;
931 }
932