sfb.c revision 1.4 1 /* $NetBSD: sfb.c,v 1.4 1998/11/14 16:31:34 drochner Exp $ */
2
3 /*
4 * Copyright (c) 1998 Tohru Nishimura. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by Tohru Nishimura
17 * for the NetBSD Project.
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
34
35 __KERNEL_RCSID(0, "$NetBSD: sfb.c,v 1.4 1998/11/14 16:31:34 drochner Exp $");
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/device.h>
41 #include <sys/malloc.h>
42 #include <sys/buf.h>
43 #include <sys/ioctl.h>
44 #include <vm/vm.h>
45
46 #include <machine/bus.h>
47 #include <machine/intr.h>
48
49 #include <dev/rcons/raster.h>
50 #include <dev/wscons/wsconsio.h>
51 #include <dev/wscons/wscons_raster.h>
52 #include <dev/wscons/wsdisplayvar.h>
53 #include <machine/autoconf.h>
54
55 #include <dev/tc/tcvar.h>
56 #include <dev/ic/bt459reg.h>
57 #include <dev/tc/sfbreg.h>
58
59 #include "opt_uvm.h"
60 #if defined(UVM)
61 #include <uvm/uvm_extern.h>
62 #define useracc uvm_useracc
63 #endif
64
65 /* XXX BUS'IFYING XXX */
66
67 #if defined(__pmax__)
68 #define machine_btop(x) mips_btop(x)
69 #define MACHINE_KSEG0_TO_PHYS(x) MIPS_KSEG1_TO_PHYS(x)
70 #endif
71
72 #if defined(__alpha__) || defined(alpha)
73 #define machine_btop(x) alpha_btop(x)
74 #define MACHINE_KSEG0_TO_PHYS(x) ALPHA_K0SEG_TO_PHYS(x)
75 #endif
76
77 /*
78 * N.B., Bt459 registers are 8bit width. Some of TC framebuffers have
79 * obscure register layout such as 2nd and 3rd Bt459 registers are
80 * adjacent each other in a word, i.e.,
81 * struct bt459triplet {
82 * struct {
83 * u_int8_t u0;
84 * u_int8_t u1;
85 * u_int8_t u2;
86 * unsigned :8;
87 * } bt_lo;
88 * ...
89 * Although HX has single Bt459, 32bit R/W can be done w/o any trouble.
90 */
91 struct bt459reg {
92 u_int32_t bt_lo;
93 u_int32_t bt_hi;
94 u_int32_t bt_reg;
95 u_int32_t bt_cmap;
96 };
97
98 /* XXX XXX XXX */
99
100 struct fb_devconfig {
101 vaddr_t dc_vaddr; /* memory space virtual base address */
102 paddr_t dc_paddr; /* memory space physical base address */
103 vsize_t dc_size; /* size of slot memory */
104 int dc_wid; /* width of frame buffer */
105 int dc_ht; /* height of frame buffer */
106 int dc_depth; /* depth, bits per pixel */
107 int dc_rowbytes; /* bytes in a FB scan line */
108 vaddr_t dc_videobase; /* base of flat frame buffer */
109 struct raster dc_raster; /* raster description */
110 struct rcons dc_rcons; /* raster blitter control info */
111 int dc_blanked; /* currently has video disabled */
112 };
113
114 struct hwcmap {
115 #define CMAP_SIZE 256 /* 256 R/G/B entries */
116 u_int8_t r[CMAP_SIZE];
117 u_int8_t g[CMAP_SIZE];
118 u_int8_t b[CMAP_SIZE];
119 };
120
121 struct hwcursor {
122 struct wsdisplay_curpos cc_pos;
123 struct wsdisplay_curpos cc_hot;
124 struct wsdisplay_curpos cc_size;
125 #define CURSOR_MAX_SIZE 64
126 u_int8_t cc_color[6];
127 u_int64_t cc_image[64 + 64];
128 };
129
130 struct sfb_softc {
131 struct device sc_dev;
132 struct fb_devconfig *sc_dc; /* device configuration */
133 struct hwcmap sc_cmap; /* software copy of colormap */
134 struct hwcursor sc_cursor; /* software copy of cursor */
135 int sc_curenb; /* cursor sprite enabled */
136 int sc_changed; /* need update of colormap */
137 #define DATA_ENB_CHANGED 0x01 /* cursor enable changed */
138 #define DATA_CURCMAP_CHANGED 0x02 /* cursor colormap changed */
139 #define DATA_CURSHAPE_CHANGED 0x04 /* cursor size, image, mask changed */
140 #define DATA_CMAP_CHANGED 0x08 /* colormap changed */
141 #define DATA_ALL_CHANGED 0x0f
142 int nscreens;
143 short magic_x, magic_y; /* HX cursor location offset */
144 #define HX_MAGIC_X 368
145 #define HX_MAGIC_Y 38
146 };
147
148 int sfbmatch __P((struct device *, struct cfdata *, void *));
149 void sfbattach __P((struct device *, struct device *, void *));
150
151 struct cfattach sfb_ca = {
152 sizeof(struct sfb_softc), sfbmatch, sfbattach,
153 };
154
155 void sfb_getdevconfig __P((tc_addr_t, struct fb_devconfig *));
156 struct fb_devconfig sfb_console_dc;
157 tc_addr_t sfb_consaddr;
158
159 struct wsdisplay_emulops sfb_emulops = {
160 rcons_cursor, /* could use hardware cursor; punt */
161 rcons_mapchar,
162 rcons_putchar,
163 rcons_copycols,
164 rcons_erasecols,
165 rcons_copyrows,
166 rcons_eraserows,
167 rcons_alloc_attr
168 };
169
170 struct wsscreen_descr sfb_stdscreen = {
171 "std", 0, 0,
172 &sfb_emulops,
173 0, 0,
174 0
175 };
176
177 const struct wsscreen_descr *_sfb_scrlist[] = {
178 &sfb_stdscreen,
179 };
180
181 struct wsscreen_list sfb_screenlist = {
182 sizeof(_sfb_scrlist) / sizeof(struct wsscreen_descr *), _sfb_scrlist
183 };
184
185 int sfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
186 int sfbmmap __P((void *, off_t, int));
187
188 int sfb_alloc_screen __P((void *, const struct wsscreen_descr *,
189 void **, int *, int *, long *));
190 void sfb_free_screen __P((void *, void *));
191 void sfb_show_screen __P((void *, void *));
192 int sfb_load_font __P((void *, void *, int, int, int, void *));
193
194 struct wsdisplay_accessops sfb_accessops = {
195 sfbioctl,
196 sfbmmap,
197 sfb_alloc_screen,
198 sfb_free_screen,
199 sfb_show_screen,
200 sfb_load_font
201 };
202
203 int sfb_cnattach __P((tc_addr_t));
204 int sfbintr __P((void *));
205 void sfbinit __P((struct fb_devconfig *));
206
207 static int get_cmap __P((struct sfb_softc *, struct wsdisplay_cmap *));
208 static int set_cmap __P((struct sfb_softc *, struct wsdisplay_cmap *));
209 static int set_cursor __P((struct sfb_softc *, struct wsdisplay_cursor *));
210 static int get_cursor __P((struct sfb_softc *, struct wsdisplay_cursor *));
211 static void set_curpos __P((struct sfb_softc *, struct wsdisplay_curpos *));
212 static void bt459_set_curpos __P((struct sfb_softc *));
213
214 /* XXX XXX XXX */
215 #define BT459_SELECT(vdac, regno) do { \
216 vdac->bt_lo = (regno) & 0x00ff; \
217 vdac->bt_hi = ((regno)& 0x0f00) >> 8 ; \
218 tc_wmb(); \
219 } while (0)
220 /* XXX XXX XXX */
221
222 /*
223 * Compose 2 bit/pixel cursor image. Bit order will be reversed.
224 * M M M M I I I I M I M I M I M I
225 * [ before ] [ after ]
226 * 3 2 1 0 3 2 1 0 0 0 1 1 2 2 3 3
227 * 7 6 5 4 7 6 5 4 4 4 5 5 6 6 7 7
228 */
229 const static u_int8_t shuffle[256] = {
230 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
231 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55,
232 0x80, 0xc0, 0x90, 0xd0, 0x84, 0xc4, 0x94, 0xd4,
233 0x81, 0xc1, 0x91, 0xd1, 0x85, 0xc5, 0x95, 0xd5,
234 0x20, 0x60, 0x30, 0x70, 0x24, 0x64, 0x34, 0x74,
235 0x21, 0x61, 0x31, 0x71, 0x25, 0x65, 0x35, 0x75,
236 0xa0, 0xe0, 0xb0, 0xf0, 0xa4, 0xe4, 0xb4, 0xf4,
237 0xa1, 0xe1, 0xb1, 0xf1, 0xa5, 0xe5, 0xb5, 0xf5,
238 0x08, 0x48, 0x18, 0x58, 0x0c, 0x4c, 0x1c, 0x5c,
239 0x09, 0x49, 0x19, 0x59, 0x0d, 0x4d, 0x1d, 0x5d,
240 0x88, 0xc8, 0x98, 0xd8, 0x8c, 0xcc, 0x9c, 0xdc,
241 0x89, 0xc9, 0x99, 0xd9, 0x8d, 0xcd, 0x9d, 0xdd,
242 0x28, 0x68, 0x38, 0x78, 0x2c, 0x6c, 0x3c, 0x7c,
243 0x29, 0x69, 0x39, 0x79, 0x2d, 0x6d, 0x3d, 0x7d,
244 0xa8, 0xe8, 0xb8, 0xf8, 0xac, 0xec, 0xbc, 0xfc,
245 0xa9, 0xe9, 0xb9, 0xf9, 0xad, 0xed, 0xbd, 0xfd,
246 0x02, 0x42, 0x12, 0x52, 0x06, 0x46, 0x16, 0x56,
247 0x03, 0x43, 0x13, 0x53, 0x07, 0x47, 0x17, 0x57,
248 0x82, 0xc2, 0x92, 0xd2, 0x86, 0xc6, 0x96, 0xd6,
249 0x83, 0xc3, 0x93, 0xd3, 0x87, 0xc7, 0x97, 0xd7,
250 0x22, 0x62, 0x32, 0x72, 0x26, 0x66, 0x36, 0x76,
251 0x23, 0x63, 0x33, 0x73, 0x27, 0x67, 0x37, 0x77,
252 0xa2, 0xe2, 0xb2, 0xf2, 0xa6, 0xe6, 0xb6, 0xf6,
253 0xa3, 0xe3, 0xb3, 0xf3, 0xa7, 0xe7, 0xb7, 0xf7,
254 0x0a, 0x4a, 0x1a, 0x5a, 0x0e, 0x4e, 0x1e, 0x5e,
255 0x0b, 0x4b, 0x1b, 0x5b, 0x0f, 0x4f, 0x1f, 0x5f,
256 0x8a, 0xca, 0x9a, 0xda, 0x8e, 0xce, 0x9e, 0xde,
257 0x8b, 0xcb, 0x9b, 0xdb, 0x8f, 0xcf, 0x9f, 0xdf,
258 0x2a, 0x6a, 0x3a, 0x7a, 0x2e, 0x6e, 0x3e, 0x7e,
259 0x2b, 0x6b, 0x3b, 0x7b, 0x2f, 0x6f, 0x3f, 0x7f,
260 0xaa, 0xea, 0xba, 0xfa, 0xae, 0xee, 0xbe, 0xfe,
261 0xab, 0xeb, 0xbb, 0xfb, 0xaf, 0xef, 0xbf, 0xff,
262 };
263
264 int
265 sfbmatch(parent, match, aux)
266 struct device *parent;
267 struct cfdata *match;
268 void *aux;
269 {
270 struct tc_attach_args *ta = aux;
271
272 if (strncmp("PMAGB-BA", ta->ta_modname, TC_ROM_LLEN) != 0)
273 return (0);
274
275 return (1);
276 }
277
278 void
279 sfb_getdevconfig(dense_addr, dc)
280 tc_addr_t dense_addr;
281 struct fb_devconfig *dc;
282 {
283 struct raster *rap;
284 struct rcons *rcp;
285 caddr_t sfbasic;
286 int i, hsetup, vsetup, vbase;
287
288 dc->dc_vaddr = dense_addr;
289 dc->dc_paddr = MACHINE_KSEG0_TO_PHYS(dc->dc_vaddr);
290
291 sfbasic = (caddr_t)(dc->dc_vaddr + SFB_ASIC_OFFSET);
292 hsetup = *(u_int32_t *)(sfbasic + SFB_ASIC_VIDEO_HSETUP);
293 vsetup = *(u_int32_t *)(sfbasic + SFB_ASIC_VIDEO_VSETUP);
294 vbase = *(u_int32_t *)(sfbasic + SFB_ASIC_VIDEO_BASE) & 0x1ff;
295
296 dc->dc_wid = (hsetup & 0x1ff) << 2;
297 dc->dc_ht = (vsetup & 0x7ff);
298 dc->dc_depth = 8;
299 dc->dc_rowbytes = dc->dc_wid * (dc->dc_depth / 8);
300 dc->dc_videobase = dc->dc_vaddr + SFB_FB_OFFSET + vbase * 4096;
301 dc->dc_blanked = 0;
302
303 /* initialize colormap and cursor resource */
304 sfbinit(dc);
305
306 /* clear the screen */
307 for (i = 0; i < dc->dc_ht * dc->dc_rowbytes; i += sizeof(u_int32_t))
308 *(u_int32_t *)(dc->dc_videobase + i) = 0x0;
309
310 /* initialize the raster */
311 rap = &dc->dc_raster;
312 rap->width = dc->dc_wid;
313 rap->height = dc->dc_ht;
314 rap->depth = dc->dc_depth;
315 rap->linelongs = dc->dc_rowbytes / sizeof(u_int32_t);
316 rap->pixels = (u_int32_t *)dc->dc_videobase;
317
318 /* initialize the raster console blitter */
319 rcp = &dc->dc_rcons;
320 rcp->rc_sp = rap;
321 rcp->rc_crow = rcp->rc_ccol = -1;
322 rcp->rc_crowp = &rcp->rc_crow;
323 rcp->rc_ccolp = &rcp->rc_ccol;
324 rcons_init(rcp, 34, 80);
325
326 sfb_stdscreen.nrows = dc->dc_rcons.rc_maxrow;
327 sfb_stdscreen.ncols = dc->dc_rcons.rc_maxcol;
328
329 }
330
331 void
332 sfbattach(parent, self, aux)
333 struct device *parent, *self;
334 void *aux;
335 {
336 struct sfb_softc *sc = (struct sfb_softc *)self;
337 struct tc_attach_args *ta = aux;
338 struct wsemuldisplaydev_attach_args waa;
339 struct hwcmap *cm;
340 caddr_t sfbasic;
341 int console, i;
342
343 console = (ta->ta_addr == sfb_consaddr);
344 if (console) {
345 sc->sc_dc = &sfb_console_dc;
346 sc->nscreens = 1;
347 }
348 else {
349 sc->sc_dc = (struct fb_devconfig *)
350 malloc(sizeof(struct fb_devconfig), M_DEVBUF, M_WAITOK);
351 sfb_getdevconfig(ta->ta_addr, sc->sc_dc);
352 }
353 printf(": %d x %d, %dbpp\n", sc->sc_dc->dc_wid, sc->sc_dc->dc_ht,
354 sc->sc_dc->dc_depth);
355
356 cm = &sc->sc_cmap;
357 cm->r[0] = cm->g[0] = cm->b[0] = 0;
358 for (i = 1; i < CMAP_SIZE; i++) {
359 cm->r[i] = cm->g[i] = cm->b[i] = 0xff;
360 }
361 sc->magic_x = HX_MAGIC_X; sc->magic_y = HX_MAGIC_Y;
362
363 tc_intr_establish(parent, ta->ta_cookie, TC_IPL_TTY, sfbintr, sc);
364
365 sfbasic = (caddr_t)(sc->sc_dc->dc_vaddr + SFB_ASIC_OFFSET);
366 *(u_int32_t *)(sfbasic + SFB_ASIC_CLEAR_INTR) = 0;
367 *(u_int32_t *)(sfbasic + SFB_ASIC_ENABLE_INTR) = 1;
368
369 waa.console = console;
370 waa.scrdata = &sfb_screenlist;
371 waa.accessops = &sfb_accessops;
372 waa.accesscookie = sc;
373
374 config_found(self, &waa, wsemuldisplaydevprint);
375 }
376
377 int
378 sfbioctl(v, cmd, data, flag, p)
379 void *v;
380 u_long cmd;
381 caddr_t data;
382 int flag;
383 struct proc *p;
384 {
385 struct sfb_softc *sc = v;
386 struct fb_devconfig *dc = sc->sc_dc;
387 int turnoff;
388
389 switch (cmd) {
390 case WSDISPLAYIO_GTYPE:
391 *(u_int *)data = WSDISPLAY_TYPE_SFB;
392 return (0);
393
394 case WSDISPLAYIO_GINFO:
395 #define wsd_fbip ((struct wsdisplay_fbinfo *)data)
396 wsd_fbip->height = sc->sc_dc->dc_ht;
397 wsd_fbip->width = sc->sc_dc->dc_wid;
398 wsd_fbip->depth = sc->sc_dc->dc_depth;
399 wsd_fbip->cmsize = CMAP_SIZE;
400 #undef fbt
401 return (0);
402
403 case WSDISPLAYIO_GETCMAP:
404 return get_cmap(sc, (struct wsdisplay_cmap *)data);
405
406 case WSDISPLAYIO_PUTCMAP:
407 return set_cmap(sc, (struct wsdisplay_cmap *)data);
408
409 case WSDISPLAYIO_SVIDEO:
410 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
411 if ((dc->dc_blanked == 0) ^ turnoff) {
412 dc->dc_blanked = turnoff;
413 /* XXX later XXX */
414 }
415 return (0);
416
417 case WSDISPLAYIO_GVIDEO:
418 *(u_int *)data = dc->dc_blanked ?
419 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
420 return (0);
421
422 case WSDISPLAYIO_GCURPOS:
423 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
424 return (0);
425
426 case WSDISPLAYIO_SCURPOS:
427 set_curpos(sc, (struct wsdisplay_curpos *)data);
428 bt459_set_curpos(sc);
429 return (0);
430
431 case WSDISPLAYIO_GCURMAX:
432 ((struct wsdisplay_curpos *)data)->x =
433 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
434 return (0);
435
436 case WSDISPLAYIO_GCURSOR:
437 return get_cursor(sc, (struct wsdisplay_cursor *)data);
438
439 case WSDISPLAYIO_SCURSOR:
440 return set_cursor(sc, (struct wsdisplay_cursor *)data);
441 }
442 return ENOTTY;
443 }
444
445 int
446 sfbmmap(v, offset, prot)
447 void *v;
448 off_t offset;
449 int prot;
450 {
451 struct sfb_softc *sc = v;
452
453 if (offset > 0x1000000) /* XXX */
454 return (-1);
455 return machine_btop(sc->sc_dc->dc_paddr + offset);
456 }
457
458 int
459 sfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
460 void *v;
461 const struct wsscreen_descr *type;
462 void **cookiep;
463 int *curxp, *curyp;
464 long *attrp;
465 {
466 struct sfb_softc *sc = v;
467 long defattr;
468
469 if (sc->nscreens > 0)
470 return (ENOMEM);
471
472 *cookiep = &sc->sc_dc->dc_rcons; /* one and only for now */
473 *curxp = 0;
474 *curyp = 0;
475 rcons_alloc_attr(&sc->sc_dc->dc_rcons, 0, 0, 0, &defattr);
476 *attrp = defattr;
477 sc->nscreens++;
478 return (0);
479 }
480
481 void
482 sfb_free_screen(v, cookie)
483 void *v;
484 void *cookie;
485 {
486 struct sfb_softc *sc = v;
487
488 if (sc->sc_dc == &sfb_console_dc)
489 panic("sfb_free_screen: console");
490
491 sc->nscreens--;
492 }
493
494 void
495 sfb_show_screen(v, cookie)
496 void *v;
497 void *cookie;
498 {
499 }
500
501 int
502 sfb_load_font(v, cookie, first, num, stride, data)
503 void *v;
504 void *cookie;
505 int first, num, stride;
506 void *data;
507 {
508 return (EINVAL);
509 }
510
511 int
512 sfb_cnattach(addr)
513 tc_addr_t addr;
514 {
515 struct fb_devconfig *dcp = &sfb_console_dc;
516 long defattr;
517
518 sfb_getdevconfig(addr, dcp);
519
520 rcons_alloc_attr(&dcp->dc_rcons, 0, 0, 0, &defattr);
521
522 wsdisplay_cnattach(&sfb_stdscreen, &dcp->dc_rcons,
523 0, 0, defattr);
524 sfb_consaddr = addr;
525 return(0);
526 }
527
528 int
529 sfbintr(arg)
530 void *arg;
531 {
532 struct sfb_softc *sc = arg;
533 caddr_t sfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
534 caddr_t sfbasic = sfbbase + SFB_ASIC_OFFSET;
535 struct bt459reg *vdac;
536 int v;
537
538 *(u_int32_t *)(sfbasic + SFB_ASIC_CLEAR_INTR) = 0;
539 /* *(u_int32_t *)(sfbasic + SFB_ASIC_ENABLE_INTR) = 1; */
540
541 if (sc->sc_changed == 0)
542 return (1);
543
544 vdac = (void *)(sfbbase + SFB_RAMDAC_OFFSET);
545 v = sc->sc_changed;
546 sc->sc_changed = 0;
547
548 if (v & DATA_ENB_CHANGED) {
549 BT459_SELECT(vdac, BT459_REG_CCR);
550 vdac->bt_reg = (sc->sc_curenb) ? 0xc0 : 0x00; tc_wmb();
551 }
552 if (v & DATA_CURCMAP_CHANGED) {
553 u_int8_t *cp = sc->sc_cursor.cc_color;
554
555 BT459_SELECT(vdac, BT459_REG_CCOLOR_2);
556 vdac->bt_reg = cp[1]; tc_wmb();
557 vdac->bt_reg = cp[3]; tc_wmb();
558 vdac->bt_reg = cp[5]; tc_wmb();
559
560 vdac->bt_reg = cp[0]; tc_wmb();
561 vdac->bt_reg = cp[2]; tc_wmb();
562 vdac->bt_reg = cp[4]; tc_wmb();
563 }
564 if (v & DATA_CURSHAPE_CHANGED) {
565 u_int8_t *ip, *mp, img, msk;
566 u_int8_t u;
567 int bcnt;
568
569 ip = (u_int8_t *)sc->sc_cursor.cc_image;
570 mp = (u_int8_t *)(sc->sc_cursor.cc_image + CURSOR_MAX_SIZE);
571
572 bcnt = 0;
573 BT459_SELECT(vdac, BT459_REG_CRAM_BASE+0);
574 /* 64 pixel scan line is consisted with 16 byte cursor ram */
575 while (bcnt < sc->sc_cursor.cc_size.y * 16) {
576 /* pad right half 32 pixel when smaller than 33 */
577 if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
578 vdac->bt_reg = 0; tc_wmb();
579 vdac->bt_reg = 0; tc_wmb();
580 }
581 else {
582 img = *ip++;
583 msk = *mp++;
584 img &= msk; /* cookie off image */
585 u = (msk & 0x0f) << 4 | (img & 0x0f);
586 vdac->bt_reg = shuffle[u]; tc_wmb();
587 u = (msk & 0xf0) | (img & 0xf0) >> 4;
588 vdac->bt_reg = shuffle[u]; tc_wmb();
589 }
590 bcnt += 2;
591 }
592 /* pad unoccupied scan lines */
593 while (bcnt < CURSOR_MAX_SIZE * 16) {
594 vdac->bt_reg = 0; tc_wmb();
595 vdac->bt_reg = 0; tc_wmb();
596 bcnt += 2;
597 }
598 }
599 if (v & DATA_CMAP_CHANGED) {
600 struct hwcmap *cm = &sc->sc_cmap;
601 int index;
602
603 BT459_SELECT(vdac, 0);
604 for (index = 0; index < CMAP_SIZE; index++) {
605 vdac->bt_cmap = cm->r[index]; tc_wmb();
606 vdac->bt_cmap = cm->g[index]; tc_wmb();
607 vdac->bt_cmap = cm->b[index]; tc_wmb();
608 }
609 }
610 return (1);
611 }
612
613 void
614 sfbinit(dc)
615 struct fb_devconfig *dc;
616 {
617 caddr_t sfbasic = (caddr_t)(dc->dc_vaddr + SFB_ASIC_OFFSET);
618 struct bt459reg *vdac = (void *)(dc->dc_vaddr + SFB_RAMDAC_OFFSET);
619 int i;
620
621 *(u_int32_t *)(sfbasic + SFB_ASIC_MODE) = 0;
622 *(u_int32_t *)(sfbasic + SFB_ASIC_VIDEO_VALID) = 1;
623 *(u_int32_t *)(sfbasic + SFB_ASIC_PLANEMASK) = ~0;
624 *(u_int32_t *)(sfbasic + SFB_ASIC_PIXELMASK) = ~0;
625
626 *(u_int32_t *)(sfbasic + 0x180000) = 0; /* Bt459 reset */
627
628 BT459_SELECT(vdac, BT459_REG_COMMAND_0);
629 vdac->bt_reg = 0x40; /* CMD0 */ tc_wmb();
630 vdac->bt_reg = 0x0; /* CMD1 */ tc_wmb();
631 vdac->bt_reg = 0xc0; /* CMD2 */ tc_wmb();
632 vdac->bt_reg = 0xff; /* PRM */ tc_wmb();
633 vdac->bt_reg = 0; /* 205 */ tc_wmb();
634 vdac->bt_reg = 0x0; /* PBM */ tc_wmb();
635 vdac->bt_reg = 0; /* 207 */ tc_wmb();
636 vdac->bt_reg = 0x0; /* ORM */ tc_wmb();
637 vdac->bt_reg = 0x0; /* OBM */ tc_wmb();
638 vdac->bt_reg = 0x0; /* ILV */ tc_wmb();
639 vdac->bt_reg = 0x0; /* TEST */ tc_wmb();
640
641 BT459_SELECT(vdac, BT459_REG_CCR);
642 vdac->bt_reg = 0x0; tc_wmb();
643 vdac->bt_reg = 0x0; tc_wmb();
644 vdac->bt_reg = 0x0; tc_wmb();
645 vdac->bt_reg = 0x0; tc_wmb();
646 vdac->bt_reg = 0x0; tc_wmb();
647 vdac->bt_reg = 0x0; tc_wmb();
648 vdac->bt_reg = 0x0; tc_wmb();
649 vdac->bt_reg = 0x0; tc_wmb();
650 vdac->bt_reg = 0x0; tc_wmb();
651 vdac->bt_reg = 0x0; tc_wmb();
652 vdac->bt_reg = 0x0; tc_wmb();
653 vdac->bt_reg = 0x0; tc_wmb();
654 vdac->bt_reg = 0x0; tc_wmb();
655
656 /* build sane colormap */
657 BT459_SELECT(vdac, 0);
658 vdac->bt_cmap = 0; tc_wmb();
659 vdac->bt_cmap = 0; tc_wmb();
660 vdac->bt_cmap = 0; tc_wmb();
661 for (i = 1; i < CMAP_SIZE; i++) {
662 vdac->bt_cmap = 0xff; tc_wmb();
663 vdac->bt_cmap = 0xff; tc_wmb();
664 vdac->bt_cmap = 0xff; tc_wmb();
665 }
666
667 /* clear out cursor image */
668 BT459_SELECT(vdac, BT459_REG_CRAM_BASE);
669 for (i = 0; i < 1024; i++)
670 vdac->bt_reg = 0xff; tc_wmb();
671
672 /*
673 * 2 bit/pixel cursor. Assign MSB for cursor mask and LSB for
674 * cursor image. CCOLOR_2 for mask color, while CCOLOR_3 for
675 * image color. CCOLOR_1 will be never used.
676 */
677 BT459_SELECT(vdac, BT459_REG_CCOLOR_1);
678 vdac->bt_reg = 0xff; tc_wmb();
679 vdac->bt_reg = 0xff; tc_wmb();
680 vdac->bt_reg = 0xff; tc_wmb();
681
682 vdac->bt_reg = 0; tc_wmb();
683 vdac->bt_reg = 0; tc_wmb();
684 vdac->bt_reg = 0; tc_wmb();
685
686 vdac->bt_reg = 0xff; tc_wmb();
687 vdac->bt_reg = 0xff; tc_wmb();
688 vdac->bt_reg = 0xff; tc_wmb();
689 }
690
691 static int
692 get_cmap(sc, p)
693 struct sfb_softc *sc;
694 struct wsdisplay_cmap *p;
695 {
696 u_int index = p->index, count = p->count;
697
698 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
699 return (EINVAL);
700
701 if (!useracc(p->red, count, B_WRITE) ||
702 !useracc(p->green, count, B_WRITE) ||
703 !useracc(p->blue, count, B_WRITE))
704 return (EFAULT);
705
706 copyout(&sc->sc_cmap.r[index], p->red, count);
707 copyout(&sc->sc_cmap.g[index], p->green, count);
708 copyout(&sc->sc_cmap.b[index], p->blue, count);
709
710 return (0);
711 }
712
713 static int
714 set_cmap(sc, p)
715 struct sfb_softc *sc;
716 struct wsdisplay_cmap *p;
717 {
718 u_int index = p->index, count = p->count;
719
720 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
721 return (EINVAL);
722
723 if (!useracc(p->red, count, B_READ) ||
724 !useracc(p->green, count, B_READ) ||
725 !useracc(p->blue, count, B_READ))
726 return (EFAULT);
727
728 copyin(p->red, &sc->sc_cmap.r[index], count);
729 copyin(p->green, &sc->sc_cmap.g[index], count);
730 copyin(p->blue, &sc->sc_cmap.b[index], count);
731
732 sc->sc_changed |= DATA_CMAP_CHANGED;
733
734 return (0);
735 }
736
737
738 static int
739 set_cursor(sc, p)
740 struct sfb_softc *sc;
741 struct wsdisplay_cursor *p;
742 {
743 #define cc (&sc->sc_cursor)
744 int v, index, count;
745
746 v = p->which;
747 if (v & WSDISPLAY_CURSOR_DOCMAP) {
748 index = p->cmap.index;
749 count = p->cmap.count;
750
751 if (index >= 2 || (index + count) > 2)
752 return (EINVAL);
753 if (!useracc(p->cmap.red, count, B_READ) ||
754 !useracc(p->cmap.green, count, B_READ) ||
755 !useracc(p->cmap.blue, count, B_READ))
756 return (EFAULT);
757 }
758 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
759 if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
760 return (EINVAL);
761 count = ((p->size.x < 33) ? 4 : 8) * p->size.y;
762 if (!useracc(p->image, count, B_READ) ||
763 !useracc(p->mask, count, B_READ))
764 return (EFAULT);
765 }
766 if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) {
767 if (v & WSDISPLAY_CURSOR_DOCUR)
768 cc->cc_hot = p->hot;
769 if (v & WSDISPLAY_CURSOR_DOPOS)
770 set_curpos(sc, &p->pos);
771 bt459_set_curpos(sc);
772 }
773
774 sc->sc_changed = 0;
775 if (v & WSDISPLAY_CURSOR_DOCUR) {
776 sc->sc_curenb = p->enable;
777 sc->sc_changed |= DATA_ENB_CHANGED;
778 }
779 if (v & WSDISPLAY_CURSOR_DOCMAP) {
780 count = p->cmap.count;
781 copyin(p->cmap.red, &cc->cc_color[index], count);
782 copyin(p->cmap.green, &cc->cc_color[index + 2], count);
783 copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
784 sc->sc_changed |= DATA_CURCMAP_CHANGED;
785 }
786 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
787 cc->cc_size = p->size;
788 memset(cc->cc_image, 0, sizeof cc->cc_image);
789 copyin(p->image, cc->cc_image, count);
790 copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, count);
791 sc->sc_changed |= DATA_CURSHAPE_CHANGED;
792 }
793
794 return (0);
795 #undef cc
796 }
797
798 static int
799 get_cursor(sc, p)
800 struct sfb_softc *sc;
801 struct wsdisplay_cursor *p;
802 {
803 return (ENOTTY); /* XXX */
804 }
805
806 static void
807 set_curpos(sc, curpos)
808 struct sfb_softc *sc;
809 struct wsdisplay_curpos *curpos;
810 {
811 struct fb_devconfig *dc = sc->sc_dc;
812 int x = curpos->x, y = curpos->y;
813
814 if (y < 0)
815 y = 0;
816 else if (y > dc->dc_ht)
817 y = dc->dc_ht;
818 if (x < 0)
819 x = 0;
820 else if (x > dc->dc_wid)
821 x = dc->dc_wid;
822 sc->sc_cursor.cc_pos.x = x;
823 sc->sc_cursor.cc_pos.y = y;
824 }
825
826 static void
827 bt459_set_curpos(sc)
828 struct sfb_softc *sc;
829 {
830 caddr_t sfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
831 struct bt459reg *vdac = (void *)(sfbbase + SFB_RAMDAC_OFFSET);
832 int x, y, s;
833
834 x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
835 y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
836 x += sc->magic_x; y += sc->magic_y; /* magic offset of HX coordinate */
837
838 s = spltty();
839
840 BT459_SELECT(vdac, BT459_REG_CURSOR_X_LOW);
841 vdac->bt_reg = x; tc_wmb();
842 vdac->bt_reg = x >> 8; tc_wmb();
843 vdac->bt_reg = y; tc_wmb();
844 vdac->bt_reg = y >> 8; tc_wmb();
845
846 splx(s);
847 }
848