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