newport.c revision 1.10 1 /* $NetBSD: newport.c,v 1.10 2007/03/04 06:00:39 christos 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.10 2007/03/04 06:00:39 christos 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
411 rex3_write(dc, REX3_REG_DRAWMODE0, REX3_DRAWMODE0_OPCODE_SCR2SCR |
412 REX3_DRAWMODE0_ADRMODE_BLOCK | REX3_DRAWMODE0_DOSETUP |
413 REX3_DRAWMODE0_STOPONX | REX3_DRAWMODE0_STOPONY);
414 rex3_write(dc, REX3_REG_XYSTARTI, (x1 << REX3_XYSTARTI_XSHIFT) | y1);
415 rex3_write(dc, REX3_REG_XYENDI, (x2 << REX3_XYENDI_XSHIFT) | y2);
416
417 tmp = (dy - y1) & 0xffff;
418 tmp |= (dx - x1) << REX3_XYMOVE_XSHIFT;
419
420 rex3_write_go(dc, REX3_REG_XYMOVE, tmp);
421 }
422
423 static void
424 newport_cmap_setrgb(struct newport_devconfig *dc, int index, uint8_t r,
425 uint8_t g, uint8_t b)
426 {
427 rex3_write(dc, REX3_REG_DCBMODE,
428 REX3_DCBMODE_DW_2 |
429 REX3_DCBMODE_ENCRSINC |
430 (NEWPORT_DCBADDR_CMAP_BOTH << REX3_DCBMODE_DCBADDR_SHIFT) |
431 (CMAP_DCBCRS_ADDRESS_LOW << REX3_DCBMODE_DCBCRS_SHIFT) |
432 (1 << REX3_DCBMODE_CSWIDTH_SHIFT) |
433 (1 << REX3_DCBMODE_CSHOLD_SHIFT) |
434 (1 << REX3_DCBMODE_CSSETUP_SHIFT) |
435 REX3_DCBMODE_SWAPENDIAN);
436
437 rex3_write(dc, REX3_REG_DCBDATA0, index << 16);
438
439 rex3_write(dc, REX3_REG_DCBMODE,
440 REX3_DCBMODE_DW_3 |
441 (NEWPORT_DCBADDR_CMAP_BOTH << REX3_DCBMODE_DCBADDR_SHIFT) |
442 (CMAP_DCBCRS_PALETTE << REX3_DCBMODE_DCBCRS_SHIFT) |
443 (1 << REX3_DCBMODE_CSWIDTH_SHIFT) |
444 (1 << REX3_DCBMODE_CSHOLD_SHIFT) |
445 (1 << REX3_DCBMODE_CSSETUP_SHIFT));
446
447 rex3_write(dc, REX3_REG_DCBDATA0, (r << 24) + (g << 16) + (b << 8));
448 }
449
450 static void
451 newport_get_resolution(struct newport_devconfig *dc)
452 {
453 uint16_t vep,lines;
454 uint16_t linep,cols;
455 uint16_t data;
456
457 vep = vc2_read_ireg(dc, VC2_IREG_VIDEO_ENTRY);
458
459 dc->dc_xres = 0;
460 dc->dc_yres = 0;
461
462 for (;;) {
463 /* Iterate over runs in video timing table */
464
465 cols = 0;
466
467 linep = vc2_read_ram(dc, vep++);
468 lines = vc2_read_ram(dc, vep++);
469
470 if (lines == 0)
471 break;
472
473 do {
474 /* Iterate over state runs in line sequence table */
475
476 data = vc2_read_ram(dc, linep++);
477
478 if ((data & 0x0001) == 0)
479 cols += (data >> 7) & 0xfe;
480
481 if ((data & 0x0080) == 0)
482 data = vc2_read_ram(dc, linep++);
483 } while ((data & 0x8000) == 0);
484
485 if (cols != 0) {
486 if (cols > dc->dc_xres)
487 dc->dc_xres = cols;
488
489 dc->dc_yres += lines;
490 }
491 }
492 }
493
494 static void
495 newport_setup_hw(struct newport_devconfig *dc)
496 {
497 uint16_t curp,tmp;
498 int i;
499 uint32_t scratch;
500
501 /* Get various revisions */
502 rex3_write(dc, REX3_REG_DCBMODE,
503 REX3_DCBMODE_DW_1 |
504 (NEWPORT_DCBADDR_CMAP_0 << REX3_DCBMODE_DCBADDR_SHIFT) |
505 (CMAP_DCBCRS_REVISION << REX3_DCBMODE_DCBCRS_SHIFT) |
506 (1 << REX3_DCBMODE_CSWIDTH_SHIFT) |
507 (1 << REX3_DCBMODE_CSHOLD_SHIFT) |
508 (1 << REX3_DCBMODE_CSSETUP_SHIFT));
509
510 scratch = vc2_read_ireg(dc, VC2_IREG_CONFIG);
511 dc->dc_vc2rev = (scratch & VC2_IREG_CONFIG_REVISION) >> 5;
512
513 scratch = rex3_read(dc, REX3_REG_DCBDATA0);
514
515 dc->dc_boardrev = (scratch >> 28) & 0x07;
516 dc->dc_cmaprev = scratch & 0x07;
517 dc->dc_xmaprev = xmap9_read(dc, XMAP9_DCBCRS_REVISION) & 0x07;
518 dc->dc_depth = ( (dc->dc_boardrev > 1) && (scratch & 0x80)) ? 8 : 24;
519
520 /* Setup cursor glyph */
521 curp = vc2_read_ireg(dc, VC2_IREG_CURSOR_ENTRY);
522
523 for (i=0; i<128; i++)
524 vc2_write_ram(dc, curp + i, newport_cursor_data[i]);
525
526 /* Setup VC2 to a known state */
527 tmp = vc2_read_ireg(dc, VC2_IREG_CONTROL) & VC2_CONTROL_INTERLACE;
528 vc2_write_ireg(dc, VC2_IREG_CONTROL, tmp |
529 VC2_CONTROL_DISPLAY_ENABLE |
530 VC2_CONTROL_VTIMING_ENABLE |
531 VC2_CONTROL_DID_ENABLE |
532 VC2_CONTROL_CURSORFUNC_ENABLE |
533 VC2_CONTROL_CURSOR_ENABLE);
534
535 /* Setup XMAP9s */
536 xmap9_write(dc, XMAP9_DCBCRS_CONFIG,
537 XMAP9_CONFIG_8BIT_SYSTEM | XMAP9_CONFIG_RGBMAP_CI);
538
539 xmap9_write(dc, XMAP9_DCBCRS_CURSOR_CMAP, 0);
540
541 xmap9_write_mode(dc, 0,
542 XMAP9_MODE_GAMMA_BYPASS |
543 XMAP9_MODE_PIXSIZE_8BPP);
544 xmap9_write(dc, XMAP9_DCBCRS_MODE_SELECT, 0);
545
546 /* Setup REX3 */
547 rex3_write(dc, REX3_REG_DRAWMODE1,
548 REX3_DRAWMODE1_PLANES_CI |
549 REX3_DRAWMODE1_DD_DD8 |
550 REX3_DRAWMODE1_RWPACKED |
551 REX3_DRAWMODE1_HD_HD8 |
552 REX3_DRAWMODE1_COMPARE_LT |
553 REX3_DRAWMODE1_COMPARE_EQ |
554 REX3_DRAWMODE1_COMPARE_GT |
555 REX3_DRAWMODE1_LO_SRC);
556 rex3_write(dc, REX3_REG_XYWIN, (4096 << 16) | 4096);
557 rex3_write(dc, REX3_REG_TOPSCAN, 0x3ff); /* XXX Why? XXX */
558
559 /* Setup CMAP */
560 for (i=0; i<16; i++)
561 newport_cmap_setrgb(dc, i, newport_defcmap[i*3],
562 newport_defcmap[i*3 + 1], newport_defcmap[i*3 + 2]);
563 }
564
565 /**** Attach routines ****/
566 static int
567 newport_match(struct device *parent, struct cfdata *self, void *aux)
568 {
569 struct gio_attach_args *ga = aux;
570
571 /* newport doesn't decode all addresses */
572 if (ga->ga_addr != 0x1f000000 && ga->ga_addr != 0x1f400000 &&
573 ga->ga_addr != 0x1f800000 && ga->ga_addr != 0x1fc00000)
574 return 0;
575
576 /* Don't do the destructive probe if we're already attached */
577 if (newport_is_console && ga->ga_addr == newport_console_dc.dc_addr)
578 return 1;
579
580 if (platform.badaddr(
581 (void *)(ga->ga_ioh + NEWPORT_REX3_OFFSET + REX3_REG_XSTARTI),
582 sizeof(uint32_t)))
583 return 0;
584 if (platform.badaddr(
585 (void *)(ga->ga_ioh + NEWPORT_REX3_OFFSET + REX3_REG_XSTART),
586 sizeof(uint32_t)))
587 return 0;
588
589 /* Ugly, this probe is destructive, blame SGI... */
590 /* XXX Should be bus_space_peek/bus_space_poke XXX */
591 bus_space_write_4(ga->ga_iot, ga->ga_ioh,
592 NEWPORT_REX3_OFFSET + REX3_REG_XSTARTI, 0x12345678);
593 if (bus_space_read_4(ga->ga_iot, ga->ga_ioh,
594 NEWPORT_REX3_OFFSET + REX3_REG_XSTART)
595 != ((0x12345678 & 0xffff) << 11))
596 return 0;
597
598 return 1;
599 }
600
601 static void
602 newport_attach_common(struct newport_devconfig *dc, struct gio_attach_args *ga)
603 {
604 dc->dc_addr = ga->ga_addr;
605
606 dc->dc_st = ga->ga_iot;
607 dc->dc_sh = ga->ga_ioh;
608
609 wsfont_init();
610
611 dc->dc_font = wsfont_find(NULL, 8, 16, 0, WSDISPLAY_FONTORDER_L2R,
612 WSDISPLAY_FONTORDER_L2R);
613 if (dc->dc_font < 0)
614 panic("newport_attach_common: no suitable fonts");
615
616 if (wsfont_lock(dc->dc_font, &dc->dc_fontdata))
617 panic("newport_attach_common: unable to lock font data");
618
619 newport_setup_hw(dc);
620
621 newport_get_resolution(dc);
622
623 newport_fill_rectangle(dc, 0, 0, dc->dc_xres, dc->dc_yres, 0);
624 }
625
626 static void
627 newport_attach(struct device *parent, struct device *self, void *aux)
628 {
629 struct gio_attach_args *ga = aux;
630 struct newport_softc *sc = (void *)self;
631 struct wsemuldisplaydev_attach_args wa;
632
633 if (newport_is_console && ga->ga_addr == newport_console_dc.dc_addr) {
634 wa.console = 1;
635 sc->sc_dc = &newport_console_dc;
636 } else {
637 wa.console = 0;
638 sc->sc_dc = malloc(sizeof(struct newport_devconfig),
639 M_DEVBUF, M_WAITOK | M_ZERO);
640 if (sc->sc_dc == NULL)
641 panic("newport_attach: out of memory");
642
643 newport_attach_common(sc->sc_dc, ga);
644 }
645
646 aprint_naive(": Display adapter\n");
647
648 aprint_normal(": SGI NG1 (board revision %d, cmap revision %d, xmap revision %d, vc2 revision %d), depth %d\n",
649 sc->sc_dc->dc_boardrev, sc->sc_dc->dc_cmaprev,
650 sc->sc_dc->dc_xmaprev, sc->sc_dc->dc_vc2rev, sc->sc_dc->dc_depth);
651
652 wa.scrdata = &newport_screenlist;
653 wa.accessops = &newport_accessops;
654 wa.accesscookie = sc->sc_dc;
655
656 config_found(&sc->sc_dev, &wa, wsemuldisplaydevprint);
657 }
658
659 int
660 newport_cnattach(struct gio_attach_args *ga)
661 {
662 long defattr = NEWPORT_ATTR_ENCODE(WSCOL_WHITE, WSCOL_BLACK);
663 const struct wsscreen_descr *screen;
664
665 if (!newport_match(NULL, NULL, ga)) {
666 return ENXIO;
667 }
668
669 newport_attach_common(&newport_console_dc, ga);
670
671 if (newport_console_dc.dc_xres >= 1280 &&
672 newport_console_dc.dc_yres >= 1024)
673 screen = &newport_screen_1280x1024;
674 else
675 screen = &newport_screen_1024x768;
676
677 wsdisplay_cnattach(screen, &newport_console_dc, 0, 0, defattr);
678
679 newport_is_console = 1;
680
681 return 0;
682 }
683
684 /**** wsdisplay textops ****/
685 static void
686 newport_cursor(void *c, int on, int row, int col)
687 {
688 struct newport_devconfig *dc = (void *)c;
689 uint16_t control;
690 int x_offset;
691
692 control = vc2_read_ireg(dc, VC2_IREG_CONTROL);
693
694 if (!on) {
695 vc2_write_ireg(dc, VC2_IREG_CONTROL,
696 control & ~VC2_CONTROL_CURSOR_ENABLE);
697 } else {
698 /* Work around bug in some board revisions */
699 if (dc->dc_boardrev < 6)
700 x_offset = 21;
701 else if (dc->dc_vc2rev == 0)
702 x_offset = 29;
703 else
704 x_offset = 31;
705
706 vc2_write_ireg(dc, VC2_IREG_CURSOR_X,
707 col * dc->dc_fontdata->fontwidth + x_offset);
708 vc2_write_ireg(dc, VC2_IREG_CURSOR_Y,
709 row * dc->dc_fontdata->fontheight + 31);
710
711 vc2_write_ireg(dc, VC2_IREG_CONTROL,
712 control | VC2_CONTROL_CURSOR_ENABLE);
713 }
714 }
715
716 static int
717 newport_mapchar(void *c, int ch, unsigned int *cp)
718 {
719 struct newport_devconfig *dc = (void *)c;
720
721 if (dc->dc_fontdata->encoding != WSDISPLAY_FONTENC_ISO) {
722 ch = wsfont_map_unichar(dc->dc_fontdata, ch);
723
724 if (ch < 0)
725 goto fail;
726 }
727
728 if (ch < dc->dc_fontdata->firstchar ||
729 ch >= dc->dc_fontdata->firstchar + dc->dc_fontdata->numchars)
730 goto fail;
731
732 *cp = ch;
733 return 5;
734
735 fail:
736 *cp = ' ';
737 return 0;
738 }
739
740 static void
741 newport_putchar(void *c, int row, int col, u_int ch, long attr)
742 {
743 struct newport_devconfig *dc = (void *)c;
744 struct wsdisplay_font *font = dc->dc_fontdata;
745 uint8_t *bitmap = (u_int8_t *)font->data + (ch - font->firstchar) *
746 font->fontheight * font->stride;
747 uint32_t pattern;
748 int i;
749 int x = col * font->fontwidth;
750 int y = row * font->fontheight;
751
752 rex3_wait_gfifo(dc);
753
754 rex3_write(dc, REX3_REG_DRAWMODE0, REX3_DRAWMODE0_OPCODE_DRAW |
755 REX3_DRAWMODE0_ADRMODE_BLOCK | REX3_DRAWMODE0_STOPONX |
756 REX3_DRAWMODE0_ENZPATTERN | REX3_DRAWMODE0_ZPOPAQUE);
757
758 rex3_write(dc, REX3_REG_XYSTARTI, (x << REX3_XYSTARTI_XSHIFT) | y);
759 rex3_write(dc, REX3_REG_XYENDI,
760 (x + font->fontwidth - 1) << REX3_XYENDI_XSHIFT);
761
762 rex3_write(dc, REX3_REG_COLORI, NEWPORT_ATTR_FG(attr));
763 rex3_write(dc, REX3_REG_COLORBACK, NEWPORT_ATTR_BG(attr));
764
765 rex3_write(dc, REX3_REG_WRMASK, 0xffffffff);
766
767 for (i=0; i<font->fontheight; i++) {
768 /* XXX Works only with font->fontwidth == 8 XXX */
769 pattern = *bitmap << 24;
770
771 rex3_write_go(dc, REX3_REG_ZPATTERN, pattern);
772
773 bitmap += font->stride;
774 }
775 }
776
777 static void
778 newport_copycols(void *c, int row, int srccol, int dstcol, int ncols)
779 {
780 struct newport_devconfig *dc = (void *)c;
781 struct wsdisplay_font *font = dc->dc_fontdata;
782
783 newport_copy_rectangle(dc,
784 srccol * font->fontwidth, /* x1 */
785 row * font->fontheight, /* y1 */
786 (srccol + ncols + 1) * font->fontwidth - 1, /* x2 */
787 (row + 1) * font->fontheight - 1, /* y2 */
788 dstcol * font->fontheight, /* dx */
789 row * font->fontheight); /* dy */
790 }
791
792 static void
793 newport_erasecols(void *c, int row, int startcol, int ncols,
794 long attr)
795 {
796 struct newport_devconfig *dc = (void *)c;
797 struct wsdisplay_font *font = dc->dc_fontdata;
798
799 newport_fill_rectangle(dc,
800 startcol * font->fontwidth, /* x1 */
801 row * font->fontheight, /* y1 */
802 (startcol + ncols + 1) * font->fontwidth - 1, /* x2 */
803 (row + 1) * font->fontheight - 1, /* y2 */
804 NEWPORT_ATTR_BG(attr));
805 }
806
807 static void
808 newport_copyrows(void *c, int srcrow, int dstrow, int nrows)
809 {
810 struct newport_devconfig *dc = (void *)c;
811 struct wsdisplay_font *font = dc->dc_fontdata;
812
813 newport_copy_rectangle(dc,
814 0, /* x1 */
815 srcrow * font->fontheight, /* y1 */
816 dc->dc_xres, /* x2 */
817 (srcrow + nrows + 1) * font->fontheight - 1, /* y2 */
818 0, /* dx */
819 dstrow * font->fontheight); /* dy */
820 }
821
822 static void
823 newport_eraserows(void *c, int startrow, int nrows, long attr)
824 {
825 struct newport_devconfig *dc = (void *)c;
826 struct wsdisplay_font *font = dc->dc_fontdata;
827
828 newport_fill_rectangle(dc,
829 0, /* x1 */
830 startrow * font->fontheight, /* y1 */
831 dc->dc_xres, /* x2 */
832 (startrow + nrows + 1) * font->fontheight - 1, /* y2 */
833 NEWPORT_ATTR_BG(attr));
834 }
835
836 static int
837 newport_allocattr(void *c, int fg, int bg, int flags, long *attr)
838 {
839 if (flags & WSATTR_BLINK)
840 return EINVAL;
841
842 if ((flags & WSATTR_WSCOLORS) == 0) {
843 fg = WSCOL_WHITE;
844 bg = WSCOL_BLACK;
845 }
846
847 if (flags & WSATTR_HILIT)
848 fg += 8;
849
850 if (flags & WSATTR_REVERSE) {
851 int tmp = fg;
852 fg = bg;
853 bg = tmp;
854 }
855
856 *attr = NEWPORT_ATTR_ENCODE(fg, bg);
857
858 return 0;
859 }
860
861 /**** wsdisplay accessops ****/
862
863 static int
864 newport_ioctl(void *c, void *vs, u_long cmd, void *data, int flag,
865 struct lwp *l)
866 {
867 struct newport_softc *sc = c;
868
869 #define FBINFO (*(struct wsdisplay_fbinfo*)data)
870
871 switch (cmd) {
872 case WSDISPLAYIO_GINFO:
873 FBINFO.width = sc->sc_dc->dc_xres;
874 FBINFO.height = sc->sc_dc->dc_yres;
875 FBINFO.depth = sc->sc_dc->dc_depth;
876 FBINFO.cmsize = 1 << FBINFO.depth;
877 return 0;
878 case WSDISPLAYIO_GTYPE:
879 *(u_int *)data = WSDISPLAY_TYPE_NEWPORT;
880 return 0;
881 }
882 return EPASSTHROUGH;
883 }
884
885 static paddr_t
886 newport_mmap(void *c, void *vs, off_t offset, int prot)
887 {
888 struct newport_devconfig *dc = c;
889
890 if ( offset >= 0xfffff)
891 return -1;
892
893 return mips_btop(dc->dc_addr + offset);
894 }
895
896 static int
897 newport_alloc_screen(void *c, const struct wsscreen_descr *type, void **cookiep,
898 int *cursxp, int *cursyp, long *attrp)
899 {
900 /* This won't get called for console screen and we don't support
901 * virtual screens */
902
903 return ENOMEM;
904 }
905
906 static void
907 newport_free_screen(void *c, void *cookie)
908 {
909 panic("newport_free_screen");
910 }
911 static int
912 newport_show_screen(void *c, void *cookie, int waitok,
913 void (*cb)(void *, int, int), void *cbarg)
914 {
915 return 0;
916 }
917