crmfb.c revision 1.6 1 /* $NetBSD: crmfb.c,v 1.6 2007/07/15 05:42:13 macallan Exp $ */
2
3 /*-
4 * Copyright (c) 2007 Jared D. McNeill <jmcneill (at) invisible.ca>
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. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Jared D. McNeill.
18 * 4. Neither the name of The NetBSD Foundation nor the names of its
19 * contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
26 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 */
34
35 /*
36 * SGI-CRM (O2) Framebuffer driver
37 */
38
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: crmfb.c,v 1.6 2007/07/15 05:42:13 macallan Exp $");
41
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/device.h>
45 #include <sys/malloc.h>
46
47 #define _SGIMIPS_BUS_DMA_PRIVATE
48 #include <machine/autoconf.h>
49 #include <machine/bus.h>
50 #include <machine/machtype.h>
51 #include <machine/vmparam.h>
52
53 #include <dev/arcbios/arcbios.h>
54 #include <dev/arcbios/arcbiosvar.h>
55
56 #include <dev/wscons/wsdisplayvar.h>
57 #include <dev/wscons/wsconsio.h>
58 #include <dev/wsfont/wsfont.h>
59 #include <dev/rasops/rasops.h>
60 #include <dev/wscons/wsdisplay_vconsvar.h>
61
62 #define CRMFB_SHADOWFB
63
64 struct wsscreen_descr crmfb_defaultscreen = {
65 "default",
66 0, 0,
67 NULL,
68 8, 16,
69 WSSCREEN_WSCOLORS,
70 NULL,
71 };
72
73 const struct wsscreen_descr *_crmfb_scrlist[] = {
74 &crmfb_defaultscreen,
75 };
76
77 struct wsscreen_list crmfb_screenlist = {
78 sizeof(_crmfb_scrlist) / sizeof(struct wsscreen_descr *),
79 _crmfb_scrlist
80 };
81
82 static struct vcons_screen crmfb_console_screen;
83
84 static int crmfb_ioctl(void *, void *, u_long, void *, int, struct lwp *);
85 static paddr_t crmfb_mmap(void *, void *, off_t, int);
86 static void crmfb_init_screen(void *, struct vcons_screen *, int, long *);
87
88 struct wsdisplay_accessops crmfb_accessops = {
89 crmfb_ioctl,
90 crmfb_mmap,
91 NULL, /* alloc_screen */
92 NULL, /* free_screen */
93 NULL, /* show_screen */
94 NULL, /* load_font */
95 NULL, /* pollc */
96 NULL, /* scroll */
97 };
98
99 /* Memory to allocate to SGI-CRM -- remember, this is stolen from
100 * host memory!
101 */
102 #define CRMFB_TILESIZE (512*128)
103
104 #define CRMFB_DOTCLOCK 0x00000004
105 #define CRMFB_DOTCLOCK_CLKRUN_SHIFT 20
106 #define CRMFB_VT_XY 0x00010000
107 #define CRMFB_VT_XY_FREEZE_SHIFT 31
108 #define CRMFB_VT_INTR01 0x00010020
109 #define CRMFB_VT_INTR01_EN 0xffffffff
110 #define CRMFB_VT_INTR23 0x00010024
111 #define CRMFB_VT_INTR23_EN 0xffffffff
112 #define CRMFB_VT_VPIX_EN 0x00010038
113 #define CRMFB_VT_VPIX_EN_OFF_SHIFT 0
114 #define CRMFB_VT_VCMAP 0x0001003c
115 #define CRMFB_VT_VCMAP_ON_SHIFT 12
116 #define CRMFB_VT_HCMAP 0x00010040
117 #define CRMFB_VT_HCMAP_ON_SHIFT 12
118 #define CRMFB_OVR_WIDTH_TILE 0x00020000
119 #define CRMFB_OVR_CONTROL 0x00020008
120 #define CRMFB_OVR_CONTROL_DMAEN_SHIFT 0
121 #define CRMFB_FRM_TILESIZE 0x00030000
122 #define CRMFB_FRM_TILESIZE_RHS_SHIFT 0
123 #define CRMFB_FRM_TILESIZE_WIDTH_SHIFT 5
124 #define CRMFB_FRM_TILESIZE_DEPTH_SHIFT 13
125 #define CRMFB_FRM_TILESIZE_DEPTH_8 0
126 #define CRMFB_FRM_TILESIZE_DEPTH_16 1
127 #define CRMFB_FRM_TILESIZE_DEPTH_32 2
128 #define CRMFB_FRM_TILESIZE_FIFOR_SHIFT 15
129 #define CRMFB_FRM_PIXSIZE 0x00030004
130 #define CRMFB_FRM_PIXSIZE_HEIGHT_SHIFT 16
131 #define CRMFB_FRM_CONTROL 0x0003000c
132 #define CRMFB_FRM_CONTROL_DMAEN_SHIFT 0
133 #define CRMFB_FRM_CONTROL_LINEAR_SHIFT 1
134 #define CRMFB_FRM_CONTROL_TILEPTR_SHIFT 9
135 #define CRMFB_DID_CONTROL 0x00040004
136 #define CRMFB_DID_CONTROL_DMAEN_SHIFT 0
137 #define CRMFB_MODE 0x00048000
138 #define CRMFB_MODE_TYP_SHIFT 2
139 #define CRMFB_MODE_TYP_I8 0
140 #define CRMFB_MODE_TYP_ARGB5 4
141 #define CRMFB_MODE_TYP_RGB8 5
142 #define CRMFB_MODE_BUF_SHIFT 0
143 #define CRMFB_MODE_BUF_BOTH 3
144 #define CRMFB_CMAP 0x00050000
145 #define CRMFB_CMAP_FIFO 0x00058000
146 #define CRMFB_GMAP 0x00060000
147 #define CRMFB_CURSOR_POS 0x00070000
148 /*
149 * upper 16 bit are Y, lower 16 bit are X - both signed so there's no need for
150 * a hotspot register
151 */
152 #define CRMFB_CURSOR_CONTROL 0x00070004
153 #define CRMFB_CURSOR_ON 0x00000001
154 #define CRMFB_CURSOR_CMAP0 0x00070008
155 #define CRMFB_CURSOR_CMAP1 0x0007000c
156 #define CRMFB_CURSOR_CMAP2 0x00070010
157 #define CRMFB_CURSOR_BITMAP 0x00078000
158 /* two bit deep cursor image, zero is transparent */
159
160 /* rendering engine registers */
161 #define CRIME_RE_TLB_A 0x1000
162 #define CRIME_RE_TLB_B 0x1200
163 #define CRIME_RE_TLB_C 0x1400
164 #define CRIME_RE_TEX 0x1600
165 #define CRIME_RE_CLIP_IDS 0x16e0
166 #define CRIME_RE_LINEAR_A 0x1700
167 #define CRIME_RE_LINEAR_B 0x1780
168
169
170 static int crmfb_match(struct device *, struct cfdata *, void *);
171 static void crmfb_attach(struct device *, struct device *, void *);
172 int crmfb_probe(void);
173
174 #define KERNADDR(p) ((void *)((p).addr))
175 #define DMAADDR(p) ((p).map->dm_segs[0].ds_addr)
176
177 struct crmfb_dma {
178 bus_dmamap_t map;
179 void *addr;
180 bus_dma_segment_t segs[1];
181 int nsegs;
182 size_t size;
183 };
184
185 struct crmfb_softc {
186 struct device sc_dev;
187 struct vcons_data sc_vd;
188
189 bus_space_tag_t sc_iot;
190 bus_space_handle_t sc_ioh;
191 bus_space_handle_t sc_reh; /* rendering engine registers */
192 bus_dma_tag_t sc_dmat;
193
194 struct crmfb_dma sc_dma;
195 struct crmfb_dma sc_dmai;
196
197 int sc_width;
198 int sc_height;
199 int sc_depth;
200 uint32_t sc_fbsize;
201 uint8_t *sc_shadowfb;
202
203 int sc_wsmode;
204
205 /* cursor stuff */
206 int sc_cur_x;
207 int sc_cur_y;
208 int sc_hot_x;
209 int sc_hot_y;
210
211 u_char sc_cmap_red[256];
212 u_char sc_cmap_green[256];
213 u_char sc_cmap_blue[256];
214 };
215
216 static int crmfb_putcmap(struct crmfb_softc *, struct wsdisplay_cmap *);
217 static int crmfb_getcmap(struct crmfb_softc *, struct wsdisplay_cmap *);
218 static void crmfb_set_palette(struct crmfb_softc *,
219 int, uint8_t, uint8_t, uint8_t);
220 static int crmfb_set_curpos(struct crmfb_softc *, int, int);
221 static int crmfb_gcursor(struct crmfb_softc *, struct wsdisplay_cursor *);
222 static int crmfb_scursor(struct crmfb_softc *, struct wsdisplay_cursor *);
223
224 CFATTACH_DECL(crmfb, sizeof(struct crmfb_softc),
225 crmfb_match, crmfb_attach, NULL, NULL);
226
227 static int
228 crmfb_match(struct device *parent, struct cfdata *cf, void *opaque)
229 {
230 return crmfb_probe();
231 }
232
233 static void
234 crmfb_attach(struct device *parent, struct device *self, void *opaque)
235 {
236 struct mainbus_attach_args *ma;
237 struct crmfb_softc *sc;
238 struct rasops_info *ri;
239 struct wsemuldisplaydev_attach_args aa;
240 uint32_t d, h;
241 uint16_t *p;
242 unsigned long v;
243 long defattr;
244 const char *consdev;
245 int rv, i;
246
247 sc = (struct crmfb_softc *)self;
248 ma = (struct mainbus_attach_args *)opaque;
249
250 sc->sc_iot = SGIMIPS_BUS_SPACE_CRIME;
251 sc->sc_dmat = &sgimips_default_bus_dma_tag;
252 sc->sc_wsmode = WSDISPLAYIO_MODE_EMUL;
253
254 aprint_normal(": SGI CRIME Graphics Display Engine\n");
255 rv = bus_space_map(sc->sc_iot, ma->ma_addr, 0 /* XXX */,
256 BUS_SPACE_MAP_LINEAR, &sc->sc_ioh);
257 if (rv)
258 panic("crmfb_attach: can't map I/O space");
259
260 rv = bus_space_map(SGIMIPS_BUS_SPACE_CRIME, 0x15000000, 0x5000, 0,
261 &sc->sc_reh);
262 if (rv)
263 panic("%s: unable to map rendering engine registers\n",
264 __func__);
265
266 /* determine mode configured by firmware */
267 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_VT_VCMAP);
268 sc->sc_width = (d >> CRMFB_VT_VCMAP_ON_SHIFT) & 0xfff;
269 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_VT_HCMAP);
270 sc->sc_height = (d >> CRMFB_VT_HCMAP_ON_SHIFT) & 0xfff;
271 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_FRM_TILESIZE);
272 h = (d >> CRMFB_FRM_TILESIZE_DEPTH_SHIFT) & 0x3;
273 if (h == 0)
274 sc->sc_depth = 8;
275 else if (h == 1)
276 sc->sc_depth = 16;
277 else
278 sc->sc_depth = 32;
279
280 if (sc->sc_width == 0 || sc->sc_height == 0) {
281 printf("%s: device unusable if not setup by firmware\n",
282 sc->sc_dev.dv_xname);
283 bus_space_unmap(sc->sc_iot, sc->sc_ioh, 0 /* XXX */);
284 return;
285 }
286
287 printf("%s: initial resolution %dx%d %d bpp\n",
288 sc->sc_dev.dv_xname, sc->sc_width, sc->sc_height, sc->sc_depth);
289
290 #if 0
291 /* Changing the colour depth is easy... */
292 sc->sc_depth = 32;
293 printf("%s: using resolution %dx%d %d bpp\n",
294 sc->sc_dev.dv_xname, sc->sc_width, sc->sc_height, sc->sc_depth);
295 #endif
296
297 sc->sc_fbsize = sc->sc_width * sc->sc_height * sc->sc_depth / 8;
298 sc->sc_fbsize = (sc->sc_fbsize / CRMFB_TILESIZE) * CRMFB_TILESIZE;
299
300 sc->sc_dmai.size = 128 * sizeof(uint16_t);
301 rv = bus_dmamem_alloc(sc->sc_dmat, sc->sc_dmai.size, 65536, 0,
302 sc->sc_dmai.segs,
303 sizeof(sc->sc_dmai.segs) / sizeof(sc->sc_dmai.segs[0]),
304 &sc->sc_dmai.nsegs, BUS_DMA_NOWAIT);
305 if (rv)
306 panic("crmfb_attach: can't allocate DMA memory");
307 rv = bus_dmamem_map(sc->sc_dmat, sc->sc_dmai.segs, sc->sc_dmai.nsegs,
308 sc->sc_dmai.size, &sc->sc_dmai.addr,
309 BUS_DMA_NOWAIT);
310 if (rv)
311 panic("crmfb_attach: can't map DMA memory");
312 rv = bus_dmamap_create(sc->sc_dmat, sc->sc_dmai.size, 1,
313 sc->sc_dmai.size, 0, BUS_DMA_NOWAIT, &sc->sc_dmai.map);
314 if (rv)
315 panic("crmfb_attach: can't create DMA map");
316 rv = bus_dmamap_load(sc->sc_dmat, sc->sc_dmai.map, sc->sc_dmai.addr,
317 sc->sc_dmai.size, NULL, BUS_DMA_NOWAIT);
318 if (rv)
319 panic("crmfb_attach: can't load DMA map");
320
321 sc->sc_dma.size = sc->sc_fbsize;
322 rv = bus_dmamem_alloc(sc->sc_dmat, sc->sc_dma.size, 65536, 0,
323 sc->sc_dma.segs,
324 sizeof(sc->sc_dma.segs) / sizeof(sc->sc_dma.segs[0]),
325 &sc->sc_dma.nsegs, BUS_DMA_NOWAIT);
326 if (rv)
327 panic("crmfb_attach: can't allocate DMA memory");
328 rv = bus_dmamem_map(sc->sc_dmat, sc->sc_dma.segs, sc->sc_dma.nsegs,
329 sc->sc_dma.size, &sc->sc_dma.addr,
330 BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
331 if (rv)
332 panic("crmfb_attach: can't map DMA memory");
333 rv = bus_dmamap_create(sc->sc_dmat, sc->sc_dma.size, 1,
334 sc->sc_dma.size, 0, BUS_DMA_NOWAIT, &sc->sc_dma.map);
335 if (rv)
336 panic("crmfb_attach: can't create DMA map");
337 rv = bus_dmamap_load(sc->sc_dmat, sc->sc_dma.map, sc->sc_dma.addr,
338 sc->sc_dma.size, NULL, BUS_DMA_NOWAIT);
339 if (rv)
340 panic("crmfb_attach: can't load DMA map");
341
342 p = KERNADDR(sc->sc_dmai);
343 v = (unsigned long)DMAADDR(sc->sc_dma);
344 for (i = 0; i < (sc->sc_fbsize >> 16); i++) {
345 p[i] = ((uint32_t)v >> 16) + i;
346 }
347
348 memset(KERNADDR(sc->sc_dma), 0x00, sc->sc_fbsize);
349
350 printf("%s: allocated %d byte fb @ %p (%p)\n", sc->sc_dev.dv_xname,
351 sc->sc_fbsize, KERNADDR(sc->sc_dmai), KERNADDR(sc->sc_dma));
352
353 #ifdef CRMFB_SHADOWFB
354 /* setup shadow framebuffer */
355 sc->sc_shadowfb = malloc(sc->sc_fbsize, M_DEVBUF, M_NOWAIT | M_ZERO);
356 if (sc->sc_shadowfb == NULL)
357 aprint_error("%s: WARNING: couldn't allocate shadow fb\n",
358 sc->sc_dev.dv_xname);
359 #endif
360
361 ri = &crmfb_console_screen.scr_ri;
362 memset(ri, 0, sizeof(struct rasops_info));
363
364 vcons_init(&sc->sc_vd, sc, &crmfb_defaultscreen, &crmfb_accessops);
365 sc->sc_vd.init_screen = crmfb_init_screen;
366 crmfb_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC;
367 vcons_init_screen(&sc->sc_vd, &crmfb_console_screen, 1, &defattr);
368
369 crmfb_defaultscreen.ncols = ri->ri_cols;
370 crmfb_defaultscreen.nrows = ri->ri_rows;
371 crmfb_defaultscreen.textops = &ri->ri_ops;
372 crmfb_defaultscreen.capabilities = ri->ri_caps;
373 crmfb_defaultscreen.modecookie = NULL;
374
375 /* disable DMA */
376 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_OVR_CONTROL);
377 d &= ~(1 << CRMFB_OVR_CONTROL_DMAEN_SHIFT);
378 bus_space_write_4(sc->sc_iot, sc->sc_ioh, CRMFB_OVR_CONTROL, d);
379 DELAY(10000);
380 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_FRM_CONTROL);
381 d &= ~(1 << CRMFB_FRM_CONTROL_DMAEN_SHIFT);
382 bus_space_write_4(sc->sc_iot, sc->sc_ioh, CRMFB_FRM_CONTROL, d);
383 DELAY(10000);
384 bus_space_write_4(sc->sc_iot, sc->sc_ioh, CRMFB_DID_CONTROL, 0);
385 DELAY(10000);
386
387 /* ensure that CRM starts drawing at the top left of the screen
388 * when we re-enable DMA later
389 */
390 d = (1 << CRMFB_VT_XY_FREEZE_SHIFT);
391 bus_space_write_4(sc->sc_iot, sc->sc_ioh, CRMFB_VT_XY, d);
392 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_DOTCLOCK);
393 d &= ~(1 << CRMFB_DOTCLOCK_CLKRUN_SHIFT);
394 bus_space_write_4(sc->sc_iot, sc->sc_ioh, CRMFB_DOTCLOCK, d);
395
396 /* reset FIFO */
397 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_FRM_TILESIZE);
398 d |= (1 << CRMFB_FRM_TILESIZE_FIFOR_SHIFT);
399 bus_space_write_4(sc->sc_iot, sc->sc_ioh, CRMFB_FRM_TILESIZE, d);
400 d &= ~(1 << CRMFB_FRM_TILESIZE_FIFOR_SHIFT);
401 bus_space_write_4(sc->sc_iot, sc->sc_ioh, CRMFB_FRM_TILESIZE, d);
402
403 /* setup colour mode */
404 switch (sc->sc_depth) {
405 case 8:
406 h = CRMFB_MODE_TYP_I8;
407 break;
408 case 16:
409 h = CRMFB_MODE_TYP_ARGB5;
410 break;
411 case 32:
412 h = CRMFB_MODE_TYP_RGB8;
413 break;
414 default:
415 panic("Unsupported depth");
416 }
417 d = h << CRMFB_MODE_TYP_SHIFT;
418 d |= CRMFB_MODE_BUF_BOTH << CRMFB_MODE_BUF_SHIFT;
419 for (i = 0; i < (32 * 4); i += 4)
420 bus_space_write_4(sc->sc_iot, sc->sc_ioh, CRMFB_MODE + i, d);
421
422 /* setup tile pointer, but don't turn on DMA yet! */
423 h = DMAADDR(sc->sc_dmai);
424 d = (h >> 9) << CRMFB_FRM_CONTROL_TILEPTR_SHIFT;
425 bus_space_write_4(sc->sc_iot, sc->sc_ioh, CRMFB_FRM_CONTROL, d);
426
427 /* init framebuffer width and pixel size */
428 d = (1 << CRMFB_FRM_TILESIZE_WIDTH_SHIFT);
429 switch (sc->sc_depth) {
430 case 8:
431 h = CRMFB_FRM_TILESIZE_DEPTH_8;
432 break;
433 case 16:
434 h = CRMFB_FRM_TILESIZE_DEPTH_16;
435 break;
436 case 32:
437 h = CRMFB_FRM_TILESIZE_DEPTH_32;
438 break;
439 default:
440 panic("Unsupported depth");
441 }
442 d |= (h << CRMFB_FRM_TILESIZE_DEPTH_SHIFT);
443 bus_space_write_4(sc->sc_iot, sc->sc_ioh, CRMFB_FRM_TILESIZE, d);
444
445 /* init framebuffer height, we use the trick that the Linux
446 * driver uses to fool the CRM out of tiled mode and into
447 * linear mode
448 */
449 h = sc->sc_width * sc->sc_height / (512 / (sc->sc_depth / 8));
450 d = h << CRMFB_FRM_PIXSIZE_HEIGHT_SHIFT;
451 bus_space_write_4(sc->sc_iot, sc->sc_ioh, CRMFB_FRM_PIXSIZE, d);
452
453 /* turn off firmware overlay and hardware cursor */
454 bus_space_write_4(sc->sc_iot, sc->sc_ioh, CRMFB_OVR_WIDTH_TILE, 0);
455 bus_space_write_4(sc->sc_iot, sc->sc_ioh, CRMFB_CURSOR_CONTROL, 0);
456
457 /* enable drawing again */
458 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_DOTCLOCK);
459 d |= (1 << CRMFB_DOTCLOCK_CLKRUN_SHIFT);
460 bus_space_write_4(sc->sc_iot, sc->sc_ioh, CRMFB_DOTCLOCK, d);
461 bus_space_write_4(sc->sc_iot, sc->sc_ioh, CRMFB_VT_XY, 0);
462
463 /* turn on DMA for the framebuffer */
464 d = bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_FRM_CONTROL);
465 d |= (1 << CRMFB_FRM_CONTROL_DMAEN_SHIFT);
466 bus_space_write_4(sc->sc_iot, sc->sc_ioh, CRMFB_FRM_CONTROL, d);
467
468 for (i = 0; i < 256; i++) {
469 crmfb_set_palette(sc, i, rasops_cmap[(i * 3) + 2],
470 rasops_cmap[(i * 3) + 1], rasops_cmap[(i * 3) + 0]);
471 sc->sc_cmap_red[i] = rasops_cmap[(i * 3) + 2];
472 sc->sc_cmap_green[i] = rasops_cmap[(i * 3) + 1];
473 sc->sc_cmap_blue[i] = rasops_cmap[(i * 3) + 0];
474 }
475
476 consdev = ARCBIOS->GetEnvironmentVariable("ConsoleOut");
477 if (consdev != NULL && strcmp(consdev, "video()") == 0) {
478 wsdisplay_cnattach(&crmfb_defaultscreen, ri, 0, 0, defattr);
479 aa.console = 1;
480 } else
481 aa.console = 0;
482 aa.scrdata = &crmfb_screenlist;
483 aa.accessops = &crmfb_accessops;
484 aa.accesscookie = &sc->sc_vd;
485
486 config_found(self, &aa, wsemuldisplaydevprint);
487
488 /* fill in RE TLB A */
489 v = (unsigned long)DMAADDR(sc->sc_dma);
490 for (i = 0; i < (sc->sc_fbsize >> 16); i++) {
491 bus_space_write_8(sc->sc_iot, sc->sc_reh,
492 CRIME_RE_TLB_A + (i << 3), (uint64_t)v + (i << 16));
493 }
494
495 sc->sc_cur_x = 0;
496 sc->sc_cur_y = 0;
497 sc->sc_hot_x = 0;
498 sc->sc_hot_y = 0;
499
500 return;
501 }
502
503 int
504 crmfb_probe(void)
505 {
506
507 if (mach_type != MACH_SGI_IP32)
508 return 0;
509
510 return 1;
511 }
512
513 static int
514 crmfb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
515 {
516 struct vcons_data *vd;
517 struct crmfb_softc *sc;
518 struct vcons_screen *ms;
519 struct wsdisplay_fbinfo *wdf;
520 int nmode;
521
522 vd = (struct vcons_data *)v;
523 sc = (struct crmfb_softc *)vd->cookie;
524 ms = (struct vcons_screen *)vd->active;
525
526 switch (cmd) {
527 case WSDISPLAYIO_GTYPE:
528 /* not really, but who cares? */
529 *(u_int *)data = WSDISPLAY_TYPE_NEWPORT;
530 return 0;
531 case WSDISPLAYIO_GINFO:
532 if (vd->active != NULL) {
533 wdf = (void *)data;
534 wdf->height = sc->sc_height;
535 wdf->width = sc->sc_width;
536 wdf->depth = sc->sc_depth;
537 wdf->cmsize = 256;
538 return 0;
539 } else
540 return ENODEV;
541 case WSDISPLAYIO_GETCMAP:
542 if (sc->sc_depth == 8)
543 return crmfb_getcmap(sc, (struct wsdisplay_cmap *)data);
544 else
545 return EINVAL;
546 case WSDISPLAYIO_PUTCMAP:
547 if (sc->sc_depth == 8)
548 return crmfb_putcmap(sc, (struct wsdisplay_cmap *)data);
549 else
550 return EINVAL;
551 case WSDISPLAYIO_LINEBYTES:
552 *(u_int *)data = sc->sc_width * sc->sc_depth / 8;
553 return 0;
554 case WSDISPLAYIO_SMODE:
555 nmode = *(int *)data;
556 if (nmode != sc->sc_wsmode) {
557 sc->sc_wsmode = nmode;
558 if (nmode == WSDISPLAYIO_MODE_EMUL)
559 vcons_redraw_screen(vd->active);
560 }
561 return 0;
562 case WSDISPLAYIO_SVIDEO:
563 case WSDISPLAYIO_GVIDEO:
564 return ENODEV; /* not supported yet */
565
566 case WSDISPLAYIO_GCURPOS:
567 {
568 struct wsdisplay_curpos *pos;
569
570 pos = (struct wsdisplay_curpos *)data;
571 pos->x = sc->sc_cur_x;
572 pos->y = sc->sc_cur_y;
573 }
574 return 0;
575 case WSDISPLAYIO_SCURPOS:
576 {
577 struct wsdisplay_curpos *pos;
578
579 pos = (struct wsdisplay_curpos *)data;
580 crmfb_set_curpos(sc, pos->x, pos->y);
581 }
582 return 0;
583 case WSDISPLAYIO_GCURMAX:
584 {
585 struct wsdisplay_curpos *pos;
586
587 pos = (struct wsdisplay_curpos *)data;
588 pos->x = 32;
589 pos->y = 32;
590 }
591 return 0;
592 case WSDISPLAYIO_GCURSOR:
593 {
594 struct wsdisplay_cursor *cu;
595
596 cu = (struct wsdisplay_cursor *)data;
597 return crmfb_gcursor(sc, cu);
598 }
599 case WSDISPLAYIO_SCURSOR:
600 {
601 struct wsdisplay_cursor *cu;
602
603 cu = (struct wsdisplay_cursor *)data;
604 return crmfb_scursor(sc, cu);
605 }
606 }
607 return EPASSTHROUGH;
608 }
609
610 static paddr_t
611 crmfb_mmap(void *v, void *vs, off_t offset, int prot)
612 {
613 struct vcons_data *vd;
614 struct crmfb_softc *sc;
615 paddr_t pa;
616
617 vd = (struct vcons_data *)v;
618 sc = (struct crmfb_softc *)vd->cookie;
619
620 if (offset >= 0 && offset < sc->sc_fbsize) {
621 pa = bus_dmamem_mmap(sc->sc_dmat, sc->sc_dma.segs,
622 sc->sc_dma.nsegs, offset, prot,
623 BUS_DMA_WAITOK | BUS_DMA_COHERENT);
624 return pa;
625 }
626
627 return -1;
628 }
629
630 static void
631 crmfb_init_screen(void *c, struct vcons_screen *scr, int existing,
632 long *defattr)
633 {
634 struct crmfb_softc *sc;
635 struct rasops_info *ri;
636
637 sc = (struct crmfb_softc *)c;
638 ri = &scr->scr_ri;
639
640 ri->ri_flg = RI_CENTER;
641 ri->ri_depth = sc->sc_depth;
642 ri->ri_width = sc->sc_width;
643 ri->ri_height = sc->sc_height;
644 ri->ri_stride = ri->ri_width * (ri->ri_depth / 8);
645
646 switch (ri->ri_depth) {
647 case 16:
648 ri->ri_rnum = ri->ri_gnum = ri->ri_bnum = 5;
649 ri->ri_rpos = 10;
650 ri->ri_gpos = 5;
651 ri->ri_bpos = 0;
652 break;
653 case 32:
654 ri->ri_rnum = ri->ri_gnum = ri->ri_bnum = 8;
655 ri->ri_rpos = 8;
656 ri->ri_gpos = 16;
657 ri->ri_bpos = 24;
658 break;
659 }
660
661 if (sc->sc_shadowfb == NULL)
662 ri->ri_bits = KERNADDR(sc->sc_dma);
663 else {
664 ri->ri_bits = sc->sc_shadowfb;
665 ri->ri_hwbits = KERNADDR(sc->sc_dma);
666 }
667
668 if (existing)
669 ri->ri_flg |= RI_CLEAR;
670
671 rasops_init(ri, ri->ri_height / 16, ri->ri_width / 8);
672 ri->ri_caps = WSSCREEN_WSCOLORS;
673 rasops_reconfig(ri, ri->ri_height / ri->ri_font->fontheight,
674 ri->ri_width / ri->ri_font->fontwidth);
675 ri->ri_hw = scr;
676
677 return;
678 }
679
680 static int
681 crmfb_putcmap(struct crmfb_softc *sc, struct wsdisplay_cmap *cm)
682 {
683 u_int idx, cnt;
684 u_char r[256], g[256], b[256];
685 u_char *rp, *gp, *bp;
686 int rv, i;
687
688 idx = cm->index;
689 cnt = cm->count;
690
691 if (idx >= 255 || cnt > 256 || idx + cnt > 256)
692 return EINVAL;
693
694 rv = copyin(cm->red, &r[idx], cnt);
695 if (rv)
696 return rv;
697 rv = copyin(cm->green, &g[idx], cnt);
698 if (rv)
699 return rv;
700 rv = copyin(cm->blue, &b[idx], cnt);
701 if (rv)
702 return rv;
703
704 memcpy(&sc->sc_cmap_red[idx], &r[idx], cnt);
705 memcpy(&sc->sc_cmap_green[idx], &g[idx], cnt);
706 memcpy(&sc->sc_cmap_blue[idx], &b[idx], cnt);
707
708 rp = &sc->sc_cmap_red[idx];
709 gp = &sc->sc_cmap_green[idx];
710 bp = &sc->sc_cmap_blue[idx];
711
712 for (i = 0; i < cnt; i++) {
713 crmfb_set_palette(sc, idx, *rp, *gp, *bp);
714 idx++;
715 rp++, gp++, bp++;
716 }
717
718 return 0;
719 }
720
721 static int
722 crmfb_getcmap(struct crmfb_softc *sc, struct wsdisplay_cmap *cm)
723 {
724 u_int idx, cnt;
725 int rv;
726
727 idx = cm->index;
728 cnt = cm->count;
729
730 if (idx >= 255 || cnt > 256 || idx + cnt > 256)
731 return EINVAL;
732
733 rv = copyout(&sc->sc_cmap_red[idx], cm->red, cnt);
734 if (rv)
735 return rv;
736 rv = copyout(&sc->sc_cmap_green[idx], cm->green, cnt);
737 if (rv)
738 return rv;
739 rv = copyout(&sc->sc_cmap_blue[idx], cm->blue, cnt);
740 if (rv)
741 return rv;
742
743 return 0;
744 }
745
746 static void
747 crmfb_set_palette(struct crmfb_softc *sc, int reg, uint8_t r, uint8_t g,
748 uint8_t b)
749 {
750 uint32_t val;
751
752 if (reg > 255 || sc->sc_depth != 8)
753 return;
754
755 while (bus_space_read_4(sc->sc_iot, sc->sc_ioh, CRMFB_CMAP_FIFO) >= 63)
756 DELAY(10);
757
758 val = (r << 24) | (g << 16) | (b << 8);
759 bus_space_write_4(sc->sc_iot, sc->sc_ioh, CRMFB_CMAP + (reg * 4), val);
760
761 return;
762 }
763
764 static int
765 crmfb_set_curpos(struct crmfb_softc *sc, int x, int y)
766 {
767 uint32_t val;
768
769 sc->sc_cur_x = x;
770 sc->sc_cur_y = y;
771
772 val = ((x - sc->sc_hot_x) & 0xffff) | ((y - sc->sc_hot_y) << 16);
773 bus_space_write_4(sc->sc_iot, sc->sc_ioh, CRMFB_CURSOR_POS, val);
774
775 return 0;
776 }
777
778 static int
779 crmfb_gcursor(struct crmfb_softc *sc, struct wsdisplay_cursor *cur)
780 {
781 /* do nothing for now */
782 return 0;
783 }
784
785 static int
786 crmfb_scursor(struct crmfb_softc *sc, struct wsdisplay_cursor *cur)
787 {
788 if (cur->which & WSDISPLAY_CURSOR_DOCUR) {
789
790 bus_space_write_4(sc->sc_iot, sc->sc_ioh, CRMFB_CURSOR_CONTROL,
791 cur->enable ? 1 : 0);
792 }
793 if (cur->which & WSDISPLAY_CURSOR_DOHOT) {
794
795 sc->sc_hot_x = cur->hot.x;
796 sc->sc_hot_y = cur->hot.y;
797 }
798 if (cur->which & WSDISPLAY_CURSOR_DOPOS) {
799
800 crmfb_set_curpos(sc, cur->pos.x, cur->pos.y);
801 }
802 if (cur->which & WSDISPLAY_CURSOR_DOCMAP) {
803 int i;
804 uint32_t val;
805
806 for (i = 0; i < cur->cmap.count; i++) {
807 val = (cur->cmap.red[i] << 24) |
808 (cur->cmap.green[i] << 16) |
809 (cur->cmap.blue[i] << 8);
810 bus_space_write_4(sc->sc_iot, sc->sc_ioh,
811 CRMFB_CURSOR_CMAP0 + ((i + cur->cmap.index) << 2),
812 val);
813 }
814 }
815 if (cur->which & WSDISPLAY_CURSOR_DOSHAPE) {
816
817 int i, j, cnt = 0;
818 uint32_t latch = 0, omask;
819 uint8_t imask;
820 for (i = 0; i < 64; i++) {
821 omask = 0x80000000;
822 imask = 0x01;
823 cur->image[cnt] &= cur->mask[cnt];
824 for (j = 0; j < 8; j++) {
825 if (cur->image[cnt] & imask)
826 latch |= omask;
827 omask >>= 1;
828 if (cur->mask[cnt] & imask)
829 latch |= omask;
830 omask >>= 1;
831 imask <<= 1;
832 }
833 cnt++;
834 imask = 0x01;
835 cur->image[cnt] &= cur->mask[cnt];
836 for (j = 0; j < 8; j++) {
837 if (cur->image[cnt] & imask)
838 latch |= omask;
839 omask >>= 1;
840 if (cur->mask[cnt] & imask)
841 latch |= omask;
842 omask >>= 1;
843 imask <<= 1;
844 }
845 cnt++;
846 bus_space_write_4(sc->sc_iot, sc->sc_ioh,
847 CRMFB_CURSOR_BITMAP + (i << 2), latch);
848 latch = 0;
849 }
850 }
851 return 0;
852 }
853