fbbm.c revision 1.1 1 /* $NetBSD: fbbm.c,v 1.1 2026/09/20 10:29:11 tsutsui Exp $ */
2
3 /*-
4 * Copyright (c) 2026 Izumi Tsutsui. 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 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 #include <sys/cdefs.h>
28 __KERNEL_RCSID(0, "$NetBSD: fbbm.c,v 1.1 2026/09/20 10:29:11 tsutsui Exp $");
29
30 #include <sys/param.h>
31 #include <sys/device.h>
32 #include <sys/errno.h>
33 #include <sys/ioctl.h>
34 #include <sys/kmem.h>
35 #include <sys/systm.h>
36
37 #include <machine/bus.h>
38
39 #include <news68k/dev/hbvar.h>
40 #include <news68k/dev/nwb225reg.h>
41
42 #include <dev/wscons/wsconsio.h>
43 #include <dev/wscons/wsdisplayvar.h>
44
45 struct fbbm_devconfig {
46 bus_space_tag_t dc_bst;
47 bus_space_handle_t dc_rcont_bsh;
48 bus_space_handle_t dc_krom_bsh;
49
50 int dc_nplanes;
51 uint32_t dc_planemask;
52 int dc_dispver;
53
54 int dc_fbwidth;
55 int dc_fbheight;
56 int dc_width;
57 int dc_height;
58
59 int dc_fontwidth;
60 int dc_fontheight;
61 int dc_cellwidth;
62 int dc_cellheight;
63
64 int dc_ncols;
65 int dc_nrows;
66 int dc_xorigin;
67 int dc_yorigin;
68
69 int dc_cursoron;
70 int dc_cursorrow;
71 int dc_cursorcol;
72
73 struct wsscreen_descr dc_wsscrdescr;
74 };
75
76 struct fbbm_softc {
77 device_t sc_dev;
78 struct fbbm_devconfig *sc_dc;
79 int sc_nscreens;
80 int sc_wsmode;
81 const struct wsscreen_descr *sc_scrdescs[1];
82 struct wsscreen_list sc_scrlist;
83 };
84
85 /* autoconf functions and helpers */
86 static int fbbm_match(device_t, cfdata_t, void *);
87 static void fbbm_attach(device_t, device_t, void *);
88
89 static bool fbbm_console_initialized(void);
90 static int fbbm_probe(bus_space_tag_t, bus_addr_t);
91
92 /* bus_space mappings */
93 static int nwb225_map(struct fbbm_devconfig *, bus_space_tag_t, bus_addr_t);
94 static void nwb225_unmap(struct fbbm_devconfig *);
95
96 /* ROP helper functions */
97 static void nwb225_rop_reset(struct fbbm_devconfig *);
98 static int nwb225_rop_wait(struct fbbm_devconfig *);
99 static void nwb225_ctl_write(struct fbbm_devconfig *, uint16_t, uint16_t);
100 static void nwb225_rop_set_plane_mask(struct fbbm_devconfig *, uint32_t);
101 static void nwb225_rop_make_funcvec(struct fbbm_devconfig *, u_int,
102 uint32_t, uint32_t, uint8_t *);
103 static void nwb225_rop_funcvec_constant_s(struct fbbm_devconfig *, uint8_t *,
104 u_int);
105 static void nwb225_rop_set_funcvec(struct fbbm_devconfig *, const uint8_t *);
106
107 /* Hardware primitive ROP functions */
108 static int nwb225_rop_copy_rect(struct fbbm_devconfig *, int, int, int, int,
109 int, int, u_int);
110 static int nwb225_rop_fill_rect(struct fbbm_devconfig *, int, int, int, int,
111 uint32_t);
112 static int nwb225_rop_hwrite(struct fbbm_devconfig *, const uint16_t *, int,
113 int, int, int, int, int, int, uint32_t, uint32_t);
114
115 /* ROM font functions */
116 static bus_size_t nwb225_krom_ascii_offset(u_int);
117 static void nwb225_krom_load_cell(struct fbbm_devconfig *, u_int,
118 uint16_t *);
119
120 /* Initialization */
121 static int nwb225_init_hardware(struct fbbm_devconfig *);
122
123 static void fbbm_init_screen(struct fbbm_devconfig *);
124 static int fbbm_clear_screen(struct fbbm_devconfig *);
125
126 /* wsdisplay_emulops functions */
127 static void fbbm_cursor(void *, int, int, int);
128 static int fbbm_mapchar(void *, int, u_int *);
129 static void fbbm_putchar(void *, int, int, u_int, long);
130 static void fbbm_copycols(void *, int, int, int, int);
131 static void fbbm_erasecols(void *, int, int, int, long);
132 static void fbbm_copyrows(void *, int, int, int);
133 static void fbbm_eraserows(void *, int, int, long);
134 static int fbbm_allocattr(void *, int, int, int, long *);
135
136 /* wsdisplay_accessops functions */
137 static int fbbm_ioctl(void *, void *, u_long, void *, int, struct lwp *);
138 static int fbbm_alloc_screen(void *, const struct wsscreen_descr *, void **,
139 int *, int *, long *);
140 static void fbbm_free_screen(void *, void *);
141 static int fbbm_show_screen(void *, void *, int, void (*)(void *, int, int),
142 void *);
143
144 /* cnattach function for early console */
145 int fbbm_cnattach(void);
146
147 CFATTACH_DECL_NEW(fbbm, sizeof(struct fbbm_softc),
148 fbbm_match, fbbm_attach, NULL, NULL);
149
150 static struct fbbm_devconfig fbbm_console_dc;
151
152 static const struct wsdisplay_emulops fbbm_emulops = {
153 .cursor = fbbm_cursor,
154 .mapchar = fbbm_mapchar,
155 .putchar = fbbm_putchar,
156 .copycols = fbbm_copycols,
157 .erasecols = fbbm_erasecols,
158 .copyrows = fbbm_copyrows,
159 .eraserows = fbbm_eraserows,
160 .allocattr = fbbm_allocattr,
161 .replaceattr = NULL,
162 };
163
164 static const struct wsdisplay_accessops fbbm_accessops = {
165 .ioctl = fbbm_ioctl,
166 .mmap = NULL,
167 .alloc_screen = fbbm_alloc_screen,
168 .free_screen = fbbm_free_screen,
169 .show_screen = fbbm_show_screen,
170 .load_font = NULL,
171 .pollc = NULL,
172 .scroll = NULL,
173 };
174
175 /* Timeout count to check ROP op complete */
176 #define NWB225_WAIT_MAX 100000
177
178 /* Maximum number of planes of NWB-225 (4 or 8) */
179 #define NWB225_MAX_PLANES 8
180
181 /*
182 * Software logical functions F(S,D).
183 * These values index nwb225_fccnvtab[] and are not hardware function values.
184 */
185 #define NWB225_ROP_LF_0 0x00
186 #define NWB225_ROP_LF_S 0x03
187 #define NWB225_ROP_LF_D 0x05
188 #define NWB225_ROP_LF_DI 0x0a
189 #define NWB225_ROP_LF_1 0x0f
190
191 /*
192 * Logical FBBM function to 51X hardware function conversion table
193 * taken from NEWS-OS fbbm_51x.o.
194 */
195 static const uint8_t nwb225_fccnvtab[16] = {
196 0x03, 0x0b, 0x07, 0x0f,
197 0x02, 0x0a, 0x06, 0x0e,
198 0x01, 0x09, 0x05, 0x0d,
199 0x00, 0x08, 0x04, 0x0c,
200 };
201
202 /*
203 * Fixed initialization values written by the NWS-1750 PROM and NEWS-OS
204 * 51X setup. Their individual timing/control semantics are intentionally
205 * not inferred here.
206 */
207 static const uint16_t nwb225_init_words[] = {
208 0x0400, 0x0002, 0x0005, 0x00d8,
209 0x0000, 0x0006, 0x0000,
210 };
211
212 /*
213 * 4-bit component values taken from the NWS-1750 PROM NWB-225 module.
214 * The PROM repeats this 16-entry table through all 256 palette indices
215 * and writes each component after shifting it left by four bits.
216 */
217 static const uint8_t nwb225_prom_palette[16][3] = {
218 { 0, 0, 0 },
219 { 0, 0, 4 },
220 { 0, 4, 0 },
221 { 0, 4, 4 },
222 { 4, 0, 0 },
223 { 4, 0, 4 },
224 { 4, 4, 0 },
225 { 4, 4, 4 },
226 { 8, 8, 8 },
227 { 0, 0, 15 },
228 { 0, 15, 0 },
229 { 0, 15, 15 },
230 { 15, 0, 0 },
231 { 15, 0, 15 },
232 { 15, 15, 0 },
233 { 15, 15, 15 },
234 };
235
236 static bool
237 fbbm_console_initialized(void)
238 {
239
240 /*
241 * This is initialized in fbbm_init_screen() via
242 * fbbm_cnattach() or fbbm_cnattach().
243 */
244 return fbbm_console_dc.dc_wsscrdescr.textops == &fbbm_emulops;
245 }
246
247 static int
248 fbbm_probe(bus_space_tag_t bst, bus_addr_t rcont_addr)
249 {
250 bus_space_handle_t bsh;
251 int rv;
252
253 if (bus_space_map(bst, rcont_addr, NWB225_RCONT_SIZE, 0, &bsh) != 0)
254 return 0;
255
256 /* NEWS-OS fb225_probe() used a byte-sized badaddr() at this base */
257 rv = news68k_bus_space_probe(bst, bsh, 0, 1);
258 bus_space_unmap(bst, bsh, NWB225_RCONT_SIZE);
259
260 return rv;
261 }
262
263 static int
264 fbbm_match(device_t parent, cfdata_t cf, void *aux)
265 {
266 struct hb_attach_args *ha = aux;
267
268 if (strcmp(ha->ha_name, "fbbm") != 0)
269 return 0;
270 if (ha->ha_address != NWB225_RCONT_BASE)
271 return 0;
272
273 return fbbm_probe(ha->ha_bust, ha->ha_address);
274 }
275
276 static void
277 fbbm_attach(device_t parent, device_t self, void *aux)
278 {
279 struct fbbm_softc *sc = device_private(self);
280 struct hb_attach_args *ha = aux;
281 struct fbbm_devconfig *dc;
282 struct wsemuldisplaydev_attach_args waa;
283 bool console;
284
285 sc->sc_dev = self;
286 console = fbbm_console_initialized();
287
288 if (console) {
289 dc = &fbbm_console_dc;
290 sc->sc_nscreens = 1;
291 } else {
292 dc = kmem_zalloc(sizeof(*dc), KM_SLEEP);
293 if (nwb225_map(dc, ha->ha_bust, ha->ha_address) != 0) {
294 aprint_error(": unable to map device registers");
295 goto out_free;
296 }
297
298 if (nwb225_init_hardware(dc) != 0) {
299 aprint_error(": controller initialization failed");
300 goto out_unmap;
301 }
302
303 fbbm_init_screen(dc);
304 if (fbbm_clear_screen(dc) != 0) {
305 aprint_error(": unable to clear text screen");
306 goto out_unmap;
307 }
308 sc->sc_nscreens = 0;
309 }
310
311 sc->sc_dc = dc;
312 sc->sc_wsmode = WSDISPLAYIO_MODE_EMUL;
313 sc->sc_scrdescs[0] = &dc->dc_wsscrdescr;
314 sc->sc_scrlist.nscreens = __arraycount(sc->sc_scrdescs);
315 sc->sc_scrlist.screens = sc->sc_scrdescs;
316
317 aprint_normal(": NWB-225, %d x %d, %d planes, display version %d\n",
318 dc->dc_width, dc->dc_height, dc->dc_nplanes, dc->dc_dispver);
319
320 waa.console = console;
321 waa.scrdata = &sc->sc_scrlist;
322 waa.accessops = &fbbm_accessops;
323 waa.accesscookie = sc;
324
325 config_found(self, &waa, wsemuldisplaydevprint, CFARGS_NONE);
326 return;
327
328 out_unmap:
329 nwb225_unmap(dc);
330 out_free:
331 kmem_free(dc, sizeof(*dc));
332 }
333
334 static int
335 nwb225_map(struct fbbm_devconfig *dc, bus_space_tag_t bst,
336 bus_addr_t rcont_addr)
337 {
338 int error;
339
340 dc->dc_bst = bst;
341
342 error = bus_space_map(bst, rcont_addr, NWB225_RCONT_SIZE, 0,
343 &dc->dc_rcont_bsh);
344 if (error != 0)
345 return error;
346
347 error = bus_space_map(bst, NWB225_KROM_BASE, NWB225_KROM_SIZE, 0,
348 &dc->dc_krom_bsh);
349 if (error != 0) {
350 bus_space_unmap(bst, dc->dc_rcont_bsh, NWB225_RCONT_SIZE);
351 return error;
352 }
353
354 return 0;
355 }
356
357 static void
358 nwb225_unmap(struct fbbm_devconfig *dc)
359 {
360
361 bus_space_unmap(dc->dc_bst, dc->dc_krom_bsh, NWB225_KROM_SIZE);
362 bus_space_unmap(dc->dc_bst, dc->dc_rcont_bsh, NWB225_RCONT_SIZE);
363 }
364
365 static void
366 nwb225_rop_reset(struct fbbm_devconfig *dc)
367 {
368
369 /*
370 * Both NEWS-OS fb51X_rop_reset() and the NWS-1750 PROM perform
371 * this 0 -> 1 sequence.
372 */
373 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh, NWB225_STATUS, 0);
374 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh, NWB225_STATUS, 1);
375 }
376
377 static int
378 nwb225_rop_wait(struct fbbm_devconfig *dc)
379 {
380 uint16_t status;
381 int i;
382
383 for (i = 0; i < NWB225_WAIT_MAX; i++) {
384 status = bus_space_read_2(dc->dc_bst, dc->dc_rcont_bsh,
385 NWB225_STATUS);
386 if ((status & NWB225_STATUS_BUSY) == 0)
387 return 0;
388 }
389
390 /* Reset ROP engine on timeout as NEWS-OS does */
391 nwb225_rop_reset(dc);
392 return ETIMEDOUT;
393 }
394
395 static void
396 nwb225_ctl_write(struct fbbm_devconfig *dc, uint16_t selector, uint16_t value)
397 {
398
399 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
400 NWB225_CTL_SELECT, selector);
401 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
402 NWB225_CTL_DATA, value);
403 }
404
405 static void
406 nwb225_rop_set_plane_mask(struct fbbm_devconfig *dc, uint32_t planemask)
407 {
408 uint8_t disabled_planes;
409 uint16_t hwmask;
410
411 disabled_planes = (uint8_t)~planemask;
412 hwmask = (uint16_t)disabled_planes << NWB225_PLANE_CTRL_SHIFT;
413 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
414 NWB225_PLANE_CTRL, hwmask);
415 }
416
417 static void
418 nwb225_rop_make_funcvec(struct fbbm_devconfig *dc, u_int logical_func,
419 uint32_t src1, uint32_t src0, uint8_t *funcvec)
420 {
421 uint8_t f_s0_d, f_s1_d;
422 uint8_t func_by_srcmap[4];
423 uint8_t src1_bit, src0_bit, src_map;
424 int i;
425
426 KASSERT(logical_func <= 0x0f);
427 KASSERT(dc->dc_nplanes == 4 || dc->dc_nplanes == 8);
428
429 /* F(0,D) */
430 f_s0_d = (logical_func >> 2) & 0x03;
431 /* F(1,D) */
432 f_s1_d = logical_func & 0x03;
433
434 func_by_srcmap[0] = (f_s0_d << 2) | f_s0_d;
435 func_by_srcmap[1] = (f_s1_d << 2) | f_s0_d;
436 func_by_srcmap[2] = (f_s0_d << 2) | f_s1_d;
437 func_by_srcmap[3] = (f_s1_d << 2) | f_s1_d;
438
439 for (i = 0; i < dc->dc_nplanes; i++) {
440 src1_bit = src1 & 0x01;
441 src0_bit = src0 & 0x01;
442 src_map = (src1_bit << 1) | src0_bit;
443 funcvec[i] = func_by_srcmap[src_map];
444 src1 >>= 1;
445 src0 >>= 1;
446 }
447 }
448
449 static void
450 nwb225_rop_funcvec_constant_s(struct fbbm_devconfig *dc, uint8_t *funcvec,
451 u_int s)
452 {
453 uint8_t logical_func, f_s0_d, f_s1_d, d_func, result;
454 int i;
455
456 KASSERT(dc->dc_nplanes == 4 || dc->dc_nplanes == 8);
457 KASSERT(s <= 1);
458
459 for (i = 0; i < dc->dc_nplanes; i++) {
460 logical_func = funcvec[i];
461 KASSERT(logical_func <= 0x0f);
462
463 /* F(0,D) */
464 f_s0_d = (logical_func >> 2) & 0x03;
465 /* F(1,D) */
466 f_s1_d = logical_func & 0x03;
467
468 d_func = (s == 0) ? f_s0_d : f_s1_d;
469 switch (d_func) {
470 case 0:
471 result = NWB225_ROP_LF_0;
472 break;
473 case 1:
474 result = NWB225_ROP_LF_D;
475 break;
476 case 2:
477 result = NWB225_ROP_LF_DI;
478 break;
479 case 3:
480 result = NWB225_ROP_LF_1;
481 break;
482 default:
483 KASSERT(false);
484 result = NWB225_ROP_LF_0;
485 break;
486 }
487 funcvec[i] = result;
488 }
489 }
490
491 static void
492 nwb225_rop_set_funcvec(struct fbbm_devconfig *dc, const uint8_t *funcvec)
493 {
494 uint8_t logical_func, hw_func;
495 int i;
496
497 for (i = 0; i < dc->dc_nplanes; i++) {
498 KASSERT(funcvec[i] <= 0x0f);
499 logical_func = funcvec[i];
500 hw_func = nwb225_fccnvtab[logical_func];
501 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
502 NWB225_ROP_FUNC(i), hw_func);
503 }
504 }
505
506 static int
507 nwb225_rect_valid(struct fbbm_devconfig *dc, int x, int y, int width,
508 int height)
509 {
510
511 if (x < 0 || y < 0 || width <= 0 || height <= 0)
512 return 0;
513 if (x >= dc->dc_fbwidth || y >= dc->dc_fbheight)
514 return 0;
515 if (width > dc->dc_fbwidth - x || height > dc->dc_fbheight - y)
516 return 0;
517
518 return 1;
519 }
520
521 static int
522 nwb225_rop_copy_rect(struct fbbm_devconfig *dc, int sx, int sy, int width,
523 int height, int dx, int dy, u_int logical_func)
524 {
525 uint8_t funcvec[NWB225_MAX_PLANES];
526 bus_size_t copy_mode;
527 bool reverse_x, reverse_y;
528 int src_x, src_y, dst_x, dst_y, limit_x;
529 int error;
530
531 if (logical_func > 0x0f)
532 return EINVAL;
533
534 if (nwb225_rect_valid(dc, sx, sy, width, height) == 0 ||
535 nwb225_rect_valid(dc, dx, dy, width, height) == 0)
536 return EINVAL;
537
538 error = nwb225_rop_wait(dc);
539 if (__predict_false(error != 0))
540 return error;
541
542 nwb225_rop_make_funcvec(dc, logical_func, dc->dc_planemask, 0, funcvec);
543 nwb225_rop_set_funcvec(dc, funcvec);
544 nwb225_rop_set_plane_mask(dc, dc->dc_planemask);
545
546 /* Wait again as NEWS-OS does */
547 error = nwb225_rop_wait(dc);
548 if (__predict_false(error != 0))
549 return error;
550
551 reverse_x = (sx < dx);
552 reverse_y = (sy < dy);
553 src_x = sx + (reverse_x ? width : 0);
554 dst_x = dx + (reverse_x ? width : 0);
555 limit_x = dx + (reverse_x ? 0 : width);
556 src_y = sy + (reverse_y ? height - 1 : 0);
557 dst_y = dy + (reverse_y ? height - 1 : 0);
558
559 if (reverse_x) {
560 if (reverse_y) {
561 copy_mode = NWB225_ROP_COPY_XR_YR;
562 } else {
563 copy_mode = NWB225_ROP_COPY_XR_YF;
564 }
565 } else {
566 if (reverse_y) {
567 copy_mode = NWB225_ROP_COPY_XF_YR;
568 } else {
569 copy_mode = NWB225_ROP_COPY_XF_YF;
570 }
571 }
572
573 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
574 copy_mode, 0);
575 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
576 NWB225_DST_ADDR(dst_y), dst_x);
577 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
578 NWB225_SRC_ADDR(src_y) | NWB225_ROP_ADDR_FLAG_SET_SHIFT, src_x);
579 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
580 NWB225_ROP_LIMIT(height) | NWB225_ROP_ADDR_FLAG_EXECUTE, limit_x);
581
582 /* Wait complete for polling ops */
583 error = nwb225_rop_wait(dc);
584
585 return error;
586 }
587
588 static int
589 nwb225_rop_fill_rect(struct fbbm_devconfig *dc, int x, int y, int width,
590 int height, uint32_t color)
591 {
592 uint8_t funcvec[NWB225_MAX_PLANES];
593 int error;
594
595 if (nwb225_rect_valid(dc, x, y, width, height) == 0)
596 return EINVAL;
597
598 error = nwb225_rop_wait(dc);
599 if (__predict_false(error != 0))
600 return error;
601
602 color &= dc->dc_planemask;
603 nwb225_rop_make_funcvec(dc, NWB225_ROP_LF_S, color, 0, funcvec);
604 nwb225_rop_funcvec_constant_s(dc, funcvec, 1);
605 nwb225_rop_set_plane_mask(dc, dc->dc_planemask);
606 nwb225_rop_set_funcvec(dc, funcvec);
607
608 /* Wait again as NEWS-OS does */
609 error = nwb225_rop_wait(dc);
610 if (__predict_false(error != 0))
611 return error;
612
613 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
614 NWB225_ROP_CONST_FILL, 0);
615 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
616 NWB225_DST_ADDR(0), 0);
617 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
618 NWB225_SRC_ADDR(0) | NWB225_ROP_ADDR_FLAG_SET_SHIFT, 0);
619 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
620 NWB225_DST_ADDR(y), x);
621 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
622 NWB225_ROP_LIMIT(height) | NWB225_ROP_ADDR_FLAG_EXECUTE, x + width);
623
624 /* Wait complete for polling ops */
625 error = nwb225_rop_wait(dc);
626
627 return error;
628 }
629
630 static int
631 nwb225_rop_hwrite(struct fbbm_devconfig *dc, const uint16_t *src_words,
632 int src_stride_words, int srcx, int srcy, int width, int height,
633 int dx, int dy, uint32_t foreground, uint32_t background)
634 {
635 uint8_t funcvec[NWB225_MAX_PLANES];
636 int source_word_offset, source_bit_offset;
637 int row_words, row_skip_words, row, word;
638 const uint16_t *sp;
639 int error;
640
641 if (src_words == NULL || src_stride_words <= 0 || srcx < 0 || srcy < 0)
642 return EINVAL;
643
644 if (nwb225_rect_valid(dc, dx, dy, width, height) == 0)
645 return EINVAL;
646
647 source_word_offset = srcx / NWB225_HWRITE_BITS_PER_WORD;
648 source_bit_offset = srcx % NWB225_HWRITE_BITS_PER_WORD;
649 row_words =
650 howmany(source_bit_offset + width, NWB225_HWRITE_BITS_PER_WORD);
651 if (source_word_offset + row_words > src_stride_words)
652 return EINVAL;
653
654 error = nwb225_rop_wait(dc);
655 if (__predict_false(error != 0))
656 return error;
657
658 foreground &= dc->dc_planemask;
659 background &= dc->dc_planemask;
660 nwb225_rop_make_funcvec(dc, NWB225_ROP_LF_S, foreground, background,
661 funcvec);
662 nwb225_rop_set_funcvec(dc, funcvec);
663 nwb225_rop_set_plane_mask(dc, dc->dc_planemask);
664
665 /* Wait again as NEWS-OS does */
666 error = nwb225_rop_wait(dc);
667 if (__predict_false(error != 0))
668 return error;
669
670 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
671 NWB225_DST_ADDR(dy), dx);
672 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
673 NWB225_SRC_ADDR(0) | NWB225_ROP_ADDR_FLAG_SET_SHIFT,
674 source_bit_offset);
675 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
676 NWB225_HWRITE_LIMIT(height) | NWB225_ROP_ADDR_FLAG_EXECUTE,
677 dx + width);
678
679 sp = src_words + (srcy * src_stride_words) + source_word_offset;
680 row_skip_words = src_stride_words - row_words;
681 for (row = 0; row < height; row++) {
682 for (word = 0; word < row_words; word++)
683 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
684 NWB225_HWRITE_DATA, *sp++);
685 sp += row_skip_words;
686 }
687
688 /* Wait complete for polling ops */
689 error = nwb225_rop_wait(dc);
690
691 return error;
692 }
693
694 static bus_size_t
695 nwb225_krom_ascii_offset(u_int c)
696 {
697 u_int index;
698
699 index = c - NWB225_KROM_ASCII_FIRST;
700 return ((index & 0xe0) << 9) | ((index & 0x1f) << 7);
701 }
702
703 static void
704 nwb225_krom_load_cell(struct fbbm_devconfig *dc, u_int c, uint16_t *cell)
705 {
706 bus_size_t offset;
707 int row;
708
709 memset(cell, 0, NWB225_CELL_HEIGHT * sizeof(*cell));
710 offset = nwb225_krom_ascii_offset(c);
711
712 /*
713 * The PROM renderer reads one 32-bit KROM row, keeps the upper word,
714 * masks its low four bits, and places the 24 glyph rows after four
715 * blank rows in the 16x30 cell.
716 */
717 for (row = 0; row < NWB225_FONT_HEIGHT; row++)
718 cell[NWB225_GLYPH_YOFFSET + row] =
719 bus_space_read_2(dc->dc_bst, dc->dc_krom_bsh,
720 offset + row * NWB225_KROM_ROWBYTES) &
721 NWB225_KROM_ASCII_MASK;
722 }
723
724 static int
725 nwb225_init_hardware(struct fbbm_devconfig *dc)
726 {
727 uint16_t status, value;
728 int i, component;
729
730 /*
731 * Use the cold-init sequence used by the NWB-225 routine in the
732 * NWS-1750 PROM. In particular, the second reset is intentional.
733 * The serial console cold-boot experiment required the init block
734 * followed by this reset before stable sync was established by CRTC.
735 */
736 nwb225_rop_reset(dc);
737
738 for (i = 0; i < __arraycount(nwb225_init_words); i++)
739 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
740 NWB225_INIT_BASE + i * sizeof(uint16_t),
741 nwb225_init_words[i]);
742
743 status = bus_space_read_2(dc->dc_bst, dc->dc_rcont_bsh, NWB225_STATUS);
744 if ((status & NWB225_STATUS_4PLANE) != 0)
745 dc->dc_nplanes = 4;
746 else
747 dc->dc_nplanes = 8;
748 dc->dc_planemask = (1U << dc->dc_nplanes) - 1;
749 dc->dc_dispver =
750 (status & NWB225_STATUS_DISPVER) >> NWB225_STATUS_DISPVER_SHIFT;
751
752 nwb225_ctl_write(dc, 4, dc->dc_planemask);
753 nwb225_ctl_write(dc, 5, 0);
754 nwb225_ctl_write(dc, 6, 0x40);
755 nwb225_ctl_write(dc, 7, 0);
756
757 nwb225_rop_reset(dc);
758
759 /* Complete the fixed PROM palette/control initialization */
760 for (i = 0; i < 256; i++) {
761 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
762 NWB225_PAL_INDEX, i);
763 for (component = 0; component < 3; component++) {
764 value = nwb225_prom_palette[i & 0x0f][component] << 4;
765 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
766 NWB225_PAL_DATA, value);
767 }
768 }
769
770 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh, NWB225_PLANE_CTRL, 0);
771
772 return nwb225_rop_wait(dc);
773 }
774
775 static void
776 fbbm_init_screen(struct fbbm_devconfig *dc)
777 {
778
779 dc->dc_fbwidth = NWB225_FB_WIDTH;
780 dc->dc_fbheight = NWB225_FB_HEIGHT;
781 dc->dc_width = NWB225_VIS_WIDTH;
782 dc->dc_height = NWB225_VIS_HEIGHT;
783
784 dc->dc_fontwidth = NWB225_FONT_WIDTH;
785 dc->dc_fontheight = NWB225_FONT_HEIGHT;
786 dc->dc_cellwidth = NWB225_CELL_WIDTH;
787 dc->dc_cellheight = NWB225_CELL_HEIGHT;
788
789 dc->dc_ncols = NWB225_TEXT_COLS;
790 dc->dc_nrows = NWB225_TEXT_ROWS;
791 dc->dc_xorigin = NWB225_TEXT_XORIGIN;
792 dc->dc_yorigin = NWB225_TEXT_YORIGIN;
793
794 dc->dc_wsscrdescr.name = "std";
795 dc->dc_wsscrdescr.ncols = dc->dc_ncols;
796 dc->dc_wsscrdescr.nrows = dc->dc_nrows;
797 dc->dc_wsscrdescr.textops = &fbbm_emulops;
798 dc->dc_wsscrdescr.fontwidth = dc->dc_cellwidth;
799 dc->dc_wsscrdescr.fontheight = dc->dc_cellheight;
800 dc->dc_wsscrdescr.capabilities = WSSCREEN_REVERSE;
801 dc->dc_wsscrdescr.modecookie = NULL;
802
803 dc->dc_cursoron = 0;
804 dc->dc_cursorrow = 0;
805 dc->dc_cursorcol = 0;
806 }
807
808 /*
809 * Clear the visible display region.
810 * Called from both normal attach and early cnattach.
811 */
812 static int
813 fbbm_clear_screen(struct fbbm_devconfig *dc)
814 {
815
816 return nwb225_rop_fill_rect(dc, 0, 0, dc->dc_width, dc->dc_height, 0);
817 }
818
819 static uint32_t
820 fbbm_attr_background(struct fbbm_devconfig *dc, long attr)
821 {
822
823 return (attr & WSATTR_REVERSE) != 0 ? dc->dc_planemask : 0;
824 }
825
826 /*
827 * wsdisplay_emulops functions
828 */
829 static void
830 fbbm_cursor(void *cookie, int on, int row, int col)
831 {
832 struct fbbm_devconfig *dc = cookie;
833 int x, y, error;
834
835 if (dc->dc_cursoron != 0) {
836 x = dc->dc_xorigin + dc->dc_cursorcol * dc->dc_cellwidth;
837 y = dc->dc_yorigin + dc->dc_cursorrow * dc->dc_cellheight;
838 error = nwb225_rop_copy_rect(dc, x, y, dc->dc_cellwidth,
839 dc->dc_cellheight, x, y, NWB225_ROP_LF_DI);
840 if (error != 0)
841 return;
842 dc->dc_cursoron = 0;
843 }
844
845 dc->dc_cursorrow = row;
846 dc->dc_cursorcol = col;
847 if (on == 0)
848 return;
849 if (row < 0 || row >= dc->dc_nrows || col < 0 || col >= dc->dc_ncols)
850 return;
851
852 x = dc->dc_xorigin + col * dc->dc_cellwidth;
853 y = dc->dc_yorigin + row * dc->dc_cellheight;
854 error = nwb225_rop_copy_rect(dc, x, y, dc->dc_cellwidth,
855 dc->dc_cellheight, x, y, NWB225_ROP_LF_DI);
856 if (error == 0)
857 dc->dc_cursoron = 1;
858 }
859
860 static int
861 fbbm_mapchar(void *cookie, int c, u_int *cp)
862 {
863
864 if (c < NWB225_KROM_ASCII_FIRST || c > NWB225_KROM_ASCII_LAST) {
865 *cp = ' ';
866 return 0;
867 }
868
869 *cp = c;
870 return 5;
871 }
872
873 static void
874 fbbm_putchar(void *cookie, int row, int col, u_int uc, long attr)
875 {
876 struct fbbm_devconfig *dc = cookie;
877 uint16_t cell[NWB225_CELL_HEIGHT];
878 uint32_t foreground, background;
879 int x, y;
880
881 if (__predict_false(row < 0 || row >= dc->dc_nrows ||
882 col < 0 || col >= dc->dc_ncols))
883 return;
884 if (uc < NWB225_KROM_ASCII_FIRST || uc > NWB225_KROM_ASCII_LAST)
885 uc = ' ';
886
887 nwb225_krom_load_cell(dc, uc, cell);
888 background = fbbm_attr_background(dc, attr);
889 foreground = (~background) & dc->dc_planemask;
890 x = dc->dc_xorigin + col * dc->dc_cellwidth;
891 y = dc->dc_yorigin + row * dc->dc_cellheight;
892
893 (void)nwb225_rop_hwrite(dc, cell, 1, 0, 0, dc->dc_cellwidth,
894 dc->dc_cellheight, x, y, foreground, background);
895 }
896
897 static void
898 fbbm_copycols(void *cookie, int row, int srccol, int dstcol, int ncols)
899 {
900 struct fbbm_devconfig *dc = cookie;
901 int sx, dx, y, width;
902
903 if (ncols <= 0 || row < 0 || row >= dc->dc_nrows)
904 return;
905 if (srccol < 0 || dstcol < 0 || srccol + ncols > dc->dc_ncols ||
906 dstcol + ncols > dc->dc_ncols)
907 return;
908 if (srccol == dstcol)
909 return;
910
911 sx = dc->dc_xorigin + srccol * dc->dc_cellwidth;
912 dx = dc->dc_xorigin + dstcol * dc->dc_cellwidth;
913 y = dc->dc_yorigin + row * dc->dc_cellheight;
914 width = ncols * dc->dc_cellwidth;
915 (void)nwb225_rop_copy_rect(dc, sx, y, width, dc->dc_cellheight,
916 dx, y, NWB225_ROP_LF_S);
917 }
918
919 static void
920 fbbm_erasecols(void *cookie, int row, int col, int ncols, long attr)
921 {
922 struct fbbm_devconfig *dc = cookie;
923 uint32_t background;
924 int x, y, width;
925
926 if (ncols <= 0 || row < 0 || row >= dc->dc_nrows)
927 return;
928 if (col < 0 || col + ncols > dc->dc_ncols)
929 return;
930
931 x = dc->dc_xorigin + col * dc->dc_cellwidth;
932 y = dc->dc_yorigin + row * dc->dc_cellheight;
933 width = ncols * dc->dc_cellwidth;
934 background = fbbm_attr_background(dc, attr);
935 (void)nwb225_rop_fill_rect(dc, x, y, width, dc->dc_cellheight,
936 background);
937 }
938
939 static void
940 fbbm_copyrows(void *cookie, int srcrow, int dstrow, int nrows)
941 {
942 struct fbbm_devconfig *dc = cookie;
943 int x, sy, dy, height;
944
945 if (nrows <= 0 || srcrow < 0 || dstrow < 0 ||
946 srcrow + nrows > dc->dc_nrows || dstrow + nrows > dc->dc_nrows)
947 return;
948 if (srcrow == dstrow)
949 return;
950
951 x = dc->dc_xorigin;
952 sy = dc->dc_yorigin + srcrow * dc->dc_cellheight;
953 dy = dc->dc_yorigin + dstrow * dc->dc_cellheight;
954 height = nrows * dc->dc_cellheight;
955 (void)nwb225_rop_copy_rect(dc, x, sy,
956 dc->dc_ncols * dc->dc_cellwidth, height, x, dy, NWB225_ROP_LF_S);
957 }
958
959 static void
960 fbbm_eraserows(void *cookie, int row, int nrows, long attr)
961 {
962 struct fbbm_devconfig *dc = cookie;
963 uint32_t background;
964 int x, y, height;
965
966 if (nrows <= 0 || row < 0 || row + nrows > dc->dc_nrows)
967 return;
968
969 x = dc->dc_xorigin;
970 y = dc->dc_yorigin + row * dc->dc_cellheight;
971 height = nrows * dc->dc_cellheight;
972 background = fbbm_attr_background(dc, attr);
973 (void)nwb225_rop_fill_rect(dc, x, y,
974 dc->dc_ncols * dc->dc_cellwidth, height, background);
975 }
976
977 static int
978 fbbm_allocattr(void *cookie, int fg, int bg, int flags, long *attrp)
979 {
980
981 if ((flags & ~WSATTR_REVERSE) != 0)
982 return EINVAL;
983
984 *attrp = flags & WSATTR_REVERSE;
985 return 0;
986 }
987
988 /*
989 * wsdisplay_accessops functions
990 */
991 static int
992 fbbm_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
993 {
994 struct fbbm_softc *sc = v;
995 struct fbbm_devconfig *dc = sc->sc_dc;
996 struct wsdisplay_fbinfo *fbinfo;
997
998 switch (cmd) {
999 case WSDISPLAYIO_GTYPE:
1000 *(u_int *)data = WSDISPLAY_TYPE_NWB225;
1001 return 0;
1002
1003 case WSDISPLAYIO_GINFO:
1004 fbinfo = data;
1005 fbinfo->height = dc->dc_height;
1006 fbinfo->width = dc->dc_width;
1007 fbinfo->depth = dc->dc_nplanes;
1008 fbinfo->cmsize = 0;
1009 return 0;
1010
1011 case WSDISPLAYIO_SMODE:
1012 sc->sc_wsmode = *(int *)data;
1013 return 0;
1014
1015 default:
1016 break;
1017 }
1018
1019 return EPASSTHROUGH;
1020 }
1021
1022 static int
1023 fbbm_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
1024 int *ccolp, int *crowp, long *attrp)
1025 {
1026 struct fbbm_softc *sc = v;
1027 struct fbbm_devconfig *dc = sc->sc_dc;
1028 long attr;
1029 int error;
1030
1031 KASSERT(type == &dc->dc_wsscrdescr);
1032
1033 if (sc->sc_nscreens != 0)
1034 return ENOMEM;
1035
1036 error = fbbm_allocattr(dc, 0, 0, 0, &attr);
1037 if (error != 0)
1038 return error;
1039
1040 *cookiep = dc;
1041 *ccolp = 0;
1042 *crowp = 0;
1043 *attrp = attr;
1044 sc->sc_nscreens = 1;
1045
1046 return 0;
1047 }
1048
1049 static void
1050 fbbm_free_screen(void *v, void *cookie)
1051 {
1052 struct fbbm_softc *sc = v;
1053
1054 KASSERT(sc->sc_nscreens == 1);
1055 KASSERT(cookie == sc->sc_dc);
1056 KASSERT(sc->sc_dc != &fbbm_console_dc);
1057 sc->sc_nscreens = 0;
1058 }
1059
1060 static int
1061 fbbm_show_screen(void *v, void *cookie, int waitok,
1062 void (*cb)(void *, int, int), void *cbarg)
1063 {
1064
1065 return 0;
1066 }
1067
1068 int
1069 fbbm_cnattach(void)
1070 {
1071 struct fbbm_devconfig *dc;
1072 long attr;
1073
1074 if (fbbm_console_initialized())
1075 return 0;
1076
1077 dc = &fbbm_console_dc;
1078 memset(dc, 0, sizeof(*dc));
1079 if (fbbm_probe(NEWS68K_BUS_SPACE_EIO, NWB225_RCONT_BASE) == 0)
1080 return ENXIO;
1081
1082 if (nwb225_map(dc, NEWS68K_BUS_SPACE_EIO, NWB225_RCONT_BASE) != 0)
1083 goto out_clear;
1084
1085 if (nwb225_init_hardware(dc) != 0)
1086 goto out_unmap;
1087
1088 fbbm_init_screen(dc);
1089 if (fbbm_clear_screen(dc) != 0)
1090 goto out_unmap;
1091
1092 if (fbbm_allocattr(dc, 0, 0, 0, &attr))
1093 goto out_unmap;
1094
1095 wsdisplay_cnattach(&dc->dc_wsscrdescr, dc, 0, 0, attr);
1096 return 0;
1097
1098 out_unmap:
1099 nwb225_unmap(dc);
1100 out_clear:
1101 memset(dc, 0, sizeof(*dc));
1102 return 1;
1103 }
1104 /* $NetBSD: fbbm.c,v 1.1 2026/09/20 10:29:11 tsutsui Exp $ */
1105
1106 /*-
1107 * Copyright (c) 2026 Izumi Tsutsui. All rights reserved.
1108 *
1109 * Redistribution and use in source and binary forms, with or without
1110 * modification, are permitted provided that the following conditions
1111 * are met:
1112 * 1. Redistributions of source code must retain the above copyright
1113 * notice, this list of conditions and the following disclaimer.
1114 * 2. Redistributions in binary form must reproduce the above copyright
1115 * notice, this list of conditions and the following disclaimer in the
1116 * documentation and/or other materials provided with the distribution.
1117 *
1118 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1119 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1120 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1121 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1122 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1123 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
1124 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
1125 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1126 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
1127 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1128 */
1129
1130 #include <sys/cdefs.h>
1131 __KERNEL_RCSID(0, "$NetBSD: fbbm.c,v 1.1 2026/09/20 10:29:11 tsutsui Exp $");
1132
1133 #include <sys/param.h>
1134 #include <sys/device.h>
1135 #include <sys/errno.h>
1136 #include <sys/ioctl.h>
1137 #include <sys/kmem.h>
1138 #include <sys/systm.h>
1139
1140 #include <machine/bus.h>
1141
1142 #include <news68k/dev/hbvar.h>
1143 #include <news68k/dev/nwb225reg.h>
1144
1145 #include <dev/wscons/wsconsio.h>
1146 #include <dev/wscons/wsdisplayvar.h>
1147
1148 #define NWB225_WAIT_MAX 100000
1149
1150 struct fbbm_devconfig {
1151 bus_space_tag_t dc_bst;
1152 bus_space_handle_t dc_rcont_bsh;
1153 bus_space_handle_t dc_krom_bsh;
1154
1155 int dc_nplanes;
1156 uint32_t dc_planemask;
1157 int dc_dispver;
1158
1159 int dc_fbwidth;
1160 int dc_fbheight;
1161 int dc_width;
1162 int dc_height;
1163
1164 int dc_fontwidth;
1165 int dc_fontheight;
1166 int dc_cellwidth;
1167 int dc_cellheight;
1168
1169 int dc_ncols;
1170 int dc_nrows;
1171 int dc_xorigin;
1172 int dc_yorigin;
1173
1174 int dc_cursoron;
1175 int dc_cursorrow;
1176 int dc_cursorcol;
1177
1178 struct wsscreen_descr dc_wsscrdescr;
1179 };
1180
1181 struct fbbm_softc {
1182 device_t sc_dev;
1183 struct fbbm_devconfig *sc_dc;
1184 int sc_nscreens;
1185 const struct wsscreen_descr *sc_scrdescs[1];
1186 struct wsscreen_list sc_scrlist;
1187 };
1188
1189 static int fbbm_match(device_t, cfdata_t, void *);
1190 static void fbbm_attach(device_t, device_t, void *);
1191
1192 static int nwb225_map(struct fbbm_devconfig *, bus_space_tag_t, bus_addr_t);
1193 static void nwb225_unmap(struct fbbm_devconfig *);
1194 static void nwb225_rop_reset(struct fbbm_devconfig *);
1195 static int nwb225_rop_wait(struct fbbm_devconfig *);
1196 static void nwb225_ctl_write(struct fbbm_devconfig *, uint16_t, uint16_t);
1197 static void nwb225_rop_set_plane_mask(struct fbbm_devconfig *, uint32_t);
1198 static void nwb225_rop_make_funcvec(struct fbbm_devconfig *, unsigned int,
1199 uint32_t, uint32_t, uint8_t *);
1200 static void nwb225_rop_setfunc(struct fbbm_devconfig *, const uint8_t *);
1201 static void nwb225_rop_cinit(struct fbbm_devconfig *, const uint8_t *,
1202 uint32_t, unsigned int);
1203 static int nwb225_rop_copy_rect(struct fbbm_devconfig *, int, int, int, int,
1204 int, int, unsigned int);
1205 static int nwb225_rop_fill_rect(struct fbbm_devconfig *, int, int, int, int,
1206 uint32_t);
1207 static int nwb225_rop_hwrite(struct fbbm_devconfig *, const uint16_t *, int,
1208 int, int, int, int, int, int, uint32_t, uint32_t);
1209 static bus_size_t nwb225_krom_ascii_offset(unsigned int);
1210 static void nwb225_krom_load_cell(struct fbbm_devconfig *, unsigned int,
1211 uint16_t *);
1212 static int nwb225_init_hardware(struct fbbm_devconfig *);
1213
1214 static void fbbm_init_screen(struct fbbm_devconfig *);
1215 static int fbbm_clear_screen(struct fbbm_devconfig *);
1216 static void fbbm_cursor(void *, int, int, int);
1217 static int fbbm_mapchar(void *, int, unsigned int *);
1218 static void fbbm_putchar(void *, int, int, u_int, long);
1219 static void fbbm_copycols(void *, int, int, int, int);
1220 static void fbbm_erasecols(void *, int, int, int, long);
1221 static void fbbm_copyrows(void *, int, int, int);
1222 static void fbbm_eraserows(void *, int, int, long);
1223 static int fbbm_allocattr(void *, int, int, int, long *);
1224 static int fbbm_ioctl(void *, void *, u_long, void *, int, struct lwp *);
1225 static int fbbm_alloc_screen(void *, const struct wsscreen_descr *, void **,
1226 int *, int *, long *);
1227 static void fbbm_free_screen(void *, void *);
1228 static int fbbm_show_screen(void *, void *, int, void (*)(void *, int, int),
1229 void *);
1230
1231 CFATTACH_DECL_NEW(fbbm, sizeof(struct fbbm_softc),
1232 fbbm_match, fbbm_attach, NULL, NULL);
1233
1234 static const struct wsdisplay_emulops fbbm_emulops = {
1235 .cursor = fbbm_cursor,
1236 .mapchar = fbbm_mapchar,
1237 .putchar = fbbm_putchar,
1238 .copycols = fbbm_copycols,
1239 .erasecols = fbbm_erasecols,
1240 .copyrows = fbbm_copyrows,
1241 .eraserows = fbbm_eraserows,
1242 .allocattr = fbbm_allocattr,
1243 .replaceattr = NULL,
1244 };
1245
1246 static const struct wsdisplay_accessops fbbm_accessops = {
1247 .ioctl = fbbm_ioctl,
1248 .mmap = NULL,
1249 .alloc_screen = fbbm_alloc_screen,
1250 .free_screen = fbbm_free_screen,
1251 .show_screen = fbbm_show_screen,
1252 .load_font = NULL,
1253 .pollc = NULL,
1254 .scroll = NULL,
1255 };
1256
1257 /* Sony FBBM logical Boolean functions used by the initial text backend. */
1258 #define NWB225_BF_0 0x0
1259 #define NWB225_BF_S 0x3
1260 #define NWB225_BF_DI 0xa
1261 #define NWB225_BF_1 0xf
1262
1263 /*
1264 * Logical FBBM function to 51X hardware function conversion recovered from
1265 * NEWS-OS fbbm_51x.o.
1266 */
1267 static const uint8_t nwb225_fccnvtab[16] = {
1268 0x03, 0x0b, 0x07, 0x0f, 0x02, 0x0a, 0x06, 0x0e,
1269 0x01, 0x09, 0x05, 0x0d, 0x00, 0x08, 0x04, 0x0c,
1270 };
1271
1272 /*
1273 * Function conversion for a constant 0/1 source, indexed by
1274 * [logical_function][source_bit].
1275 */
1276 static const uint8_t nwb225_func01tab[16][2] = {
1277 { 0x03, 0x03 }, { 0x03, 0x0a }, { 0x03, 0x05 }, { 0x03, 0x0c },
1278 { 0x0a, 0x03 }, { 0x0a, 0x0a }, { 0x0a, 0x05 }, { 0x0a, 0x0c },
1279 { 0x05, 0x03 }, { 0x05, 0x0a }, { 0x05, 0x05 }, { 0x05, 0x0c },
1280 { 0x0c, 0x03 }, { 0x0c, 0x0a }, { 0x0c, 0x05 }, { 0x0c, 0x0c },
1281 };
1282
1283 /*
1284 * Fixed initialization words written by the NWS-1750 PROM and NEWS-OS
1285 * 51X setup. Their individual timing/control semantics are intentionally
1286 * not inferred here.
1287 */
1288 static const uint16_t nwb225_init_words[] = {
1289 0x0400, 0x0002, 0x0005, 0x00d8,
1290 0x0000, 0x0006, 0x0000,
1291 };
1292
1293 /*
1294 * 4-bit component values from the NWS-1750 PROM NWB-225 module. The PROM
1295 * repeats this 16-entry table through all 256 palette indices and writes
1296 * each component after shifting it left by four bits.
1297 */
1298 static const uint8_t nwb225_prom_palette[16][3] = {
1299 { 0, 0, 0 }, { 0, 0, 4 },
1300 { 0, 4, 0 }, { 0, 4, 4 },
1301 { 4, 0, 0 }, { 4, 0, 4 },
1302 { 4, 4, 0 }, { 4, 4, 4 },
1303 { 8, 8, 8 }, { 0, 0, 15 },
1304 { 0, 15, 0 }, { 0, 15, 15 },
1305 { 15, 0, 0 }, { 15, 0, 15 },
1306 { 15, 15, 0 }, { 15, 15, 15 },
1307 };
1308
1309 static int
1310 fbbm_match(device_t parent, cfdata_t cf, void *aux)
1311 {
1312 struct hb_attach_args *ha = aux;
1313 bus_space_handle_t bsh;
1314 int rv;
1315
1316 __USE(parent);
1317 __USE(cf);
1318
1319 if (strcmp(ha->ha_name, "fbbm") != 0)
1320 return 0;
1321 if (ha->ha_address != NWB225_RCONT_BASE)
1322 return 0;
1323
1324 if (bus_space_map(ha->ha_bust, ha->ha_address, NWB225_RCONT_SIZE,
1325 0, &bsh) != 0)
1326 return 0;
1327
1328 /* NEWS-OS fb225_probe() used a byte-sized badaddr() at this base. */
1329 rv = news68k_bus_space_probe(ha->ha_bust, bsh, 0, 1);
1330 bus_space_unmap(ha->ha_bust, bsh, NWB225_RCONT_SIZE);
1331
1332 return rv;
1333 }
1334
1335 static void
1336 fbbm_attach(device_t parent, device_t self, void *aux)
1337 {
1338 struct fbbm_softc *sc = device_private(self);
1339 struct hb_attach_args *ha = aux;
1340 struct fbbm_devconfig *dc;
1341 struct wsemuldisplaydev_attach_args waa;
1342 int error;
1343
1344 __USE(parent);
1345
1346 sc->sc_dev = self;
1347
1348 dc = kmem_zalloc(sizeof(*dc), KM_SLEEP);
1349 error = nwb225_map(dc, ha->ha_bust, ha->ha_address);
1350 if (error != 0) {
1351 aprint_error_dev(self, "unable to map device registers: %d\n",
1352 error);
1353 kmem_free(dc, sizeof(*dc));
1354 return;
1355 }
1356
1357 error = nwb225_init_hardware(dc);
1358 if (error != 0) {
1359 aprint_error_dev(self, "controller initialization failed: %d\n",
1360 error);
1361 nwb225_unmap(dc);
1362 kmem_free(dc, sizeof(*dc));
1363 return;
1364 }
1365
1366 fbbm_init_screen(dc);
1367 error = fbbm_clear_screen(dc);
1368 if (error != 0) {
1369 aprint_error_dev(self, "unable to clear text screen: %d\n", error);
1370 nwb225_unmap(dc);
1371 kmem_free(dc, sizeof(*dc));
1372 return;
1373 }
1374
1375 sc->sc_dc = dc;
1376 sc->sc_nscreens = 0;
1377 sc->sc_scrdescs[0] = &dc->dc_wsscrdescr;
1378 sc->sc_scrlist.nscreens = __arraycount(sc->sc_scrdescs);
1379 sc->sc_scrlist.screens = sc->sc_scrdescs;
1380
1381 aprint_normal(": NWB-225 compatible, %d x %d, %d planes, "
1382 "display version %d\n", dc->dc_width, dc->dc_height,
1383 dc->dc_nplanes, dc->dc_dispver);
1384
1385 waa.console = 0;
1386 waa.scrdata = &sc->sc_scrlist;
1387 waa.accessops = &fbbm_accessops;
1388 waa.accesscookie = sc;
1389
1390 config_found(self, &waa, wsemuldisplaydevprint, CFARGS_NONE);
1391 }
1392
1393 static int
1394 nwb225_map(struct fbbm_devconfig *dc, bus_space_tag_t bst,
1395 bus_addr_t rcont_addr)
1396 {
1397 int error;
1398
1399 dc->dc_bst = bst;
1400
1401 error = bus_space_map(bst, rcont_addr, NWB225_RCONT_SIZE, 0,
1402 &dc->dc_rcont_bsh);
1403 if (error != 0)
1404 return error;
1405
1406 error = bus_space_map(bst, NWB225_KROM_BASE, NWB225_KROM_SIZE, 0,
1407 &dc->dc_krom_bsh);
1408 if (error != 0) {
1409 bus_space_unmap(bst, dc->dc_rcont_bsh, NWB225_RCONT_SIZE);
1410 return error;
1411 }
1412
1413 return 0;
1414 }
1415
1416 static void
1417 nwb225_unmap(struct fbbm_devconfig *dc)
1418 {
1419
1420 bus_space_unmap(dc->dc_bst, dc->dc_krom_bsh, NWB225_KROM_SIZE);
1421 bus_space_unmap(dc->dc_bst, dc->dc_rcont_bsh, NWB225_RCONT_SIZE);
1422 }
1423
1424 static void
1425 nwb225_rop_reset(struct fbbm_devconfig *dc)
1426 {
1427
1428 /* fb51X_rop_reset() and the PROM both perform this 0 -> 1 sequence. */
1429 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh, NWB225_STATUS, 0);
1430 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh, NWB225_STATUS, 1);
1431 }
1432
1433 static int
1434 nwb225_rop_wait(struct fbbm_devconfig *dc)
1435 {
1436 uint16_t status;
1437 int i;
1438
1439 for (i = 0; i < NWB225_WAIT_MAX; i++) {
1440 status = bus_space_read_2(dc->dc_bst, dc->dc_rcont_bsh,
1441 NWB225_STATUS);
1442 if ((status & NWB225_STATUS_BUSY) == 0)
1443 return 0;
1444 }
1445
1446 /* Match the NEWS-OS recovery action, but report failure to K1 attach. */
1447 nwb225_rop_reset(dc);
1448 return ETIMEDOUT;
1449 }
1450
1451 static void
1452 nwb225_ctl_write(struct fbbm_devconfig *dc, uint16_t selector,
1453 uint16_t value)
1454 {
1455
1456 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
1457 NWB225_CTL_SELECT, selector);
1458 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
1459 NWB225_CTL_DATA, value);
1460 }
1461
1462 static void
1463 nwb225_rop_set_plane_mask(struct fbbm_devconfig *dc, uint32_t planemask)
1464 {
1465 uint16_t hwmask;
1466
1467 hwmask = (uint16_t)(~(planemask << 8) & 0xff00);
1468 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
1469 NWB225_PLANE_CTRL, hwmask);
1470 }
1471
1472 static void
1473 nwb225_rop_make_funcvec(struct fbbm_devconfig *dc, unsigned int func,
1474 uint32_t fore, uint32_t aux, uint8_t *funcvec)
1475 {
1476 uint8_t tmp[4];
1477 unsigned int i, index;
1478
1479 func &= 0x0f;
1480 tmp[0] = (func & 0x0c) | (func >> 2);
1481 tmp[1] = (func >> 2) | ((func << 2) & 0x0c);
1482 tmp[2] = func;
1483 tmp[3] = ((func << 2) & 0x0c) | (func & 0x03);
1484
1485 for (i = 0; i < (unsigned int)dc->dc_nplanes; i++) {
1486 index = ((fore & 1) << 1) | (aux & 1);
1487 funcvec[i] = tmp[index];
1488 fore >>= 1;
1489 aux >>= 1;
1490 }
1491 }
1492
1493 static void
1494 nwb225_rop_setfunc(struct fbbm_devconfig *dc, const uint8_t *funcvec)
1495 {
1496 unsigned int i;
1497
1498 for (i = 0; i < (unsigned int)dc->dc_nplanes; i++)
1499 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
1500 NWB225_ROP_FUNC + i * sizeof(uint16_t),
1501 nwb225_fccnvtab[funcvec[i] & 0x0f]);
1502 }
1503
1504 static void
1505 nwb225_rop_cinit(struct fbbm_devconfig *dc, const uint8_t *funcvec,
1506 uint32_t planemask, unsigned int source_bit)
1507 {
1508 unsigned int i;
1509
1510 nwb225_rop_set_plane_mask(dc, planemask);
1511 source_bit &= 1;
1512 for (i = 0; i < (unsigned int)dc->dc_nplanes; i++)
1513 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
1514 NWB225_ROP_FUNC + i * sizeof(uint16_t),
1515 nwb225_func01tab[funcvec[i] & 0x0f][source_bit]);
1516 }
1517
1518 static int
1519 nwb225_rect_valid(struct fbbm_devconfig *dc, int x, int y, int width,
1520 int height)
1521 {
1522
1523 if (x < 0 || y < 0 || width <= 0 || height <= 0)
1524 return 0;
1525 if (x >= dc->dc_fbwidth || y >= dc->dc_fbheight)
1526 return 0;
1527 if (width > dc->dc_fbwidth - x || height > dc->dc_fbheight - y)
1528 return 0;
1529
1530 return 1;
1531 }
1532
1533 static int
1534 nwb225_rop_copy_rect(struct fbbm_devconfig *dc, int sx, int sy, int width,
1535 int height, int dx, int dy, unsigned int func)
1536 {
1537 uint8_t funcvec[8];
1538 bus_size_t command;
1539 int error;
1540
1541 if (width <= 0 || height <= 0)
1542 return 0;
1543 if (nwb225_rect_valid(dc, sx, sy, width, height) == 0 ||
1544 nwb225_rect_valid(dc, dx, dy, width, height) == 0)
1545 return EINVAL;
1546
1547 error = nwb225_rop_wait(dc);
1548 if (error != 0)
1549 return error;
1550
1551 nwb225_rop_make_funcvec(dc, func, dc->dc_planemask, 0, funcvec);
1552 nwb225_rop_setfunc(dc, funcvec);
1553 nwb225_rop_set_plane_mask(dc, dc->dc_planemask);
1554
1555 if (sx >= dx) {
1556 if (sy >= dy) {
1557 command = NWB225_ROP_COPY_FF;
1558 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
1559 command, 0);
1560 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
1561 NWB225_DST_X + dy * sizeof(uint16_t), dx);
1562 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
1563 NWB225_SRC_X + sy * sizeof(uint16_t), sx);
1564 } else {
1565 command = NWB225_ROP_COPY_FR;
1566 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
1567 command, 0);
1568 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
1569 NWB225_DST_X + (dy + height - 1) *
1570 sizeof(uint16_t), dx);
1571 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
1572 NWB225_SRC_X + (sy + height - 1) *
1573 sizeof(uint16_t), sx);
1574 }
1575 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
1576 NWB225_ROP_EDGE + (height - 1) * sizeof(uint16_t),
1577 dx + width);
1578 } else {
1579 if (sy >= dy) {
1580 command = NWB225_ROP_COPY_RF;
1581 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
1582 command, 0);
1583 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
1584 NWB225_DST_X + dy * sizeof(uint16_t), dx + width);
1585 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
1586 NWB225_SRC_X + sy * sizeof(uint16_t), sx + width);
1587 } else {
1588 command = NWB225_ROP_COPY_RR;
1589 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
1590 command, 0);
1591 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
1592 NWB225_DST_X + (dy + height - 1) *
1593 sizeof(uint16_t), dx + width);
1594 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
1595 NWB225_SRC_X + (sy + height - 1) *
1596 sizeof(uint16_t), sx + width);
1597 }
1598 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
1599 NWB225_ROP_EDGE + (height - 1) * sizeof(uint16_t), dx);
1600 }
1601
1602 return nwb225_rop_wait(dc);
1603 }
1604
1605 static int
1606 nwb225_rop_fill_rect(struct fbbm_devconfig *dc, int x, int y, int width,
1607 int height, uint32_t color)
1608 {
1609 uint8_t funcvec[8];
1610 int error;
1611
1612 if (width <= 0 || height <= 0)
1613 return 0;
1614 if (nwb225_rect_valid(dc, x, y, width, height) == 0)
1615 return EINVAL;
1616
1617 error = nwb225_rop_wait(dc);
1618 if (error != 0)
1619 return error;
1620
1621 color &= dc->dc_planemask;
1622 nwb225_rop_make_funcvec(dc, NWB225_BF_S, color, 0, funcvec);
1623 nwb225_rop_cinit(dc, funcvec, dc->dc_planemask, 1);
1624
1625 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
1626 NWB225_ROP_CLEAR, 0);
1627 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh, NWB225_DST_X, 0);
1628 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh, NWB225_SRC_X, 0);
1629 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
1630 NWB225_DST_X + y * sizeof(uint16_t), x);
1631 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
1632 NWB225_ROP_EDGE + (height - 1) * sizeof(uint16_t), x + width);
1633
1634 return nwb225_rop_wait(dc);
1635 }
1636
1637 static int
1638 nwb225_rop_hwrite(struct fbbm_devconfig *dc, const uint16_t *src,
1639 int srcwidth, int srcx, int srcy, int width, int height, int dx, int dy,
1640 uint32_t foreground, uint32_t background)
1641 {
1642 uint8_t funcvec[8];
1643 const uint16_t *sp;
1644 int nwords, skip, row, word, error;
1645
1646 if (src == NULL || srcwidth <= 0 || srcx < 0 || srcy < 0 ||
1647 width <= 0 || height <= 0)
1648 return EINVAL;
1649 if (nwb225_rect_valid(dc, dx, dy, width, height) == 0)
1650 return EINVAL;
1651
1652 nwords = ((srcx & 15) + width + 15) >> 4;
1653 if ((srcx >> 4) + nwords > srcwidth)
1654 return EINVAL;
1655
1656 error = nwb225_rop_wait(dc);
1657 if (error != 0)
1658 return error;
1659
1660 foreground &= dc->dc_planemask;
1661 background &= dc->dc_planemask;
1662 nwb225_rop_make_funcvec(dc, NWB225_BF_S, foreground, background,
1663 funcvec);
1664 nwb225_rop_setfunc(dc, funcvec);
1665 nwb225_rop_set_plane_mask(dc, dc->dc_planemask);
1666
1667 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
1668 NWB225_DST_X + dy * sizeof(uint16_t), dx);
1669 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
1670 NWB225_SRC_X, srcx & 15);
1671 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
1672 NWB225_HWRITE_EDGE + (height - 1) * sizeof(uint16_t), dx + width);
1673
1674 sp = src + srcy * srcwidth + (srcx >> 4);
1675 skip = srcwidth - nwords;
1676 for (row = 0; row < height; row++) {
1677 for (word = 0; word < nwords; word++)
1678 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
1679 NWB225_HWRITE_DATA, *sp++);
1680 sp += skip;
1681 }
1682
1683 return nwb225_rop_wait(dc);
1684 }
1685
1686 static bus_size_t
1687 nwb225_krom_ascii_offset(unsigned int c)
1688 {
1689 unsigned int index;
1690
1691 index = c - NWB225_KROM_ASCII_FIRST;
1692 return ((index & 0xe0) << 9) | ((index & 0x1f) << 7);
1693 }
1694
1695 static void
1696 nwb225_krom_load_cell(struct fbbm_devconfig *dc, unsigned int c,
1697 uint16_t *cell)
1698 {
1699 bus_size_t offset;
1700 int row;
1701
1702 memset(cell, 0, NWB225_CELL_HEIGHT * sizeof(*cell));
1703 offset = nwb225_krom_ascii_offset(c);
1704
1705 /*
1706 * The PROM renderer reads one 32-bit KROM row, keeps the upper word,
1707 * masks its low four bits, and places the 24 glyph rows after four
1708 * blank rows in the 16x30 cell.
1709 */
1710 for (row = 0; row < NWB225_FONT_HEIGHT; row++)
1711 cell[NWB225_GLYPH_YOFFSET + row] =
1712 bus_space_read_2(dc->dc_bst, dc->dc_krom_bsh,
1713 offset + row * NWB225_KROM_ROWBYTES) &
1714 NWB225_KROM_ASCII_MASK;
1715 }
1716
1717 static int
1718 nwb225_init_hardware(struct fbbm_devconfig *dc)
1719 {
1720 uint16_t status, value;
1721 unsigned int i, component;
1722
1723 /*
1724 * Keep the cold-init sequence in the same order as the NWS-1750 PROM
1725 * NWB-225 module. In particular, the second reset is intentional: the
1726 * serial-console cold-boot experiment required the init block followed
1727 * by this reset before stable sync was established.
1728 */
1729 nwb225_rop_reset(dc);
1730
1731 for (i = 0; i < __arraycount(nwb225_init_words); i++)
1732 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
1733 NWB225_INIT_BASE + i * sizeof(uint16_t),
1734 nwb225_init_words[i]);
1735
1736 status = bus_space_read_2(dc->dc_bst, dc->dc_rcont_bsh,
1737 NWB225_STATUS);
1738 if ((status & NWB225_STATUS_4PLANE) != 0)
1739 dc->dc_nplanes = 4;
1740 else
1741 dc->dc_nplanes = 8;
1742 dc->dc_planemask = (1U << dc->dc_nplanes) - 1;
1743 dc->dc_dispver =
1744 (status & NWB225_STATUS_DISPVER) >> NWB225_STATUS_DISPVER_SHIFT;
1745
1746 nwb225_ctl_write(dc, 4, dc->dc_planemask);
1747 nwb225_ctl_write(dc, 5, 0);
1748 nwb225_ctl_write(dc, 6, 0x40);
1749 nwb225_ctl_write(dc, 7, 0);
1750
1751 nwb225_rop_reset(dc);
1752
1753 /* Complete the fixed PROM palette/control initialization. */
1754 for (i = 0; i < 256; i++) {
1755 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
1756 NWB225_PAL_INDEX, i);
1757 for (component = 0; component < 3; component++) {
1758 value = nwb225_prom_palette[i & 0x0f][component] << 4;
1759 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
1760 NWB225_PAL_DATA, value);
1761 }
1762 }
1763
1764 bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
1765 NWB225_PLANE_CTRL, 0);
1766
1767 return nwb225_rop_wait(dc);
1768 }
1769
1770 static void
1771 fbbm_init_screen(struct fbbm_devconfig *dc)
1772 {
1773
1774 dc->dc_fbwidth = NWB225_FB_WIDTH;
1775 dc->dc_fbheight = NWB225_FB_HEIGHT;
1776 dc->dc_width = NWB225_VIS_WIDTH;
1777 dc->dc_height = NWB225_VIS_HEIGHT;
1778
1779 dc->dc_fontwidth = NWB225_FONT_WIDTH;
1780 dc->dc_fontheight = NWB225_FONT_HEIGHT;
1781 dc->dc_cellwidth = NWB225_CELL_WIDTH;
1782 dc->dc_cellheight = NWB225_CELL_HEIGHT;
1783
1784 dc->dc_ncols = NWB225_TEXT_COLS;
1785 dc->dc_nrows = NWB225_TEXT_ROWS;
1786 dc->dc_xorigin = NWB225_TEXT_XORIGIN;
1787 dc->dc_yorigin = NWB225_TEXT_YORIGIN;
1788
1789 dc->dc_wsscrdescr.name = "std";
1790 dc->dc_wsscrdescr.ncols = dc->dc_ncols;
1791 dc->dc_wsscrdescr.nrows = dc->dc_nrows;
1792 dc->dc_wsscrdescr.textops = &fbbm_emulops;
1793 dc->dc_wsscrdescr.fontwidth = dc->dc_cellwidth;
1794 dc->dc_wsscrdescr.fontheight = dc->dc_cellheight;
1795 dc->dc_wsscrdescr.capabilities = WSSCREEN_REVERSE;
1796 dc->dc_wsscrdescr.modecookie = NULL;
1797
1798 dc->dc_cursoron = 0;
1799 dc->dc_cursorrow = 0;
1800 dc->dc_cursorcol = 0;
1801 }
1802
1803 /*
1804 * Clear only the visible text display. This is separate from logical screen
1805 * initialization so that the C1 early-console path can perform the clear at
1806 * takeover time before wsdisplay_cnattach(), while the later normal attach
1807 * can reuse the established console state without clearing it again.
1808 */
1809 static int
1810 fbbm_clear_screen(struct fbbm_devconfig *dc)
1811 {
1812
1813 return nwb225_rop_fill_rect(dc, 0, 0, dc->dc_width, dc->dc_height, 0);
1814 }
1815
1816 static uint32_t
1817 fbbm_attr_background(struct fbbm_devconfig *dc, long attr)
1818 {
1819
1820 return (attr & 1) != 0 ? dc->dc_planemask : 0;
1821 }
1822
1823 static void
1824 fbbm_cursor(void *cookie, int on, int row, int col)
1825 {
1826 struct fbbm_devconfig *dc = cookie;
1827 int x, y, error;
1828
1829 if (dc->dc_cursoron != 0) {
1830 x = dc->dc_xorigin + dc->dc_cursorcol * dc->dc_cellwidth;
1831 y = dc->dc_yorigin + dc->dc_cursorrow * dc->dc_cellheight;
1832 error = nwb225_rop_copy_rect(dc, x, y, dc->dc_cellwidth,
1833 dc->dc_cellheight, x, y, NWB225_BF_DI);
1834 if (error != 0)
1835 return;
1836 dc->dc_cursoron = 0;
1837 }
1838
1839 dc->dc_cursorrow = row;
1840 dc->dc_cursorcol = col;
1841 if (on == 0)
1842 return;
1843 if (row < 0 || row >= dc->dc_nrows || col < 0 || col >= dc->dc_ncols)
1844 return;
1845
1846 x = dc->dc_xorigin + col * dc->dc_cellwidth;
1847 y = dc->dc_yorigin + row * dc->dc_cellheight;
1848 error = nwb225_rop_copy_rect(dc, x, y, dc->dc_cellwidth,
1849 dc->dc_cellheight, x, y, NWB225_BF_DI);
1850 if (error == 0)
1851 dc->dc_cursoron = 1;
1852 }
1853
1854 static int
1855 fbbm_mapchar(void *cookie, int c, unsigned int *cp)
1856 {
1857
1858 __USE(cookie);
1859
1860 if (c < NWB225_KROM_ASCII_FIRST || c > NWB225_KROM_ASCII_LAST) {
1861 *cp = ' ';
1862 return 0;
1863 }
1864
1865 *cp = c;
1866 return 5;
1867 }
1868
1869 static void
1870 fbbm_putchar(void *cookie, int row, int col, u_int uc, long attr)
1871 {
1872 struct fbbm_devconfig *dc = cookie;
1873 uint16_t cell[NWB225_CELL_HEIGHT];
1874 uint32_t foreground, background;
1875 int x, y;
1876
1877 if (row < 0 || row >= dc->dc_nrows || col < 0 || col >= dc->dc_ncols)
1878 return;
1879 if (uc < NWB225_KROM_ASCII_FIRST || uc > NWB225_KROM_ASCII_LAST)
1880 uc = ' ';
1881
1882 nwb225_krom_load_cell(dc, uc, cell);
1883 background = fbbm_attr_background(dc, attr);
1884 foreground = dc->dc_planemask ^ background;
1885 x = dc->dc_xorigin + col * dc->dc_cellwidth;
1886 y = dc->dc_yorigin + row * dc->dc_cellheight;
1887
1888 (void)nwb225_rop_hwrite(dc, cell, 1, 0, 0, dc->dc_cellwidth,
1889 dc->dc_cellheight, x, y, foreground, background);
1890 }
1891
1892 static void
1893 fbbm_copycols(void *cookie, int row, int srccol, int dstcol, int ncols)
1894 {
1895 struct fbbm_devconfig *dc = cookie;
1896 int sx, dx, y, width;
1897
1898 if (ncols <= 0 || row < 0 || row >= dc->dc_nrows)
1899 return;
1900 if (srccol < 0 || dstcol < 0 || srccol + ncols > dc->dc_ncols ||
1901 dstcol + ncols > dc->dc_ncols)
1902 return;
1903 if (srccol == dstcol)
1904 return;
1905
1906 sx = dc->dc_xorigin + srccol * dc->dc_cellwidth;
1907 dx = dc->dc_xorigin + dstcol * dc->dc_cellwidth;
1908 y = dc->dc_yorigin + row * dc->dc_cellheight;
1909 width = ncols * dc->dc_cellwidth;
1910 (void)nwb225_rop_copy_rect(dc, sx, y, width, dc->dc_cellheight,
1911 dx, y, NWB225_BF_S);
1912 }
1913
1914 static void
1915 fbbm_erasecols(void *cookie, int row, int col, int ncols, long attr)
1916 {
1917 struct fbbm_devconfig *dc = cookie;
1918 uint32_t background;
1919 int x, y, width;
1920
1921 if (ncols <= 0 || row < 0 || row >= dc->dc_nrows)
1922 return;
1923 if (col < 0 || col + ncols > dc->dc_ncols)
1924 return;
1925
1926 x = dc->dc_xorigin + col * dc->dc_cellwidth;
1927 y = dc->dc_yorigin + row * dc->dc_cellheight;
1928 width = ncols * dc->dc_cellwidth;
1929 background = fbbm_attr_background(dc, attr);
1930 (void)nwb225_rop_fill_rect(dc, x, y, width, dc->dc_cellheight,
1931 background);
1932 }
1933
1934 static void
1935 fbbm_copyrows(void *cookie, int srcrow, int dstrow, int nrows)
1936 {
1937 struct fbbm_devconfig *dc = cookie;
1938 int x, sy, dy, height;
1939
1940 if (nrows <= 0 || srcrow < 0 || dstrow < 0 ||
1941 srcrow + nrows > dc->dc_nrows || dstrow + nrows > dc->dc_nrows)
1942 return;
1943 if (srcrow == dstrow)
1944 return;
1945
1946 x = dc->dc_xorigin;
1947 sy = dc->dc_yorigin + srcrow * dc->dc_cellheight;
1948 dy = dc->dc_yorigin + dstrow * dc->dc_cellheight;
1949 height = nrows * dc->dc_cellheight;
1950 (void)nwb225_rop_copy_rect(dc, x, sy,
1951 dc->dc_ncols * dc->dc_cellwidth, height, x, dy, NWB225_BF_S);
1952 }
1953
1954 static void
1955 fbbm_eraserows(void *cookie, int row, int nrows, long attr)
1956 {
1957 struct fbbm_devconfig *dc = cookie;
1958 uint32_t background;
1959 int x, y, height;
1960
1961 if (nrows <= 0 || row < 0 || row + nrows > dc->dc_nrows)
1962 return;
1963
1964 x = dc->dc_xorigin;
1965 y = dc->dc_yorigin + row * dc->dc_cellheight;
1966 height = nrows * dc->dc_cellheight;
1967 background = fbbm_attr_background(dc, attr);
1968 (void)nwb225_rop_fill_rect(dc, x, y,
1969 dc->dc_ncols * dc->dc_cellwidth, height, background);
1970 }
1971
1972 static int
1973 fbbm_allocattr(void *cookie, int fg, int bg, int flags, long *attrp)
1974 {
1975
1976 __USE(cookie);
1977 __USE(fg);
1978 __USE(bg);
1979
1980 if ((flags & ~WSATTR_REVERSE) != 0)
1981 return EINVAL;
1982
1983 *attrp = (flags & WSATTR_REVERSE) != 0 ? 1 : 0;
1984 return 0;
1985 }
1986
1987 static int
1988 fbbm_ioctl(void *v, void *vs, u_long cmd, void *data, int flag,
1989 struct lwp *l)
1990 {
1991 struct fbbm_softc *sc = v;
1992 struct fbbm_devconfig *dc = sc->sc_dc;
1993 struct wsdisplay_fbinfo *fbinfo;
1994
1995 __USE(vs);
1996 __USE(flag);
1997 __USE(l);
1998
1999 switch (cmd) {
2000 case WSDISPLAYIO_GTYPE:
2001 *(u_int *)data = WSDISPLAY_TYPE_NWB225;
2002 return 0;
2003
2004 case WSDISPLAYIO_GINFO:
2005 fbinfo = data;
2006 fbinfo->height = dc->dc_height;
2007 fbinfo->width = dc->dc_width;
2008 fbinfo->depth = dc->dc_nplanes;
2009 fbinfo->cmsize = 0;
2010 return 0;
2011
2012 default:
2013 return EPASSTHROUGH;
2014 }
2015 }
2016
2017 static int
2018 fbbm_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
2019 int *ccolp, int *crowp, long *attrp)
2020 {
2021 struct fbbm_softc *sc = v;
2022 struct fbbm_devconfig *dc = sc->sc_dc;
2023 long attr;
2024 int error;
2025
2026 KASSERT(type == &dc->dc_wsscrdescr);
2027
2028 if (sc->sc_nscreens != 0)
2029 return ENOMEM;
2030
2031 error = fbbm_allocattr(dc, 0, 0, 0, &attr);
2032 if (error != 0)
2033 return error;
2034
2035 *cookiep = dc;
2036 *ccolp = 0;
2037 *crowp = 0;
2038 *attrp = attr;
2039 sc->sc_nscreens = 1;
2040
2041 return 0;
2042 }
2043
2044 static void
2045 fbbm_free_screen(void *v, void *cookie)
2046 {
2047 struct fbbm_softc *sc = v;
2048
2049 KASSERT(sc->sc_nscreens == 1);
2050 KASSERT(cookie == sc->sc_dc);
2051 sc->sc_nscreens = 0;
2052 }
2053
2054 static int
2055 fbbm_show_screen(void *v, void *cookie, int waitok,
2056 void (*cb)(void *, int, int), void *cbarg)
2057 {
2058
2059 __USE(v);
2060 __USE(cookie);
2061 __USE(waitok);
2062 __USE(cb);
2063 __USE(cbarg);
2064
2065 return 0;
2066 }
2067