1 /* $NetBSD: fbbm.c,v 1.2 2026/09/20 11:52:56 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.2 2026/09/20 11:52:56 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