1 /* $NetBSD: cfb.c,v 1.61 2012/01/11 21:12:36 macallan Exp $ */
2
3 /*-
4 * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Tohru Nishimura.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: cfb.c,v 1.61 2012/01/11 21:12:36 macallan Exp $");
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/device.h>
39 #include <sys/malloc.h>
40 #include <sys/buf.h>
41 #include <sys/ioctl.h>
42
43 #include <sys/bus.h>
44 #include <sys/intr.h>
45
46 #include <dev/wscons/wsconsio.h>
47 #include <dev/wscons/wsdisplayvar.h>
48
49 #include <dev/rasops/rasops.h>
50 #include <dev/wsfont/wsfont.h>
51
52 #include <dev/tc/tcvar.h>
53 #include <dev/ic/bt459reg.h>
54
55 #if defined(pmax)
56 #define machine_btop(x) mips_btop(MIPS_KSEG1_TO_PHYS(x))
57 #endif
58
59 #if defined(alpha)
60 #define machine_btop(x) alpha_btop(ALPHA_K0SEG_TO_PHYS(x))
61 #endif
62
63 /*
64 * N.B., Bt459 registers are 8bit width. Some of TC framebuffers have
65 * obscure register layout such as 2nd and 3rd Bt459 registers are
66 * adjacent each other in a word, i.e.,
67 * struct bt459triplet {
68 * struct {
69 * uint8_t u0;
70 * uint8_t u1;
71 * uint8_t u2;
72 * unsigned :8;
73 * } bt_lo;
74 * ...
75 * Although CX has single Bt459, 32bit R/W can be done w/o any trouble.
76 * struct bt459reg {
77 * uint32_t bt_lo;
78 * uint32_t bt_hi;
79 * uint32_t bt_reg;
80 * uint32_t bt_cmap;
81 * };
82 */
83
84 /* Bt459 hardware registers, memory-mapped in 32bit stride */
85 #define bt_lo 0x0
86 #define bt_hi 0x4
87 #define bt_reg 0x8
88 #define bt_cmap 0xc
89
90 #define REGWRITE32(p,i,v) do { \
91 *(volatile uint32_t *)((p) + (i)) = (v); tc_wmb(); \
92 } while (0)
93 #define VDACSELECT(p,r) do { \
94 REGWRITE32(p, bt_lo, 0xff & (r)); \
95 REGWRITE32(p, bt_hi, 0x0f & ((r)>>8)); \
96 } while (0)
97
98 struct hwcmap256 {
99 #define CMAP_SIZE 256 /* 256 R/G/B entries */
100 uint8_t r[CMAP_SIZE];
101 uint8_t g[CMAP_SIZE];
102 uint8_t b[CMAP_SIZE];
103 };
104
105 struct hwcursor64 {
106 struct wsdisplay_curpos cc_pos;
107 struct wsdisplay_curpos cc_hot;
108 struct wsdisplay_curpos cc_size;
109 struct wsdisplay_curpos cc_magic;
110 #define CURSOR_MAX_SIZE 64
111 uint8_t cc_color[6];
112 uint64_t cc_image[CURSOR_MAX_SIZE];
113 uint64_t cc_mask[CURSOR_MAX_SIZE];
114 };
115
116 struct cfb_softc {
117 vaddr_t sc_vaddr;
118 size_t sc_size;
119 struct rasops_info *sc_ri;
120 struct hwcmap256 sc_cmap; /* software copy of colormap */
121 struct hwcursor64 sc_cursor; /* software copy of cursor */
122 int sc_blanked;
123 int sc_curenb; /* cursor sprite enabled */
124 int sc_changed; /* need update of hardware */
125 #define WSDISPLAY_CMAP_DOLUT 0x20
126 int nscreens;
127 };
128
129 #define CX_MAGIC_X 220
130 #define CX_MAGIC_Y 35
131
132 #define CX_FB_OFFSET 0x000000
133 #define CX_FB_SIZE 0x100000
134 #define CX_BT459_OFFSET 0x200000
135 #define CX_OFFSET_IREQ 0x300000 /* Interrupt req. control */
136
137 static int cfbmatch(device_t, cfdata_t, void *);
138 static void cfbattach(device_t, device_t, void *);
139
140 CFATTACH_DECL_NEW(cfb, sizeof(struct cfb_softc),
141 cfbmatch, cfbattach, NULL, NULL);
142
143 static void cfb_common_init(struct rasops_info *);
144 static struct rasops_info cfb_console_ri;
145 static tc_addr_t cfb_consaddr;
146
147 static struct wsscreen_descr cfb_stdscreen = {
148 "std", 0, 0,
149 0, /* textops */
150 0, 0,
151 WSSCREEN_REVERSE
152 };
153
154 static const struct wsscreen_descr *_cfb_scrlist[] = {
155 &cfb_stdscreen,
156 };
157
158 static const struct wsscreen_list cfb_screenlist = {
159 sizeof(_cfb_scrlist) / sizeof(struct wsscreen_descr *), _cfb_scrlist
160 };
161
162 static int cfbioctl(void *, void *, u_long, void *, int, struct lwp *);
163 static paddr_t cfbmmap(void *, void *, off_t, int);
164
165 static int cfb_alloc_screen(void *, const struct wsscreen_descr *,
166 void **, int *, int *, long *);
167 static void cfb_free_screen(void *, void *);
168 static int cfb_show_screen(void *, void *, int,
169 void (*) (void *, int, int), void *);
170
171 static const struct wsdisplay_accessops cfb_accessops = {
172 cfbioctl,
173 cfbmmap,
174 cfb_alloc_screen,
175 cfb_free_screen,
176 cfb_show_screen,
177 0 /* load_font */
178 };
179
180 int cfb_cnattach(tc_addr_t);
181 static int cfbintr(void *);
182 static void cfbhwinit(void *);
183 static void cfb_cmap_init(struct cfb_softc *);
184
185 static int get_cmap(struct cfb_softc *, struct wsdisplay_cmap *);
186 static int set_cmap(struct cfb_softc *, struct wsdisplay_cmap *);
187 static int set_cursor(struct cfb_softc *, struct wsdisplay_cursor *);
188 static int get_cursor(struct cfb_softc *, struct wsdisplay_cursor *);
189 static void set_curpos(struct cfb_softc *, struct wsdisplay_curpos *);
190
191 /*
192 * Compose 2 bit/pixel cursor image. Bit order will be reversed.
193 * M M M M I I I I M I M I M I M I
194 * [ before ] [ after ]
195 * 3 2 1 0 3 2 1 0 0 0 1 1 2 2 3 3
196 * 7 6 5 4 7 6 5 4 4 4 5 5 6 6 7 7
197 */
198 static const uint8_t shuffle[256] = {
199 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
200 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55,
201 0x80, 0xc0, 0x90, 0xd0, 0x84, 0xc4, 0x94, 0xd4,
202 0x81, 0xc1, 0x91, 0xd1, 0x85, 0xc5, 0x95, 0xd5,
203 0x20, 0x60, 0x30, 0x70, 0x24, 0x64, 0x34, 0x74,
204 0x21, 0x61, 0x31, 0x71, 0x25, 0x65, 0x35, 0x75,
205 0xa0, 0xe0, 0xb0, 0xf0, 0xa4, 0xe4, 0xb4, 0xf4,
206 0xa1, 0xe1, 0xb1, 0xf1, 0xa5, 0xe5, 0xb5, 0xf5,
207 0x08, 0x48, 0x18, 0x58, 0x0c, 0x4c, 0x1c, 0x5c,
208 0x09, 0x49, 0x19, 0x59, 0x0d, 0x4d, 0x1d, 0x5d,
209 0x88, 0xc8, 0x98, 0xd8, 0x8c, 0xcc, 0x9c, 0xdc,
210 0x89, 0xc9, 0x99, 0xd9, 0x8d, 0xcd, 0x9d, 0xdd,
211 0x28, 0x68, 0x38, 0x78, 0x2c, 0x6c, 0x3c, 0x7c,
212 0x29, 0x69, 0x39, 0x79, 0x2d, 0x6d, 0x3d, 0x7d,
213 0xa8, 0xe8, 0xb8, 0xf8, 0xac, 0xec, 0xbc, 0xfc,
214 0xa9, 0xe9, 0xb9, 0xf9, 0xad, 0xed, 0xbd, 0xfd,
215 0x02, 0x42, 0x12, 0x52, 0x06, 0x46, 0x16, 0x56,
216 0x03, 0x43, 0x13, 0x53, 0x07, 0x47, 0x17, 0x57,
217 0x82, 0xc2, 0x92, 0xd2, 0x86, 0xc6, 0x96, 0xd6,
218 0x83, 0xc3, 0x93, 0xd3, 0x87, 0xc7, 0x97, 0xd7,
219 0x22, 0x62, 0x32, 0x72, 0x26, 0x66, 0x36, 0x76,
220 0x23, 0x63, 0x33, 0x73, 0x27, 0x67, 0x37, 0x77,
221 0xa2, 0xe2, 0xb2, 0xf2, 0xa6, 0xe6, 0xb6, 0xf6,
222 0xa3, 0xe3, 0xb3, 0xf3, 0xa7, 0xe7, 0xb7, 0xf7,
223 0x0a, 0x4a, 0x1a, 0x5a, 0x0e, 0x4e, 0x1e, 0x5e,
224 0x0b, 0x4b, 0x1b, 0x5b, 0x0f, 0x4f, 0x1f, 0x5f,
225 0x8a, 0xca, 0x9a, 0xda, 0x8e, 0xce, 0x9e, 0xde,
226 0x8b, 0xcb, 0x9b, 0xdb, 0x8f, 0xcf, 0x9f, 0xdf,
227 0x2a, 0x6a, 0x3a, 0x7a, 0x2e, 0x6e, 0x3e, 0x7e,
228 0x2b, 0x6b, 0x3b, 0x7b, 0x2f, 0x6f, 0x3f, 0x7f,
229 0xaa, 0xea, 0xba, 0xfa, 0xae, 0xee, 0xbe, 0xfe,
230 0xab, 0xeb, 0xbb, 0xfb, 0xaf, 0xef, 0xbf, 0xff,
231 };
232
233 static int
cfbmatch(device_t parent,cfdata_t match,void * aux)234 cfbmatch(device_t parent, cfdata_t match, void *aux)
235 {
236 struct tc_attach_args *ta = aux;
237
238 if (strncmp("PMAG-BA ", ta->ta_modname, TC_ROM_LLEN) != 0)
239 return (0);
240
241 return (1);
242 }
243
244 static void
cfbattach(device_t parent,device_t self,void * aux)245 cfbattach(device_t parent, device_t self, void *aux)
246 {
247 struct cfb_softc *sc = device_private(self);
248 struct tc_attach_args *ta = aux;
249 struct rasops_info *ri;
250 struct wsemuldisplaydev_attach_args waa;
251 int console;
252
253 console = (ta->ta_addr == cfb_consaddr);
254 if (console) {
255 sc->sc_ri = ri = &cfb_console_ri;
256 ri->ri_flg &= ~RI_NO_AUTO;
257 sc->nscreens = 1;
258 }
259 else {
260 ri = malloc(sizeof(struct rasops_info),
261 M_DEVBUF, M_NOWAIT|M_ZERO);
262 if (ri == NULL) {
263 printf(": can't alloc memory\n");
264 return;
265 }
266
267 ri->ri_hw = (void *)ta->ta_addr;
268 cfb_common_init(ri);
269 sc->sc_ri = ri;
270 }
271 printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height, ri->ri_depth);
272
273 cfb_cmap_init(sc);
274
275 sc->sc_vaddr = ta->ta_addr;
276 sc->sc_cursor.cc_magic.x = CX_MAGIC_X;
277 sc->sc_cursor.cc_magic.y = CX_MAGIC_Y;
278 sc->sc_blanked = sc->sc_curenb = 0;
279
280 tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, cfbintr, sc);
281
282 /* clear any pending interrupts */
283 *(volatile uint8_t *)((char *)ri->ri_hw + CX_OFFSET_IREQ) = 0;
284
285 waa.console = console;
286 waa.scrdata = &cfb_screenlist;
287 waa.accessops = &cfb_accessops;
288 waa.accesscookie = sc;
289
290 config_found(self, &waa, wsemuldisplaydevprint);
291 }
292
293 static void
cfb_cmap_init(struct cfb_softc * sc)294 cfb_cmap_init(struct cfb_softc *sc)
295 {
296 struct hwcmap256 *cm;
297 const uint8_t *p;
298 int index;
299
300 cm = &sc->sc_cmap;
301 p = rasops_cmap;
302 for (index = 0; index < CMAP_SIZE; index++, p += 3) {
303 cm->r[index] = p[0];
304 cm->g[index] = p[1];
305 cm->b[index] = p[2];
306 }
307 }
308
309 static void
cfb_common_init(struct rasops_info * ri)310 cfb_common_init(struct rasops_info *ri)
311 {
312 char *base;
313 int cookie;
314
315 base = (void *)ri->ri_hw;
316
317 /* initialize colormap and cursor hardware */
318 cfbhwinit(base);
319
320 ri->ri_flg = RI_CENTER;
321 if (ri == &cfb_console_ri)
322 ri->ri_flg |= RI_NO_AUTO;
323 ri->ri_depth = 8;
324 ri->ri_width = 1024;
325 ri->ri_height = 864;
326 ri->ri_stride = 1024;
327 ri->ri_bits = base + CX_FB_OFFSET;
328
329 /* clear the screen */
330 memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
331
332 wsfont_init();
333 /* prefer 12 pixel wide font */
334 cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_L2R,
335 WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
336 if (cookie <= 0)
337 cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_L2R,
338 WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
339 if (cookie <= 0) {
340 printf("cfb: font table is empty\n");
341 return;
342 }
343
344 if (wsfont_lock(cookie, &ri->ri_font)) {
345 printf("cfb: couldn't lock font\n");
346 return;
347 }
348 ri->ri_wsfcookie = cookie;
349
350 rasops_init(ri, 34, 80);
351
352 /* XXX shouldn't be global */
353 cfb_stdscreen.nrows = ri->ri_rows;
354 cfb_stdscreen.ncols = ri->ri_cols;
355 cfb_stdscreen.textops = &ri->ri_ops;
356 cfb_stdscreen.capabilities = ri->ri_caps;
357 }
358
359 static int
cfbioctl(void * v,void * vs,u_long cmd,void * data,int flag,struct lwp * l)360 cfbioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
361 {
362 struct cfb_softc *sc = v;
363 struct rasops_info *ri = sc->sc_ri;
364 int turnoff, s;
365
366 switch (cmd) {
367 case WSDISPLAYIO_GTYPE:
368 *(u_int *)data = WSDISPLAY_TYPE_CFB;
369 return (0);
370
371 case WSDISPLAYIO_GINFO:
372 #define wsd_fbip ((struct wsdisplay_fbinfo *)data)
373 wsd_fbip->height = ri->ri_height;
374 wsd_fbip->width = ri->ri_width;
375 wsd_fbip->depth = ri->ri_depth;
376 wsd_fbip->cmsize = CMAP_SIZE;
377 #undef fbt
378 return (0);
379
380 case WSDISPLAYIO_GETCMAP:
381 return get_cmap(sc, (struct wsdisplay_cmap *)data);
382
383 case WSDISPLAYIO_PUTCMAP:
384 return set_cmap(sc, (struct wsdisplay_cmap *)data);
385
386 case WSDISPLAYIO_SVIDEO:
387 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
388 if (sc->sc_blanked != turnoff) {
389 sc->sc_blanked = turnoff;
390 /* XXX later XXX */
391 }
392 return (0);
393
394 case WSDISPLAYIO_GVIDEO:
395 *(u_int *)data = sc->sc_blanked ?
396 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
397 return (0);
398
399 case WSDISPLAYIO_GCURPOS:
400 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
401 return (0);
402
403 case WSDISPLAYIO_SCURPOS:
404 s = spltty();
405 set_curpos(sc, (struct wsdisplay_curpos *)data);
406 sc->sc_changed |= WSDISPLAY_CURSOR_DOPOS;
407 splx(s);
408 return (0);
409
410 case WSDISPLAYIO_GCURMAX:
411 ((struct wsdisplay_curpos *)data)->x =
412 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
413 return (0);
414
415 case WSDISPLAYIO_GCURSOR:
416 return get_cursor(sc, (struct wsdisplay_cursor *)data);
417
418 case WSDISPLAYIO_SCURSOR:
419 return set_cursor(sc, (struct wsdisplay_cursor *)data);
420
421 case WSDISPLAYIO_SMODE:
422 if (*(int *)data == WSDISPLAYIO_MODE_EMUL) {
423 s = spltty();
424 cfb_cmap_init(sc);
425 sc->sc_curenb = 0;
426 sc->sc_blanked = 0;
427 sc->sc_changed |= (WSDISPLAY_CURSOR_DOCUR |
428 WSDISPLAY_CMAP_DOLUT);
429 splx(s);
430 }
431 return (0);
432 }
433 return EPASSTHROUGH;
434 }
435
436 paddr_t
cfbmmap(void * v,void * vs,off_t offset,int prot)437 cfbmmap(void *v, void *vs, off_t offset, int prot)
438 {
439 struct cfb_softc *sc = v;
440
441 if (offset >= CX_FB_SIZE || offset < 0)
442 return (-1);
443 return machine_btop(sc->sc_vaddr + CX_FB_OFFSET + offset);
444 }
445
446 static int
cfb_alloc_screen(void * v,const struct wsscreen_descr * type,void ** cookiep,int * curxp,int * curyp,long * attrp)447 cfb_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
448 int *curxp, int *curyp, long *attrp)
449 {
450 struct cfb_softc *sc = v;
451 struct rasops_info *ri = sc->sc_ri;
452 long defattr;
453
454 if (sc->nscreens > 0)
455 return (ENOMEM);
456
457 *cookiep = ri; /* one and only for now */
458 *curxp = 0;
459 *curyp = 0;
460 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
461 *attrp = defattr;
462 sc->nscreens++;
463 return (0);
464 }
465
466 static void
cfb_free_screen(void * v,void * cookie)467 cfb_free_screen(void *v, void *cookie)
468 {
469 struct cfb_softc *sc = v;
470
471 if (sc->sc_ri == &cfb_console_ri)
472 panic("cfb_free_screen: console");
473
474 sc->nscreens--;
475 }
476
477 static int
cfb_show_screen(void * v,void * cookie,int waitok,void (* cb)(void *,int,int),void * cbarg)478 cfb_show_screen(void *v, void *cookie, int waitok,
479 void (*cb)(void *, int, int), void *cbarg)
480 {
481
482 return (0);
483 }
484
485 /* EXPORT */ int
cfb_cnattach(tc_addr_t addr)486 cfb_cnattach(tc_addr_t addr)
487 {
488 struct rasops_info *ri;
489 long defattr;
490
491 ri = &cfb_console_ri;
492 ri->ri_hw = (void *)addr;
493 cfb_common_init(ri);
494 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
495 wsdisplay_cnattach(&cfb_stdscreen, ri, 0, 0, defattr);
496 cfb_consaddr = addr;
497 return(0);
498 }
499
500 static int
cfbintr(void * arg)501 cfbintr(void *arg)
502 {
503 struct cfb_softc *sc = arg;
504 char *base, *vdac;
505 int v;
506
507 base = (void *)sc->sc_ri->ri_hw;
508 *(uint8_t *)(base + CX_OFFSET_IREQ) = 0;
509 if (sc->sc_changed == 0)
510 return (1);
511
512 vdac = base + CX_BT459_OFFSET;
513 v = sc->sc_changed;
514 if (v & WSDISPLAY_CURSOR_DOCUR) {
515 VDACSELECT(vdac, BT459_IREG_CCR);
516 REGWRITE32(vdac, bt_reg, (sc->sc_curenb) ? 0xc0 : 0x00);
517 }
518 if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) {
519 int x, y;
520
521 x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
522 y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
523
524 x += sc->sc_cursor.cc_magic.x;
525 y += sc->sc_cursor.cc_magic.y;
526
527 VDACSELECT(vdac, BT459_IREG_CURSOR_X_LOW);
528 REGWRITE32(vdac, bt_reg, x);
529 REGWRITE32(vdac, bt_reg, x >> 8);
530 REGWRITE32(vdac, bt_reg, y);
531 REGWRITE32(vdac, bt_reg, y >> 8);
532 }
533 if (v & WSDISPLAY_CURSOR_DOCMAP) {
534 uint8_t *cp = sc->sc_cursor.cc_color;
535
536 VDACSELECT(vdac, BT459_IREG_CCOLOR_2);
537 REGWRITE32(vdac, bt_reg, cp[1]);
538 REGWRITE32(vdac, bt_reg, cp[3]);
539 REGWRITE32(vdac, bt_reg, cp[5]);
540
541 REGWRITE32(vdac, bt_reg, cp[0]);
542 REGWRITE32(vdac, bt_reg, cp[2]);
543 REGWRITE32(vdac, bt_reg, cp[4]);
544 }
545 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
546 uint8_t *ip, *mp, img, msk;
547 uint8_t u;
548 int bcnt;
549
550 ip = (uint8_t *)sc->sc_cursor.cc_image;
551 mp = (uint8_t *)sc->sc_cursor.cc_mask;
552
553 bcnt = 0;
554 VDACSELECT(vdac, BT459_IREG_CRAM_BASE+0);
555 /* 64 pixel scan line is consisted with 16 byte cursor ram */
556 while (bcnt < sc->sc_cursor.cc_size.y * 16) {
557 /* pad right half 32 pixel when smaller than 33 */
558 if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
559 REGWRITE32(vdac, bt_reg, 0);
560 REGWRITE32(vdac, bt_reg, 0);
561 }
562 else {
563 img = *ip++;
564 msk = *mp++;
565 img &= msk; /* cookie off image */
566 u = (msk & 0x0f) << 4 | (img & 0x0f);
567 REGWRITE32(vdac, bt_reg, shuffle[u]);
568 u = (msk & 0xf0) | (img & 0xf0) >> 4;
569 REGWRITE32(vdac, bt_reg, shuffle[u]);
570 }
571 bcnt += 2;
572 }
573 /* pad unoccupied scan lines */
574 while (bcnt < CURSOR_MAX_SIZE * 16) {
575 REGWRITE32(vdac, bt_reg, 0);
576 REGWRITE32(vdac, bt_reg, 0);
577 bcnt += 2;
578 }
579 }
580 if (v & WSDISPLAY_CMAP_DOLUT) {
581 struct hwcmap256 *cm = &sc->sc_cmap;
582 int index;
583
584 VDACSELECT(vdac, 0);
585 for (index = 0; index < CMAP_SIZE; index++) {
586 REGWRITE32(vdac, bt_cmap, cm->r[index]);
587 REGWRITE32(vdac, bt_cmap, cm->g[index]);
588 REGWRITE32(vdac, bt_cmap, cm->b[index]);
589 }
590 }
591 sc->sc_changed = 0;
592 return (1);
593 }
594
595 static void
cfbhwinit(void * cfbbase)596 cfbhwinit(void *cfbbase)
597 {
598 char *vdac = (char *)cfbbase + CX_BT459_OFFSET;
599 const uint8_t *p;
600 int i;
601
602 VDACSELECT(vdac, BT459_IREG_COMMAND_0);
603 REGWRITE32(vdac, bt_reg, 0x40); /* CMD0 */
604 REGWRITE32(vdac, bt_reg, 0x0); /* CMD1 */
605 REGWRITE32(vdac, bt_reg, 0xc0); /* CMD2 */
606 REGWRITE32(vdac, bt_reg, 0xff); /* PRM */
607 REGWRITE32(vdac, bt_reg, 0); /* 205 */
608 REGWRITE32(vdac, bt_reg, 0x0); /* PBM */
609 REGWRITE32(vdac, bt_reg, 0); /* 207 */
610 REGWRITE32(vdac, bt_reg, 0x0); /* ORM */
611 REGWRITE32(vdac, bt_reg, 0x0); /* OBM */
612 REGWRITE32(vdac, bt_reg, 0x0); /* ILV */
613 REGWRITE32(vdac, bt_reg, 0x0); /* TEST */
614
615 VDACSELECT(vdac, BT459_IREG_CCR);
616 REGWRITE32(vdac, bt_reg, 0x0);
617 REGWRITE32(vdac, bt_reg, 0x0);
618 REGWRITE32(vdac, bt_reg, 0x0);
619 REGWRITE32(vdac, bt_reg, 0x0);
620 REGWRITE32(vdac, bt_reg, 0x0);
621 REGWRITE32(vdac, bt_reg, 0x0);
622 REGWRITE32(vdac, bt_reg, 0x0);
623 REGWRITE32(vdac, bt_reg, 0x0);
624 REGWRITE32(vdac, bt_reg, 0x0);
625 REGWRITE32(vdac, bt_reg, 0x0);
626 REGWRITE32(vdac, bt_reg, 0x0);
627 REGWRITE32(vdac, bt_reg, 0x0);
628 REGWRITE32(vdac, bt_reg, 0x0);
629
630 /* build sane colormap */
631 VDACSELECT(vdac, 0);
632 p = rasops_cmap;
633 for (i = 0; i < CMAP_SIZE; i++, p += 3) {
634 REGWRITE32(vdac, bt_cmap, p[0]);
635 REGWRITE32(vdac, bt_cmap, p[1]);
636 REGWRITE32(vdac, bt_cmap, p[2]);
637 }
638
639 /* clear out cursor image */
640 VDACSELECT(vdac, BT459_IREG_CRAM_BASE);
641 for (i = 0; i < 1024; i++)
642 REGWRITE32(vdac, bt_reg, 0xff);
643
644 /*
645 * 2 bit/pixel cursor. Assign MSB for cursor mask and LSB for
646 * cursor image. CCOLOR_2 for mask color, while CCOLOR_3 for
647 * image color. CCOLOR_1 will be never used.
648 */
649 VDACSELECT(vdac, BT459_IREG_CCOLOR_1);
650 REGWRITE32(vdac, bt_reg, 0xff);
651 REGWRITE32(vdac, bt_reg, 0xff);
652 REGWRITE32(vdac, bt_reg, 0xff);
653
654 REGWRITE32(vdac, bt_reg, 0);
655 REGWRITE32(vdac, bt_reg, 0);
656 REGWRITE32(vdac, bt_reg, 0);
657
658 REGWRITE32(vdac, bt_reg, 0xff);
659 REGWRITE32(vdac, bt_reg, 0xff);
660 REGWRITE32(vdac, bt_reg, 0xff);
661 }
662
663 static int
get_cmap(struct cfb_softc * sc,struct wsdisplay_cmap * p)664 get_cmap(struct cfb_softc *sc, struct wsdisplay_cmap *p)
665 {
666 u_int index = p->index, count = p->count;
667 int error;
668
669 if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
670 return (EINVAL);
671
672 error = copyout(&sc->sc_cmap.r[index], p->red, count);
673 if (error)
674 return error;
675 error = copyout(&sc->sc_cmap.g[index], p->green, count);
676 if (error)
677 return error;
678 error = copyout(&sc->sc_cmap.b[index], p->blue, count);
679 return error;
680 }
681
682 static int
set_cmap(struct cfb_softc * sc,struct wsdisplay_cmap * p)683 set_cmap(struct cfb_softc *sc, struct wsdisplay_cmap *p)
684 {
685 struct hwcmap256 cmap;
686 u_int index = p->index, count = p->count;
687 int error, s;
688
689 if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
690 return (EINVAL);
691
692 error = copyin(p->red, &cmap.r[index], count);
693 if (error)
694 return error;
695 error = copyin(p->green, &cmap.g[index], count);
696 if (error)
697 return error;
698 error = copyin(p->blue, &cmap.b[index], count);
699 if (error)
700 return error;
701 s = spltty();
702 memcpy(&sc->sc_cmap.r[index], &cmap.r[index], count);
703 memcpy(&sc->sc_cmap.g[index], &cmap.g[index], count);
704 memcpy(&sc->sc_cmap.b[index], &cmap.b[index], count);
705 sc->sc_changed |= WSDISPLAY_CMAP_DOLUT;
706 splx(s);
707 return (0);
708 }
709
710 static int
set_cursor(struct cfb_softc * sc,struct wsdisplay_cursor * p)711 set_cursor(struct cfb_softc *sc, struct wsdisplay_cursor *p)
712 {
713 #define cc (&sc->sc_cursor)
714 u_int v, index = 0, count = 0, icount = 0;
715 uint8_t r[2], g[2], b[2], image[512], mask[512];
716 int error, s;
717
718 v = p->which;
719 if (v & WSDISPLAY_CURSOR_DOCMAP) {
720 index = p->cmap.index;
721 count = p->cmap.count;
722 if (index >= 2 || (index + count) > 2)
723 return (EINVAL);
724 error = copyin(p->cmap.red, &r[index], count);
725 if (error)
726 return error;
727 error = copyin(p->cmap.green, &g[index], count);
728 if (error)
729 return error;
730 error = copyin(p->cmap.blue, &b[index], count);
731 if (error)
732 return error;
733 }
734 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
735 if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
736 return (EINVAL);
737 icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
738 error = copyin(p->image, image, icount);
739 if (error)
740 return error;
741 error = copyin(p->mask, mask, icount);
742 if (error)
743 return error;
744 }
745
746 s = spltty();
747 if (v & WSDISPLAY_CURSOR_DOCUR)
748 sc->sc_curenb = p->enable;
749 if (v & WSDISPLAY_CURSOR_DOPOS)
750 set_curpos(sc, &p->pos);
751 if (v & WSDISPLAY_CURSOR_DOHOT)
752 cc->cc_hot = p->hot;
753 if (v & WSDISPLAY_CURSOR_DOCMAP) {
754 memcpy(&cc->cc_color[index], &r[index], count);
755 memcpy(&cc->cc_color[index + 2], &g[index], count);
756 memcpy(&cc->cc_color[index + 4], &b[index], count);
757 }
758 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
759 cc->cc_size = p->size;
760 memset(cc->cc_image, 0, sizeof cc->cc_image);
761 memcpy(cc->cc_image, image, icount);
762 memset(cc->cc_mask, 0, sizeof cc->cc_mask);
763 memcpy(cc->cc_mask, mask, icount);
764 }
765 sc->sc_changed |= v;
766 splx(s);
767
768 return (0);
769 #undef cc
770 }
771
772 static int
get_cursor(struct cfb_softc * sc,struct wsdisplay_cursor * p)773 get_cursor(struct cfb_softc *sc, struct wsdisplay_cursor *p)
774 {
775 return (EPASSTHROUGH); /* XXX */
776 }
777
778 static void
set_curpos(struct cfb_softc * sc,struct wsdisplay_curpos * curpos)779 set_curpos(struct cfb_softc *sc, struct wsdisplay_curpos *curpos)
780 {
781 struct rasops_info *ri = sc->sc_ri;
782 int x = curpos->x, y = curpos->y;
783
784 if (y < 0)
785 y = 0;
786 else if (y > ri->ri_height)
787 y = ri->ri_height;
788 if (x < 0)
789 x = 0;
790 else if (x > ri->ri_width)
791 x = ri->ri_width;
792 sc->sc_cursor.cc_pos.x = x;
793 sc->sc_cursor.cc_pos.y = y;
794 }
795