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