1 1.1 tsutsui /* $NetBSD: fbbm.c,v 1.2 2026/09/20 11:52:56 tsutsui Exp $ */ 2 1.1 tsutsui 3 1.1 tsutsui /*- 4 1.1 tsutsui * Copyright (c) 2026 Izumi Tsutsui. All rights reserved. 5 1.1 tsutsui * 6 1.1 tsutsui * Redistribution and use in source and binary forms, with or without 7 1.1 tsutsui * modification, are permitted provided that the following conditions 8 1.1 tsutsui * are met: 9 1.1 tsutsui * 1. Redistributions of source code must retain the above copyright 10 1.1 tsutsui * notice, this list of conditions and the following disclaimer. 11 1.1 tsutsui * 2. Redistributions in binary form must reproduce the above copyright 12 1.1 tsutsui * notice, this list of conditions and the following disclaimer in the 13 1.1 tsutsui * documentation and/or other materials provided with the distribution. 14 1.1 tsutsui * 15 1.1 tsutsui * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 1.1 tsutsui * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 1.1 tsutsui * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 1.1 tsutsui * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 1.1 tsutsui * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 1.1 tsutsui * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 1.1 tsutsui * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 1.1 tsutsui * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 1.1 tsutsui * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 1.1 tsutsui * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 1.1 tsutsui */ 26 1.1 tsutsui 27 1.1 tsutsui #include <sys/cdefs.h> 28 1.1 tsutsui __KERNEL_RCSID(0, "$NetBSD: fbbm.c,v 1.2 2026/09/20 11:52:56 tsutsui Exp $"); 29 1.1 tsutsui 30 1.1 tsutsui #include <sys/param.h> 31 1.1 tsutsui #include <sys/device.h> 32 1.1 tsutsui #include <sys/errno.h> 33 1.1 tsutsui #include <sys/ioctl.h> 34 1.1 tsutsui #include <sys/kmem.h> 35 1.1 tsutsui #include <sys/systm.h> 36 1.1 tsutsui 37 1.1 tsutsui #include <machine/bus.h> 38 1.1 tsutsui 39 1.1 tsutsui #include <news68k/dev/hbvar.h> 40 1.1 tsutsui #include <news68k/dev/nwb225reg.h> 41 1.1 tsutsui 42 1.1 tsutsui #include <dev/wscons/wsconsio.h> 43 1.1 tsutsui #include <dev/wscons/wsdisplayvar.h> 44 1.1 tsutsui 45 1.1 tsutsui struct fbbm_devconfig { 46 1.1 tsutsui bus_space_tag_t dc_bst; 47 1.1 tsutsui bus_space_handle_t dc_rcont_bsh; 48 1.1 tsutsui bus_space_handle_t dc_krom_bsh; 49 1.1 tsutsui 50 1.1 tsutsui int dc_nplanes; 51 1.1 tsutsui uint32_t dc_planemask; 52 1.1 tsutsui int dc_dispver; 53 1.1 tsutsui 54 1.1 tsutsui int dc_fbwidth; 55 1.1 tsutsui int dc_fbheight; 56 1.1 tsutsui int dc_width; 57 1.1 tsutsui int dc_height; 58 1.1 tsutsui 59 1.1 tsutsui int dc_fontwidth; 60 1.1 tsutsui int dc_fontheight; 61 1.1 tsutsui int dc_cellwidth; 62 1.1 tsutsui int dc_cellheight; 63 1.1 tsutsui 64 1.1 tsutsui int dc_ncols; 65 1.1 tsutsui int dc_nrows; 66 1.1 tsutsui int dc_xorigin; 67 1.1 tsutsui int dc_yorigin; 68 1.1 tsutsui 69 1.1 tsutsui int dc_cursoron; 70 1.1 tsutsui int dc_cursorrow; 71 1.1 tsutsui int dc_cursorcol; 72 1.1 tsutsui 73 1.1 tsutsui struct wsscreen_descr dc_wsscrdescr; 74 1.1 tsutsui }; 75 1.1 tsutsui 76 1.1 tsutsui struct fbbm_softc { 77 1.1 tsutsui device_t sc_dev; 78 1.1 tsutsui struct fbbm_devconfig *sc_dc; 79 1.1 tsutsui int sc_nscreens; 80 1.1 tsutsui int sc_wsmode; 81 1.1 tsutsui const struct wsscreen_descr *sc_scrdescs[1]; 82 1.1 tsutsui struct wsscreen_list sc_scrlist; 83 1.1 tsutsui }; 84 1.1 tsutsui 85 1.1 tsutsui /* autoconf functions and helpers */ 86 1.1 tsutsui static int fbbm_match(device_t, cfdata_t, void *); 87 1.1 tsutsui static void fbbm_attach(device_t, device_t, void *); 88 1.1 tsutsui 89 1.1 tsutsui static bool fbbm_console_initialized(void); 90 1.1 tsutsui static int fbbm_probe(bus_space_tag_t, bus_addr_t); 91 1.1 tsutsui 92 1.1 tsutsui /* bus_space mappings */ 93 1.1 tsutsui static int nwb225_map(struct fbbm_devconfig *, bus_space_tag_t, bus_addr_t); 94 1.1 tsutsui static void nwb225_unmap(struct fbbm_devconfig *); 95 1.1 tsutsui 96 1.1 tsutsui /* ROP helper functions */ 97 1.1 tsutsui static void nwb225_rop_reset(struct fbbm_devconfig *); 98 1.1 tsutsui static int nwb225_rop_wait(struct fbbm_devconfig *); 99 1.1 tsutsui static void nwb225_ctl_write(struct fbbm_devconfig *, uint16_t, uint16_t); 100 1.1 tsutsui static void nwb225_rop_set_plane_mask(struct fbbm_devconfig *, uint32_t); 101 1.1 tsutsui static void nwb225_rop_make_funcvec(struct fbbm_devconfig *, u_int, 102 1.1 tsutsui uint32_t, uint32_t, uint8_t *); 103 1.1 tsutsui static void nwb225_rop_funcvec_constant_s(struct fbbm_devconfig *, uint8_t *, 104 1.1 tsutsui u_int); 105 1.1 tsutsui static void nwb225_rop_set_funcvec(struct fbbm_devconfig *, const uint8_t *); 106 1.1 tsutsui 107 1.1 tsutsui /* Hardware primitive ROP functions */ 108 1.1 tsutsui static int nwb225_rop_copy_rect(struct fbbm_devconfig *, int, int, int, int, 109 1.1 tsutsui int, int, u_int); 110 1.1 tsutsui static int nwb225_rop_fill_rect(struct fbbm_devconfig *, int, int, int, int, 111 1.1 tsutsui uint32_t); 112 1.1 tsutsui static int nwb225_rop_hwrite(struct fbbm_devconfig *, const uint16_t *, int, 113 1.1 tsutsui int, int, int, int, int, int, uint32_t, uint32_t); 114 1.1 tsutsui 115 1.1 tsutsui /* ROM font functions */ 116 1.1 tsutsui static bus_size_t nwb225_krom_ascii_offset(u_int); 117 1.1 tsutsui static void nwb225_krom_load_cell(struct fbbm_devconfig *, u_int, 118 1.1 tsutsui uint16_t *); 119 1.1 tsutsui 120 1.1 tsutsui /* Initialization */ 121 1.1 tsutsui static int nwb225_init_hardware(struct fbbm_devconfig *); 122 1.1 tsutsui 123 1.1 tsutsui static void fbbm_init_screen(struct fbbm_devconfig *); 124 1.1 tsutsui static int fbbm_clear_screen(struct fbbm_devconfig *); 125 1.1 tsutsui 126 1.1 tsutsui /* wsdisplay_emulops functions */ 127 1.1 tsutsui static void fbbm_cursor(void *, int, int, int); 128 1.1 tsutsui static int fbbm_mapchar(void *, int, u_int *); 129 1.1 tsutsui static void fbbm_putchar(void *, int, int, u_int, long); 130 1.1 tsutsui static void fbbm_copycols(void *, int, int, int, int); 131 1.1 tsutsui static void fbbm_erasecols(void *, int, int, int, long); 132 1.1 tsutsui static void fbbm_copyrows(void *, int, int, int); 133 1.1 tsutsui static void fbbm_eraserows(void *, int, int, long); 134 1.1 tsutsui static int fbbm_allocattr(void *, int, int, int, long *); 135 1.1 tsutsui 136 1.1 tsutsui /* wsdisplay_accessops functions */ 137 1.1 tsutsui static int fbbm_ioctl(void *, void *, u_long, void *, int, struct lwp *); 138 1.1 tsutsui static int fbbm_alloc_screen(void *, const struct wsscreen_descr *, void **, 139 1.1 tsutsui int *, int *, long *); 140 1.1 tsutsui static void fbbm_free_screen(void *, void *); 141 1.1 tsutsui static int fbbm_show_screen(void *, void *, int, void (*)(void *, int, int), 142 1.1 tsutsui void *); 143 1.1 tsutsui 144 1.1 tsutsui /* cnattach function for early console */ 145 1.1 tsutsui int fbbm_cnattach(void); 146 1.1 tsutsui 147 1.1 tsutsui CFATTACH_DECL_NEW(fbbm, sizeof(struct fbbm_softc), 148 1.1 tsutsui fbbm_match, fbbm_attach, NULL, NULL); 149 1.1 tsutsui 150 1.1 tsutsui static struct fbbm_devconfig fbbm_console_dc; 151 1.1 tsutsui 152 1.1 tsutsui static const struct wsdisplay_emulops fbbm_emulops = { 153 1.1 tsutsui .cursor = fbbm_cursor, 154 1.1 tsutsui .mapchar = fbbm_mapchar, 155 1.1 tsutsui .putchar = fbbm_putchar, 156 1.1 tsutsui .copycols = fbbm_copycols, 157 1.1 tsutsui .erasecols = fbbm_erasecols, 158 1.1 tsutsui .copyrows = fbbm_copyrows, 159 1.1 tsutsui .eraserows = fbbm_eraserows, 160 1.1 tsutsui .allocattr = fbbm_allocattr, 161 1.1 tsutsui .replaceattr = NULL, 162 1.1 tsutsui }; 163 1.1 tsutsui 164 1.1 tsutsui static const struct wsdisplay_accessops fbbm_accessops = { 165 1.1 tsutsui .ioctl = fbbm_ioctl, 166 1.1 tsutsui .mmap = NULL, 167 1.1 tsutsui .alloc_screen = fbbm_alloc_screen, 168 1.1 tsutsui .free_screen = fbbm_free_screen, 169 1.1 tsutsui .show_screen = fbbm_show_screen, 170 1.1 tsutsui .load_font = NULL, 171 1.1 tsutsui .pollc = NULL, 172 1.1 tsutsui .scroll = NULL, 173 1.1 tsutsui }; 174 1.1 tsutsui 175 1.1 tsutsui /* Timeout count to check ROP op complete */ 176 1.1 tsutsui #define NWB225_WAIT_MAX 100000 177 1.1 tsutsui 178 1.1 tsutsui /* Maximum number of planes of NWB-225 (4 or 8) */ 179 1.1 tsutsui #define NWB225_MAX_PLANES 8 180 1.1 tsutsui 181 1.1 tsutsui /* 182 1.1 tsutsui * Software logical functions F(S,D). 183 1.1 tsutsui * These values index nwb225_fccnvtab[] and are not hardware function values. 184 1.1 tsutsui */ 185 1.1 tsutsui #define NWB225_ROP_LF_0 0x00 186 1.1 tsutsui #define NWB225_ROP_LF_S 0x03 187 1.1 tsutsui #define NWB225_ROP_LF_D 0x05 188 1.1 tsutsui #define NWB225_ROP_LF_DI 0x0a 189 1.1 tsutsui #define NWB225_ROP_LF_1 0x0f 190 1.1 tsutsui 191 1.1 tsutsui /* 192 1.1 tsutsui * Logical FBBM function to 51X hardware function conversion table 193 1.1 tsutsui * taken from NEWS-OS fbbm_51x.o. 194 1.1 tsutsui */ 195 1.1 tsutsui static const uint8_t nwb225_fccnvtab[16] = { 196 1.1 tsutsui 0x03, 0x0b, 0x07, 0x0f, 197 1.1 tsutsui 0x02, 0x0a, 0x06, 0x0e, 198 1.1 tsutsui 0x01, 0x09, 0x05, 0x0d, 199 1.1 tsutsui 0x00, 0x08, 0x04, 0x0c, 200 1.1 tsutsui }; 201 1.1 tsutsui 202 1.1 tsutsui /* 203 1.1 tsutsui * Fixed initialization values written by the NWS-1750 PROM and NEWS-OS 204 1.1 tsutsui * 51X setup. Their individual timing/control semantics are intentionally 205 1.1 tsutsui * not inferred here. 206 1.1 tsutsui */ 207 1.1 tsutsui static const uint16_t nwb225_init_words[] = { 208 1.1 tsutsui 0x0400, 0x0002, 0x0005, 0x00d8, 209 1.1 tsutsui 0x0000, 0x0006, 0x0000, 210 1.1 tsutsui }; 211 1.1 tsutsui 212 1.1 tsutsui /* 213 1.1 tsutsui * 4-bit component values taken from the NWS-1750 PROM NWB-225 module. 214 1.1 tsutsui * The PROM repeats this 16-entry table through all 256 palette indices 215 1.1 tsutsui * and writes each component after shifting it left by four bits. 216 1.1 tsutsui */ 217 1.1 tsutsui static const uint8_t nwb225_prom_palette[16][3] = { 218 1.1 tsutsui { 0, 0, 0 }, 219 1.1 tsutsui { 0, 0, 4 }, 220 1.1 tsutsui { 0, 4, 0 }, 221 1.1 tsutsui { 0, 4, 4 }, 222 1.1 tsutsui { 4, 0, 0 }, 223 1.1 tsutsui { 4, 0, 4 }, 224 1.1 tsutsui { 4, 4, 0 }, 225 1.1 tsutsui { 4, 4, 4 }, 226 1.1 tsutsui { 8, 8, 8 }, 227 1.1 tsutsui { 0, 0, 15 }, 228 1.1 tsutsui { 0, 15, 0 }, 229 1.1 tsutsui { 0, 15, 15 }, 230 1.1 tsutsui { 15, 0, 0 }, 231 1.1 tsutsui { 15, 0, 15 }, 232 1.1 tsutsui { 15, 15, 0 }, 233 1.1 tsutsui { 15, 15, 15 }, 234 1.1 tsutsui }; 235 1.1 tsutsui 236 1.1 tsutsui static bool 237 1.1 tsutsui fbbm_console_initialized(void) 238 1.1 tsutsui { 239 1.1 tsutsui 240 1.1 tsutsui /* 241 1.1 tsutsui * This is initialized in fbbm_init_screen() via 242 1.1 tsutsui * fbbm_cnattach() or fbbm_cnattach(). 243 1.1 tsutsui */ 244 1.1 tsutsui return fbbm_console_dc.dc_wsscrdescr.textops == &fbbm_emulops; 245 1.1 tsutsui } 246 1.1 tsutsui 247 1.1 tsutsui static int 248 1.1 tsutsui fbbm_probe(bus_space_tag_t bst, bus_addr_t rcont_addr) 249 1.1 tsutsui { 250 1.1 tsutsui bus_space_handle_t bsh; 251 1.1 tsutsui int rv; 252 1.1 tsutsui 253 1.1 tsutsui if (bus_space_map(bst, rcont_addr, NWB225_RCONT_SIZE, 0, &bsh) != 0) 254 1.1 tsutsui return 0; 255 1.1 tsutsui 256 1.1 tsutsui /* NEWS-OS fb225_probe() used a byte-sized badaddr() at this base */ 257 1.1 tsutsui rv = news68k_bus_space_probe(bst, bsh, 0, 1); 258 1.1 tsutsui bus_space_unmap(bst, bsh, NWB225_RCONT_SIZE); 259 1.1 tsutsui 260 1.1 tsutsui return rv; 261 1.1 tsutsui } 262 1.1 tsutsui 263 1.1 tsutsui static int 264 1.1 tsutsui fbbm_match(device_t parent, cfdata_t cf, void *aux) 265 1.1 tsutsui { 266 1.1 tsutsui struct hb_attach_args *ha = aux; 267 1.1 tsutsui 268 1.1 tsutsui if (strcmp(ha->ha_name, "fbbm") != 0) 269 1.1 tsutsui return 0; 270 1.1 tsutsui if (ha->ha_address != NWB225_RCONT_BASE) 271 1.1 tsutsui return 0; 272 1.1 tsutsui 273 1.1 tsutsui return fbbm_probe(ha->ha_bust, ha->ha_address); 274 1.1 tsutsui } 275 1.1 tsutsui 276 1.1 tsutsui static void 277 1.1 tsutsui fbbm_attach(device_t parent, device_t self, void *aux) 278 1.1 tsutsui { 279 1.1 tsutsui struct fbbm_softc *sc = device_private(self); 280 1.1 tsutsui struct hb_attach_args *ha = aux; 281 1.1 tsutsui struct fbbm_devconfig *dc; 282 1.1 tsutsui struct wsemuldisplaydev_attach_args waa; 283 1.1 tsutsui bool console; 284 1.1 tsutsui 285 1.1 tsutsui sc->sc_dev = self; 286 1.1 tsutsui console = fbbm_console_initialized(); 287 1.1 tsutsui 288 1.1 tsutsui if (console) { 289 1.1 tsutsui dc = &fbbm_console_dc; 290 1.1 tsutsui sc->sc_nscreens = 1; 291 1.1 tsutsui } else { 292 1.1 tsutsui dc = kmem_zalloc(sizeof(*dc), KM_SLEEP); 293 1.1 tsutsui if (nwb225_map(dc, ha->ha_bust, ha->ha_address) != 0) { 294 1.1 tsutsui aprint_error(": unable to map device registers"); 295 1.1 tsutsui goto out_free; 296 1.1 tsutsui } 297 1.1 tsutsui 298 1.1 tsutsui if (nwb225_init_hardware(dc) != 0) { 299 1.1 tsutsui aprint_error(": controller initialization failed"); 300 1.1 tsutsui goto out_unmap; 301 1.1 tsutsui } 302 1.1 tsutsui 303 1.1 tsutsui fbbm_init_screen(dc); 304 1.1 tsutsui if (fbbm_clear_screen(dc) != 0) { 305 1.1 tsutsui aprint_error(": unable to clear text screen"); 306 1.1 tsutsui goto out_unmap; 307 1.1 tsutsui } 308 1.1 tsutsui sc->sc_nscreens = 0; 309 1.1 tsutsui } 310 1.1 tsutsui 311 1.1 tsutsui sc->sc_dc = dc; 312 1.1 tsutsui sc->sc_wsmode = WSDISPLAYIO_MODE_EMUL; 313 1.1 tsutsui sc->sc_scrdescs[0] = &dc->dc_wsscrdescr; 314 1.1 tsutsui sc->sc_scrlist.nscreens = __arraycount(sc->sc_scrdescs); 315 1.1 tsutsui sc->sc_scrlist.screens = sc->sc_scrdescs; 316 1.1 tsutsui 317 1.1 tsutsui aprint_normal(": NWB-225, %d x %d, %d planes, display version %d\n", 318 1.1 tsutsui dc->dc_width, dc->dc_height, dc->dc_nplanes, dc->dc_dispver); 319 1.1 tsutsui 320 1.1 tsutsui waa.console = console; 321 1.1 tsutsui waa.scrdata = &sc->sc_scrlist; 322 1.1 tsutsui waa.accessops = &fbbm_accessops; 323 1.1 tsutsui waa.accesscookie = sc; 324 1.1 tsutsui 325 1.1 tsutsui config_found(self, &waa, wsemuldisplaydevprint, CFARGS_NONE); 326 1.1 tsutsui return; 327 1.1 tsutsui 328 1.1 tsutsui out_unmap: 329 1.1 tsutsui nwb225_unmap(dc); 330 1.1 tsutsui out_free: 331 1.1 tsutsui kmem_free(dc, sizeof(*dc)); 332 1.1 tsutsui } 333 1.1 tsutsui 334 1.1 tsutsui static int 335 1.1 tsutsui nwb225_map(struct fbbm_devconfig *dc, bus_space_tag_t bst, 336 1.1 tsutsui bus_addr_t rcont_addr) 337 1.1 tsutsui { 338 1.1 tsutsui int error; 339 1.1 tsutsui 340 1.1 tsutsui dc->dc_bst = bst; 341 1.1 tsutsui 342 1.1 tsutsui error = bus_space_map(bst, rcont_addr, NWB225_RCONT_SIZE, 0, 343 1.1 tsutsui &dc->dc_rcont_bsh); 344 1.1 tsutsui if (error != 0) 345 1.1 tsutsui return error; 346 1.1 tsutsui 347 1.1 tsutsui error = bus_space_map(bst, NWB225_KROM_BASE, NWB225_KROM_SIZE, 0, 348 1.1 tsutsui &dc->dc_krom_bsh); 349 1.1 tsutsui if (error != 0) { 350 1.1 tsutsui bus_space_unmap(bst, dc->dc_rcont_bsh, NWB225_RCONT_SIZE); 351 1.1 tsutsui return error; 352 1.1 tsutsui } 353 1.1 tsutsui 354 1.1 tsutsui return 0; 355 1.1 tsutsui } 356 1.1 tsutsui 357 1.1 tsutsui static void 358 1.1 tsutsui nwb225_unmap(struct fbbm_devconfig *dc) 359 1.1 tsutsui { 360 1.1 tsutsui 361 1.1 tsutsui bus_space_unmap(dc->dc_bst, dc->dc_krom_bsh, NWB225_KROM_SIZE); 362 1.1 tsutsui bus_space_unmap(dc->dc_bst, dc->dc_rcont_bsh, NWB225_RCONT_SIZE); 363 1.1 tsutsui } 364 1.1 tsutsui 365 1.1 tsutsui static void 366 1.1 tsutsui nwb225_rop_reset(struct fbbm_devconfig *dc) 367 1.1 tsutsui { 368 1.1 tsutsui 369 1.1 tsutsui /* 370 1.1 tsutsui * Both NEWS-OS fb51X_rop_reset() and the NWS-1750 PROM perform 371 1.1 tsutsui * this 0 -> 1 sequence. 372 1.1 tsutsui */ 373 1.1 tsutsui bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh, NWB225_STATUS, 0); 374 1.1 tsutsui bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh, NWB225_STATUS, 1); 375 1.1 tsutsui } 376 1.1 tsutsui 377 1.1 tsutsui static int 378 1.1 tsutsui nwb225_rop_wait(struct fbbm_devconfig *dc) 379 1.1 tsutsui { 380 1.1 tsutsui uint16_t status; 381 1.1 tsutsui int i; 382 1.1 tsutsui 383 1.1 tsutsui for (i = 0; i < NWB225_WAIT_MAX; i++) { 384 1.1 tsutsui status = bus_space_read_2(dc->dc_bst, dc->dc_rcont_bsh, 385 1.1 tsutsui NWB225_STATUS); 386 1.1 tsutsui if ((status & NWB225_STATUS_BUSY) == 0) 387 1.1 tsutsui return 0; 388 1.1 tsutsui } 389 1.1 tsutsui 390 1.1 tsutsui /* Reset ROP engine on timeout as NEWS-OS does */ 391 1.1 tsutsui nwb225_rop_reset(dc); 392 1.1 tsutsui return ETIMEDOUT; 393 1.1 tsutsui } 394 1.1 tsutsui 395 1.1 tsutsui static void 396 1.1 tsutsui nwb225_ctl_write(struct fbbm_devconfig *dc, uint16_t selector, uint16_t value) 397 1.1 tsutsui { 398 1.1 tsutsui 399 1.1 tsutsui bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh, 400 1.1 tsutsui NWB225_CTL_SELECT, selector); 401 1.1 tsutsui bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh, 402 1.1 tsutsui NWB225_CTL_DATA, value); 403 1.1 tsutsui } 404 1.1 tsutsui 405 1.1 tsutsui static void 406 1.1 tsutsui nwb225_rop_set_plane_mask(struct fbbm_devconfig *dc, uint32_t planemask) 407 1.1 tsutsui { 408 1.1 tsutsui uint8_t disabled_planes; 409 1.1 tsutsui uint16_t hwmask; 410 1.1 tsutsui 411 1.1 tsutsui disabled_planes = (uint8_t)~planemask; 412 1.1 tsutsui hwmask = (uint16_t)disabled_planes << NWB225_PLANE_CTRL_SHIFT; 413 1.1 tsutsui bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh, 414 1.1 tsutsui NWB225_PLANE_CTRL, hwmask); 415 1.1 tsutsui } 416 1.1 tsutsui 417 1.1 tsutsui static void 418 1.1 tsutsui nwb225_rop_make_funcvec(struct fbbm_devconfig *dc, u_int logical_func, 419 1.1 tsutsui uint32_t src1, uint32_t src0, uint8_t *funcvec) 420 1.1 tsutsui { 421 1.1 tsutsui uint8_t f_s0_d, f_s1_d; 422 1.1 tsutsui uint8_t func_by_srcmap[4]; 423 1.1 tsutsui uint8_t src1_bit, src0_bit, src_map; 424 1.1 tsutsui int i; 425 1.1 tsutsui 426 1.1 tsutsui KASSERT(logical_func <= 0x0f); 427 1.1 tsutsui KASSERT(dc->dc_nplanes == 4 || dc->dc_nplanes == 8); 428 1.1 tsutsui 429 1.1 tsutsui /* F(0,D) */ 430 1.1 tsutsui f_s0_d = (logical_func >> 2) & 0x03; 431 1.1 tsutsui /* F(1,D) */ 432 1.1 tsutsui f_s1_d = logical_func & 0x03; 433 1.1 tsutsui 434 1.1 tsutsui func_by_srcmap[0] = (f_s0_d << 2) | f_s0_d; 435 1.1 tsutsui func_by_srcmap[1] = (f_s1_d << 2) | f_s0_d; 436 1.1 tsutsui func_by_srcmap[2] = (f_s0_d << 2) | f_s1_d; 437 1.1 tsutsui func_by_srcmap[3] = (f_s1_d << 2) | f_s1_d; 438 1.1 tsutsui 439 1.1 tsutsui for (i = 0; i < dc->dc_nplanes; i++) { 440 1.1 tsutsui src1_bit = src1 & 0x01; 441 1.1 tsutsui src0_bit = src0 & 0x01; 442 1.1 tsutsui src_map = (src1_bit << 1) | src0_bit; 443 1.1 tsutsui funcvec[i] = func_by_srcmap[src_map]; 444 1.1 tsutsui src1 >>= 1; 445 1.1 tsutsui src0 >>= 1; 446 1.1 tsutsui } 447 1.1 tsutsui } 448 1.1 tsutsui 449 1.1 tsutsui static void 450 1.1 tsutsui nwb225_rop_funcvec_constant_s(struct fbbm_devconfig *dc, uint8_t *funcvec, 451 1.1 tsutsui u_int s) 452 1.1 tsutsui { 453 1.1 tsutsui uint8_t logical_func, f_s0_d, f_s1_d, d_func, result; 454 1.1 tsutsui int i; 455 1.1 tsutsui 456 1.1 tsutsui KASSERT(dc->dc_nplanes == 4 || dc->dc_nplanes == 8); 457 1.1 tsutsui KASSERT(s <= 1); 458 1.1 tsutsui 459 1.1 tsutsui for (i = 0; i < dc->dc_nplanes; i++) { 460 1.1 tsutsui logical_func = funcvec[i]; 461 1.1 tsutsui KASSERT(logical_func <= 0x0f); 462 1.1 tsutsui 463 1.1 tsutsui /* F(0,D) */ 464 1.1 tsutsui f_s0_d = (logical_func >> 2) & 0x03; 465 1.1 tsutsui /* F(1,D) */ 466 1.1 tsutsui f_s1_d = logical_func & 0x03; 467 1.1 tsutsui 468 1.1 tsutsui d_func = (s == 0) ? f_s0_d : f_s1_d; 469 1.1 tsutsui switch (d_func) { 470 1.1 tsutsui case 0: 471 1.1 tsutsui result = NWB225_ROP_LF_0; 472 1.1 tsutsui break; 473 1.1 tsutsui case 1: 474 1.1 tsutsui result = NWB225_ROP_LF_D; 475 1.1 tsutsui break; 476 1.1 tsutsui case 2: 477 1.1 tsutsui result = NWB225_ROP_LF_DI; 478 1.1 tsutsui break; 479 1.1 tsutsui case 3: 480 1.1 tsutsui result = NWB225_ROP_LF_1; 481 1.1 tsutsui break; 482 1.1 tsutsui default: 483 1.1 tsutsui KASSERT(false); 484 1.1 tsutsui result = NWB225_ROP_LF_0; 485 1.1 tsutsui break; 486 1.1 tsutsui } 487 1.1 tsutsui funcvec[i] = result; 488 1.1 tsutsui } 489 1.1 tsutsui } 490 1.1 tsutsui 491 1.1 tsutsui static void 492 1.1 tsutsui nwb225_rop_set_funcvec(struct fbbm_devconfig *dc, const uint8_t *funcvec) 493 1.1 tsutsui { 494 1.1 tsutsui uint8_t logical_func, hw_func; 495 1.1 tsutsui int i; 496 1.1 tsutsui 497 1.1 tsutsui for (i = 0; i < dc->dc_nplanes; i++) { 498 1.1 tsutsui KASSERT(funcvec[i] <= 0x0f); 499 1.1 tsutsui logical_func = funcvec[i]; 500 1.1 tsutsui hw_func = nwb225_fccnvtab[logical_func]; 501 1.1 tsutsui bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh, 502 1.1 tsutsui NWB225_ROP_FUNC(i), hw_func); 503 1.1 tsutsui } 504 1.1 tsutsui } 505 1.1 tsutsui 506 1.1 tsutsui static int 507 1.1 tsutsui nwb225_rect_valid(struct fbbm_devconfig *dc, int x, int y, int width, 508 1.1 tsutsui int height) 509 1.1 tsutsui { 510 1.1 tsutsui 511 1.1 tsutsui if (x < 0 || y < 0 || width <= 0 || height <= 0) 512 1.1 tsutsui return 0; 513 1.1 tsutsui if (x >= dc->dc_fbwidth || y >= dc->dc_fbheight) 514 1.1 tsutsui return 0; 515 1.1 tsutsui if (width > dc->dc_fbwidth - x || height > dc->dc_fbheight - y) 516 1.1 tsutsui return 0; 517 1.1 tsutsui 518 1.1 tsutsui return 1; 519 1.1 tsutsui } 520 1.1 tsutsui 521 1.1 tsutsui static int 522 1.1 tsutsui nwb225_rop_copy_rect(struct fbbm_devconfig *dc, int sx, int sy, int width, 523 1.1 tsutsui int height, int dx, int dy, u_int logical_func) 524 1.1 tsutsui { 525 1.1 tsutsui uint8_t funcvec[NWB225_MAX_PLANES]; 526 1.1 tsutsui bus_size_t copy_mode; 527 1.1 tsutsui bool reverse_x, reverse_y; 528 1.1 tsutsui int src_x, src_y, dst_x, dst_y, limit_x; 529 1.1 tsutsui int error; 530 1.1 tsutsui 531 1.1 tsutsui if (logical_func > 0x0f) 532 1.1 tsutsui return EINVAL; 533 1.1 tsutsui 534 1.1 tsutsui if (nwb225_rect_valid(dc, sx, sy, width, height) == 0 || 535 1.1 tsutsui nwb225_rect_valid(dc, dx, dy, width, height) == 0) 536 1.1 tsutsui return EINVAL; 537 1.1 tsutsui 538 1.1 tsutsui error = nwb225_rop_wait(dc); 539 1.1 tsutsui if (__predict_false(error != 0)) 540 1.1 tsutsui return error; 541 1.1 tsutsui 542 1.1 tsutsui nwb225_rop_make_funcvec(dc, logical_func, dc->dc_planemask, 0, funcvec); 543 1.1 tsutsui nwb225_rop_set_funcvec(dc, funcvec); 544 1.1 tsutsui nwb225_rop_set_plane_mask(dc, dc->dc_planemask); 545 1.1 tsutsui 546 1.1 tsutsui /* Wait again as NEWS-OS does */ 547 1.1 tsutsui error = nwb225_rop_wait(dc); 548 1.1 tsutsui if (__predict_false(error != 0)) 549 1.1 tsutsui return error; 550 1.1 tsutsui 551 1.1 tsutsui reverse_x = (sx < dx); 552 1.1 tsutsui reverse_y = (sy < dy); 553 1.1 tsutsui src_x = sx + (reverse_x ? width : 0); 554 1.1 tsutsui dst_x = dx + (reverse_x ? width : 0); 555 1.1 tsutsui limit_x = dx + (reverse_x ? 0 : width); 556 1.1 tsutsui src_y = sy + (reverse_y ? height - 1 : 0); 557 1.1 tsutsui dst_y = dy + (reverse_y ? height - 1 : 0); 558 1.1 tsutsui 559 1.1 tsutsui if (reverse_x) { 560 1.1 tsutsui if (reverse_y) { 561 1.1 tsutsui copy_mode = NWB225_ROP_COPY_XR_YR; 562 1.1 tsutsui } else { 563 1.1 tsutsui copy_mode = NWB225_ROP_COPY_XR_YF; 564 1.1 tsutsui } 565 1.1 tsutsui } else { 566 1.1 tsutsui if (reverse_y) { 567 1.1 tsutsui copy_mode = NWB225_ROP_COPY_XF_YR; 568 1.1 tsutsui } else { 569 1.1 tsutsui copy_mode = NWB225_ROP_COPY_XF_YF; 570 1.1 tsutsui } 571 1.1 tsutsui } 572 1.1 tsutsui 573 1.1 tsutsui bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh, 574 1.1 tsutsui copy_mode, 0); 575 1.1 tsutsui bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh, 576 1.1 tsutsui NWB225_DST_ADDR(dst_y), dst_x); 577 1.1 tsutsui bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh, 578 1.1 tsutsui NWB225_SRC_ADDR(src_y) | NWB225_ROP_ADDR_FLAG_SET_SHIFT, src_x); 579 1.1 tsutsui bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh, 580 1.1 tsutsui NWB225_ROP_LIMIT(height) | NWB225_ROP_ADDR_FLAG_EXECUTE, limit_x); 581 1.1 tsutsui 582 1.1 tsutsui /* Wait complete for polling ops */ 583 1.1 tsutsui error = nwb225_rop_wait(dc); 584 1.1 tsutsui 585 1.1 tsutsui return error; 586 1.1 tsutsui } 587 1.1 tsutsui 588 1.1 tsutsui static int 589 1.1 tsutsui nwb225_rop_fill_rect(struct fbbm_devconfig *dc, int x, int y, int width, 590 1.1 tsutsui int height, uint32_t color) 591 1.1 tsutsui { 592 1.1 tsutsui uint8_t funcvec[NWB225_MAX_PLANES]; 593 1.1 tsutsui int error; 594 1.1 tsutsui 595 1.1 tsutsui if (nwb225_rect_valid(dc, x, y, width, height) == 0) 596 1.1 tsutsui return EINVAL; 597 1.1 tsutsui 598 1.1 tsutsui error = nwb225_rop_wait(dc); 599 1.1 tsutsui if (__predict_false(error != 0)) 600 1.1 tsutsui return error; 601 1.1 tsutsui 602 1.1 tsutsui color &= dc->dc_planemask; 603 1.1 tsutsui nwb225_rop_make_funcvec(dc, NWB225_ROP_LF_S, color, 0, funcvec); 604 1.1 tsutsui nwb225_rop_funcvec_constant_s(dc, funcvec, 1); 605 1.1 tsutsui nwb225_rop_set_plane_mask(dc, dc->dc_planemask); 606 1.1 tsutsui nwb225_rop_set_funcvec(dc, funcvec); 607 1.1 tsutsui 608 1.1 tsutsui /* Wait again as NEWS-OS does */ 609 1.1 tsutsui error = nwb225_rop_wait(dc); 610 1.1 tsutsui if (__predict_false(error != 0)) 611 1.1 tsutsui return error; 612 1.1 tsutsui 613 1.1 tsutsui bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh, 614 1.1 tsutsui NWB225_ROP_CONST_FILL, 0); 615 1.1 tsutsui bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh, 616 1.1 tsutsui NWB225_DST_ADDR(0), 0); 617 1.1 tsutsui bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh, 618 1.1 tsutsui NWB225_SRC_ADDR(0) | NWB225_ROP_ADDR_FLAG_SET_SHIFT, 0); 619 1.1 tsutsui bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh, 620 1.1 tsutsui NWB225_DST_ADDR(y), x); 621 1.1 tsutsui bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh, 622 1.1 tsutsui NWB225_ROP_LIMIT(height) | NWB225_ROP_ADDR_FLAG_EXECUTE, x + width); 623 1.1 tsutsui 624 1.1 tsutsui /* Wait complete for polling ops */ 625 1.1 tsutsui error = nwb225_rop_wait(dc); 626 1.1 tsutsui 627 1.1 tsutsui return error; 628 1.1 tsutsui } 629 1.1 tsutsui 630 1.1 tsutsui static int 631 1.1 tsutsui nwb225_rop_hwrite(struct fbbm_devconfig *dc, const uint16_t *src_words, 632 1.1 tsutsui int src_stride_words, int srcx, int srcy, int width, int height, 633 1.1 tsutsui int dx, int dy, uint32_t foreground, uint32_t background) 634 1.1 tsutsui { 635 1.1 tsutsui uint8_t funcvec[NWB225_MAX_PLANES]; 636 1.1 tsutsui int source_word_offset, source_bit_offset; 637 1.1 tsutsui int row_words, row_skip_words, row, word; 638 1.1 tsutsui const uint16_t *sp; 639 1.1 tsutsui int error; 640 1.1 tsutsui 641 1.1 tsutsui if (src_words == NULL || src_stride_words <= 0 || srcx < 0 || srcy < 0) 642 1.1 tsutsui return EINVAL; 643 1.1 tsutsui 644 1.1 tsutsui if (nwb225_rect_valid(dc, dx, dy, width, height) == 0) 645 1.1 tsutsui return EINVAL; 646 1.1 tsutsui 647 1.1 tsutsui source_word_offset = srcx / NWB225_HWRITE_BITS_PER_WORD; 648 1.1 tsutsui source_bit_offset = srcx % NWB225_HWRITE_BITS_PER_WORD; 649 1.1 tsutsui row_words = 650 1.1 tsutsui howmany(source_bit_offset + width, NWB225_HWRITE_BITS_PER_WORD); 651 1.1 tsutsui if (source_word_offset + row_words > src_stride_words) 652 1.1 tsutsui return EINVAL; 653 1.1 tsutsui 654 1.1 tsutsui error = nwb225_rop_wait(dc); 655 1.1 tsutsui if (__predict_false(error != 0)) 656 1.1 tsutsui return error; 657 1.1 tsutsui 658 1.1 tsutsui foreground &= dc->dc_planemask; 659 1.1 tsutsui background &= dc->dc_planemask; 660 1.1 tsutsui nwb225_rop_make_funcvec(dc, NWB225_ROP_LF_S, foreground, background, 661 1.1 tsutsui funcvec); 662 1.1 tsutsui nwb225_rop_set_funcvec(dc, funcvec); 663 1.1 tsutsui nwb225_rop_set_plane_mask(dc, dc->dc_planemask); 664 1.1 tsutsui 665 1.1 tsutsui /* Wait again as NEWS-OS does */ 666 1.1 tsutsui error = nwb225_rop_wait(dc); 667 1.1 tsutsui if (__predict_false(error != 0)) 668 1.1 tsutsui return error; 669 1.1 tsutsui 670 1.1 tsutsui bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh, 671 1.1 tsutsui NWB225_DST_ADDR(dy), dx); 672 1.1 tsutsui bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh, 673 1.1 tsutsui NWB225_SRC_ADDR(0) | NWB225_ROP_ADDR_FLAG_SET_SHIFT, 674 1.1 tsutsui source_bit_offset); 675 1.1 tsutsui bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh, 676 1.1 tsutsui NWB225_HWRITE_LIMIT(height) | NWB225_ROP_ADDR_FLAG_EXECUTE, 677 1.1 tsutsui dx + width); 678 1.1 tsutsui 679 1.1 tsutsui sp = src_words + (srcy * src_stride_words) + source_word_offset; 680 1.1 tsutsui row_skip_words = src_stride_words - row_words; 681 1.1 tsutsui for (row = 0; row < height; row++) { 682 1.1 tsutsui for (word = 0; word < row_words; word++) 683 1.1 tsutsui bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh, 684 1.1 tsutsui NWB225_HWRITE_DATA, *sp++); 685 1.1 tsutsui sp += row_skip_words; 686 1.1 tsutsui } 687 1.1 tsutsui 688 1.1 tsutsui /* Wait complete for polling ops */ 689 1.1 tsutsui error = nwb225_rop_wait(dc); 690 1.1 tsutsui 691 1.1 tsutsui return error; 692 1.1 tsutsui } 693 1.1 tsutsui 694 1.1 tsutsui static bus_size_t 695 1.1 tsutsui nwb225_krom_ascii_offset(u_int c) 696 1.1 tsutsui { 697 1.1 tsutsui u_int index; 698 1.1 tsutsui 699 1.1 tsutsui index = c - NWB225_KROM_ASCII_FIRST; 700 1.1 tsutsui return ((index & 0xe0) << 9) | ((index & 0x1f) << 7); 701 1.1 tsutsui } 702 1.1 tsutsui 703 1.1 tsutsui static void 704 1.1 tsutsui nwb225_krom_load_cell(struct fbbm_devconfig *dc, u_int c, uint16_t *cell) 705 1.1 tsutsui { 706 1.1 tsutsui bus_size_t offset; 707 1.1 tsutsui int row; 708 1.1 tsutsui 709 1.1 tsutsui memset(cell, 0, NWB225_CELL_HEIGHT * sizeof(*cell)); 710 1.1 tsutsui offset = nwb225_krom_ascii_offset(c); 711 1.1 tsutsui 712 1.1 tsutsui /* 713 1.1 tsutsui * The PROM renderer reads one 32-bit KROM row, keeps the upper word, 714 1.1 tsutsui * masks its low four bits, and places the 24 glyph rows after four 715 1.1 tsutsui * blank rows in the 16x30 cell. 716 1.1 tsutsui */ 717 1.1 tsutsui for (row = 0; row < NWB225_FONT_HEIGHT; row++) 718 1.1 tsutsui cell[NWB225_GLYPH_YOFFSET + row] = 719 1.1 tsutsui bus_space_read_2(dc->dc_bst, dc->dc_krom_bsh, 720 1.1 tsutsui offset + row * NWB225_KROM_ROWBYTES) & 721 1.1 tsutsui NWB225_KROM_ASCII_MASK; 722 1.1 tsutsui } 723 1.1 tsutsui 724 1.1 tsutsui static int 725 1.1 tsutsui nwb225_init_hardware(struct fbbm_devconfig *dc) 726 1.1 tsutsui { 727 1.1 tsutsui uint16_t status, value; 728 1.1 tsutsui int i, component; 729 1.1 tsutsui 730 1.1 tsutsui /* 731 1.1 tsutsui * Use the cold-init sequence used by the NWB-225 routine in the 732 1.1 tsutsui * NWS-1750 PROM. In particular, the second reset is intentional. 733 1.1 tsutsui * The serial console cold-boot experiment required the init block 734 1.1 tsutsui * followed by this reset before stable sync was established by CRTC. 735 1.1 tsutsui */ 736 1.1 tsutsui nwb225_rop_reset(dc); 737 1.1 tsutsui 738 1.1 tsutsui for (i = 0; i < __arraycount(nwb225_init_words); i++) 739 1.1 tsutsui bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh, 740 1.1 tsutsui NWB225_INIT_BASE + i * sizeof(uint16_t), 741 1.1 tsutsui nwb225_init_words[i]); 742 1.1 tsutsui 743 1.1 tsutsui status = bus_space_read_2(dc->dc_bst, dc->dc_rcont_bsh, NWB225_STATUS); 744 1.1 tsutsui if ((status & NWB225_STATUS_4PLANE) != 0) 745 1.1 tsutsui dc->dc_nplanes = 4; 746 1.1 tsutsui else 747 1.1 tsutsui dc->dc_nplanes = 8; 748 1.1 tsutsui dc->dc_planemask = (1U << dc->dc_nplanes) - 1; 749 1.1 tsutsui dc->dc_dispver = 750 1.1 tsutsui (status & NWB225_STATUS_DISPVER) >> NWB225_STATUS_DISPVER_SHIFT; 751 1.1 tsutsui 752 1.1 tsutsui nwb225_ctl_write(dc, 4, dc->dc_planemask); 753 1.1 tsutsui nwb225_ctl_write(dc, 5, 0); 754 1.1 tsutsui nwb225_ctl_write(dc, 6, 0x40); 755 1.1 tsutsui nwb225_ctl_write(dc, 7, 0); 756 1.1 tsutsui 757 1.1 tsutsui nwb225_rop_reset(dc); 758 1.1 tsutsui 759 1.1 tsutsui /* Complete the fixed PROM palette/control initialization */ 760 1.1 tsutsui for (i = 0; i < 256; i++) { 761 1.1 tsutsui bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh, 762 1.1 tsutsui NWB225_PAL_INDEX, i); 763 1.1 tsutsui for (component = 0; component < 3; component++) { 764 1.1 tsutsui value = nwb225_prom_palette[i & 0x0f][component] << 4; 765 1.1 tsutsui bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh, 766 1.1 tsutsui NWB225_PAL_DATA, value); 767 1.1 tsutsui } 768 1.1 tsutsui } 769 1.1 tsutsui 770 1.1 tsutsui bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh, NWB225_PLANE_CTRL, 0); 771 1.1 tsutsui 772 1.1 tsutsui return nwb225_rop_wait(dc); 773 1.1 tsutsui } 774 1.1 tsutsui 775 1.1 tsutsui static void 776 1.1 tsutsui fbbm_init_screen(struct fbbm_devconfig *dc) 777 1.1 tsutsui { 778 1.1 tsutsui 779 1.1 tsutsui dc->dc_fbwidth = NWB225_FB_WIDTH; 780 1.1 tsutsui dc->dc_fbheight = NWB225_FB_HEIGHT; 781 1.1 tsutsui dc->dc_width = NWB225_VIS_WIDTH; 782 1.1 tsutsui dc->dc_height = NWB225_VIS_HEIGHT; 783 1.1 tsutsui 784 1.1 tsutsui dc->dc_fontwidth = NWB225_FONT_WIDTH; 785 1.1 tsutsui dc->dc_fontheight = NWB225_FONT_HEIGHT; 786 1.1 tsutsui dc->dc_cellwidth = NWB225_CELL_WIDTH; 787 1.1 tsutsui dc->dc_cellheight = NWB225_CELL_HEIGHT; 788 1.1 tsutsui 789 1.1 tsutsui dc->dc_ncols = NWB225_TEXT_COLS; 790 1.1 tsutsui dc->dc_nrows = NWB225_TEXT_ROWS; 791 1.1 tsutsui dc->dc_xorigin = NWB225_TEXT_XORIGIN; 792 1.1 tsutsui dc->dc_yorigin = NWB225_TEXT_YORIGIN; 793 1.1 tsutsui 794 1.1 tsutsui dc->dc_wsscrdescr.name = "std"; 795 1.1 tsutsui dc->dc_wsscrdescr.ncols = dc->dc_ncols; 796 1.1 tsutsui dc->dc_wsscrdescr.nrows = dc->dc_nrows; 797 1.1 tsutsui dc->dc_wsscrdescr.textops = &fbbm_emulops; 798 1.1 tsutsui dc->dc_wsscrdescr.fontwidth = dc->dc_cellwidth; 799 1.1 tsutsui dc->dc_wsscrdescr.fontheight = dc->dc_cellheight; 800 1.1 tsutsui dc->dc_wsscrdescr.capabilities = WSSCREEN_REVERSE; 801 1.1 tsutsui dc->dc_wsscrdescr.modecookie = NULL; 802 1.1 tsutsui 803 1.1 tsutsui dc->dc_cursoron = 0; 804 1.1 tsutsui dc->dc_cursorrow = 0; 805 1.1 tsutsui dc->dc_cursorcol = 0; 806 1.1 tsutsui } 807 1.1 tsutsui 808 1.1 tsutsui /* 809 1.1 tsutsui * Clear the visible display region. 810 1.1 tsutsui * Called from both normal attach and early cnattach. 811 1.1 tsutsui */ 812 1.1 tsutsui static int 813 1.1 tsutsui fbbm_clear_screen(struct fbbm_devconfig *dc) 814 1.1 tsutsui { 815 1.1 tsutsui 816 1.1 tsutsui return nwb225_rop_fill_rect(dc, 0, 0, dc->dc_width, dc->dc_height, 0); 817 1.1 tsutsui } 818 1.1 tsutsui 819 1.1 tsutsui static uint32_t 820 1.1 tsutsui fbbm_attr_background(struct fbbm_devconfig *dc, long attr) 821 1.1 tsutsui { 822 1.1 tsutsui 823 1.1 tsutsui return (attr & WSATTR_REVERSE) != 0 ? dc->dc_planemask : 0; 824 1.1 tsutsui } 825 1.1 tsutsui 826 1.1 tsutsui /* 827 1.1 tsutsui * wsdisplay_emulops functions 828 1.1 tsutsui */ 829 1.1 tsutsui static void 830 1.1 tsutsui fbbm_cursor(void *cookie, int on, int row, int col) 831 1.1 tsutsui { 832 1.1 tsutsui struct fbbm_devconfig *dc = cookie; 833 1.1 tsutsui int x, y, error; 834 1.1 tsutsui 835 1.1 tsutsui if (dc->dc_cursoron != 0) { 836 1.1 tsutsui x = dc->dc_xorigin + dc->dc_cursorcol * dc->dc_cellwidth; 837 1.1 tsutsui y = dc->dc_yorigin + dc->dc_cursorrow * dc->dc_cellheight; 838 1.1 tsutsui error = nwb225_rop_copy_rect(dc, x, y, dc->dc_cellwidth, 839 1.1 tsutsui dc->dc_cellheight, x, y, NWB225_ROP_LF_DI); 840 1.1 tsutsui if (error != 0) 841 1.1 tsutsui return; 842 1.1 tsutsui dc->dc_cursoron = 0; 843 1.1 tsutsui } 844 1.1 tsutsui 845 1.1 tsutsui dc->dc_cursorrow = row; 846 1.1 tsutsui dc->dc_cursorcol = col; 847 1.1 tsutsui if (on == 0) 848 1.1 tsutsui return; 849 1.1 tsutsui if (row < 0 || row >= dc->dc_nrows || col < 0 || col >= dc->dc_ncols) 850 1.1 tsutsui return; 851 1.1 tsutsui 852 1.1 tsutsui x = dc->dc_xorigin + col * dc->dc_cellwidth; 853 1.1 tsutsui y = dc->dc_yorigin + row * dc->dc_cellheight; 854 1.1 tsutsui error = nwb225_rop_copy_rect(dc, x, y, dc->dc_cellwidth, 855 1.1 tsutsui dc->dc_cellheight, x, y, NWB225_ROP_LF_DI); 856 1.1 tsutsui if (error == 0) 857 1.1 tsutsui dc->dc_cursoron = 1; 858 1.1 tsutsui } 859 1.1 tsutsui 860 1.1 tsutsui static int 861 1.1 tsutsui fbbm_mapchar(void *cookie, int c, u_int *cp) 862 1.1 tsutsui { 863 1.1 tsutsui 864 1.1 tsutsui if (c < NWB225_KROM_ASCII_FIRST || c > NWB225_KROM_ASCII_LAST) { 865 1.1 tsutsui *cp = ' '; 866 1.1 tsutsui return 0; 867 1.1 tsutsui } 868 1.1 tsutsui 869 1.1 tsutsui *cp = c; 870 1.1 tsutsui return 5; 871 1.1 tsutsui } 872 1.1 tsutsui 873 1.1 tsutsui static void 874 1.1 tsutsui fbbm_putchar(void *cookie, int row, int col, u_int uc, long attr) 875 1.1 tsutsui { 876 1.1 tsutsui struct fbbm_devconfig *dc = cookie; 877 1.1 tsutsui uint16_t cell[NWB225_CELL_HEIGHT]; 878 1.1 tsutsui uint32_t foreground, background; 879 1.1 tsutsui int x, y; 880 1.1 tsutsui 881 1.1 tsutsui if (__predict_false(row < 0 || row >= dc->dc_nrows || 882 1.1 tsutsui col < 0 || col >= dc->dc_ncols)) 883 1.1 tsutsui return; 884 1.1 tsutsui if (uc < NWB225_KROM_ASCII_FIRST || uc > NWB225_KROM_ASCII_LAST) 885 1.1 tsutsui uc = ' '; 886 1.1 tsutsui 887 1.1 tsutsui nwb225_krom_load_cell(dc, uc, cell); 888 1.1 tsutsui background = fbbm_attr_background(dc, attr); 889 1.1 tsutsui foreground = (~background) & dc->dc_planemask; 890 1.1 tsutsui x = dc->dc_xorigin + col * dc->dc_cellwidth; 891 1.1 tsutsui y = dc->dc_yorigin + row * dc->dc_cellheight; 892 1.1 tsutsui 893 1.1 tsutsui (void)nwb225_rop_hwrite(dc, cell, 1, 0, 0, dc->dc_cellwidth, 894 1.1 tsutsui dc->dc_cellheight, x, y, foreground, background); 895 1.1 tsutsui } 896 1.1 tsutsui 897 1.1 tsutsui static void 898 1.1 tsutsui fbbm_copycols(void *cookie, int row, int srccol, int dstcol, int ncols) 899 1.1 tsutsui { 900 1.1 tsutsui struct fbbm_devconfig *dc = cookie; 901 1.1 tsutsui int sx, dx, y, width; 902 1.1 tsutsui 903 1.1 tsutsui if (ncols <= 0 || row < 0 || row >= dc->dc_nrows) 904 1.1 tsutsui return; 905 1.1 tsutsui if (srccol < 0 || dstcol < 0 || srccol + ncols > dc->dc_ncols || 906 1.1 tsutsui dstcol + ncols > dc->dc_ncols) 907 1.1 tsutsui return; 908 1.1 tsutsui if (srccol == dstcol) 909 1.1 tsutsui return; 910 1.1 tsutsui 911 1.1 tsutsui sx = dc->dc_xorigin + srccol * dc->dc_cellwidth; 912 1.1 tsutsui dx = dc->dc_xorigin + dstcol * dc->dc_cellwidth; 913 1.1 tsutsui y = dc->dc_yorigin + row * dc->dc_cellheight; 914 1.1 tsutsui width = ncols * dc->dc_cellwidth; 915 1.1 tsutsui (void)nwb225_rop_copy_rect(dc, sx, y, width, dc->dc_cellheight, 916 1.1 tsutsui dx, y, NWB225_ROP_LF_S); 917 1.1 tsutsui } 918 1.1 tsutsui 919 1.1 tsutsui static void 920 1.1 tsutsui fbbm_erasecols(void *cookie, int row, int col, int ncols, long attr) 921 1.1 tsutsui { 922 1.1 tsutsui struct fbbm_devconfig *dc = cookie; 923 1.1 tsutsui uint32_t background; 924 1.1 tsutsui int x, y, width; 925 1.1 tsutsui 926 1.1 tsutsui if (ncols <= 0 || row < 0 || row >= dc->dc_nrows) 927 1.1 tsutsui return; 928 1.1 tsutsui if (col < 0 || col + ncols > dc->dc_ncols) 929 1.1 tsutsui return; 930 1.1 tsutsui 931 1.1 tsutsui x = dc->dc_xorigin + col * dc->dc_cellwidth; 932 1.1 tsutsui y = dc->dc_yorigin + row * dc->dc_cellheight; 933 1.1 tsutsui width = ncols * dc->dc_cellwidth; 934 1.1 tsutsui background = fbbm_attr_background(dc, attr); 935 1.1 tsutsui (void)nwb225_rop_fill_rect(dc, x, y, width, dc->dc_cellheight, 936 1.1 tsutsui background); 937 1.1 tsutsui } 938 1.1 tsutsui 939 1.1 tsutsui static void 940 1.1 tsutsui fbbm_copyrows(void *cookie, int srcrow, int dstrow, int nrows) 941 1.1 tsutsui { 942 1.1 tsutsui struct fbbm_devconfig *dc = cookie; 943 1.1 tsutsui int x, sy, dy, height; 944 1.1 tsutsui 945 1.1 tsutsui if (nrows <= 0 || srcrow < 0 || dstrow < 0 || 946 1.1 tsutsui srcrow + nrows > dc->dc_nrows || dstrow + nrows > dc->dc_nrows) 947 1.1 tsutsui return; 948 1.1 tsutsui if (srcrow == dstrow) 949 1.1 tsutsui return; 950 1.1 tsutsui 951 1.1 tsutsui x = dc->dc_xorigin; 952 1.1 tsutsui sy = dc->dc_yorigin + srcrow * dc->dc_cellheight; 953 1.1 tsutsui dy = dc->dc_yorigin + dstrow * dc->dc_cellheight; 954 1.1 tsutsui height = nrows * dc->dc_cellheight; 955 1.1 tsutsui (void)nwb225_rop_copy_rect(dc, x, sy, 956 1.1 tsutsui dc->dc_ncols * dc->dc_cellwidth, height, x, dy, NWB225_ROP_LF_S); 957 1.1 tsutsui } 958 1.1 tsutsui 959 1.1 tsutsui static void 960 1.1 tsutsui fbbm_eraserows(void *cookie, int row, int nrows, long attr) 961 1.1 tsutsui { 962 1.1 tsutsui struct fbbm_devconfig *dc = cookie; 963 1.1 tsutsui uint32_t background; 964 1.1 tsutsui int x, y, height; 965 1.1 tsutsui 966 1.1 tsutsui if (nrows <= 0 || row < 0 || row + nrows > dc->dc_nrows) 967 1.1 tsutsui return; 968 1.1 tsutsui 969 1.1 tsutsui x = dc->dc_xorigin; 970 1.1 tsutsui y = dc->dc_yorigin + row * dc->dc_cellheight; 971 1.1 tsutsui height = nrows * dc->dc_cellheight; 972 1.1 tsutsui background = fbbm_attr_background(dc, attr); 973 1.1 tsutsui (void)nwb225_rop_fill_rect(dc, x, y, 974 1.1 tsutsui dc->dc_ncols * dc->dc_cellwidth, height, background); 975 1.1 tsutsui } 976 1.1 tsutsui 977 1.1 tsutsui static int 978 1.1 tsutsui fbbm_allocattr(void *cookie, int fg, int bg, int flags, long *attrp) 979 1.1 tsutsui { 980 1.1 tsutsui 981 1.1 tsutsui if ((flags & ~WSATTR_REVERSE) != 0) 982 1.1 tsutsui return EINVAL; 983 1.1 tsutsui 984 1.1 tsutsui *attrp = flags & WSATTR_REVERSE; 985 1.1 tsutsui return 0; 986 1.1 tsutsui } 987 1.1 tsutsui 988 1.1 tsutsui /* 989 1.1 tsutsui * wsdisplay_accessops functions 990 1.1 tsutsui */ 991 1.1 tsutsui static int 992 1.1 tsutsui fbbm_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l) 993 1.1 tsutsui { 994 1.1 tsutsui struct fbbm_softc *sc = v; 995 1.1 tsutsui struct fbbm_devconfig *dc = sc->sc_dc; 996 1.1 tsutsui struct wsdisplay_fbinfo *fbinfo; 997 1.1 tsutsui 998 1.1 tsutsui switch (cmd) { 999 1.1 tsutsui case WSDISPLAYIO_GTYPE: 1000 1.1 tsutsui *(u_int *)data = WSDISPLAY_TYPE_NWB225; 1001 1.1 tsutsui return 0; 1002 1.1 tsutsui 1003 1.1 tsutsui case WSDISPLAYIO_GINFO: 1004 1.1 tsutsui fbinfo = data; 1005 1.1 tsutsui fbinfo->height = dc->dc_height; 1006 1.1 tsutsui fbinfo->width = dc->dc_width; 1007 1.1 tsutsui fbinfo->depth = dc->dc_nplanes; 1008 1.1 tsutsui fbinfo->cmsize = 0; 1009 1.1 tsutsui return 0; 1010 1.1 tsutsui 1011 1.1 tsutsui case WSDISPLAYIO_SMODE: 1012 1.1 tsutsui sc->sc_wsmode = *(int *)data; 1013 1.1 tsutsui return 0; 1014 1.1 tsutsui 1015 1.1 tsutsui default: 1016 1.1 tsutsui break; 1017 1.1 tsutsui } 1018 1.1 tsutsui 1019 1.1 tsutsui return EPASSTHROUGH; 1020 1.1 tsutsui } 1021 1.1 tsutsui 1022 1.1 tsutsui static int 1023 1.1 tsutsui fbbm_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep, 1024 1.1 tsutsui int *ccolp, int *crowp, long *attrp) 1025 1.1 tsutsui { 1026 1.1 tsutsui struct fbbm_softc *sc = v; 1027 1.1 tsutsui struct fbbm_devconfig *dc = sc->sc_dc; 1028 1.1 tsutsui long attr; 1029 1.1 tsutsui int error; 1030 1.1 tsutsui 1031 1.1 tsutsui KASSERT(type == &dc->dc_wsscrdescr); 1032 1.1 tsutsui 1033 1.1 tsutsui if (sc->sc_nscreens != 0) 1034 1.1 tsutsui return ENOMEM; 1035 1.1 tsutsui 1036 1.1 tsutsui error = fbbm_allocattr(dc, 0, 0, 0, &attr); 1037 1.1 tsutsui if (error != 0) 1038 1.1 tsutsui return error; 1039 1.1 tsutsui 1040 1.1 tsutsui *cookiep = dc; 1041 1.1 tsutsui *ccolp = 0; 1042 1.1 tsutsui *crowp = 0; 1043 1.1 tsutsui *attrp = attr; 1044 1.1 tsutsui sc->sc_nscreens = 1; 1045 1.1 tsutsui 1046 1.1 tsutsui return 0; 1047 1.1 tsutsui } 1048 1.1 tsutsui 1049 1.1 tsutsui static void 1050 1.1 tsutsui fbbm_free_screen(void *v, void *cookie) 1051 1.1 tsutsui { 1052 1.1 tsutsui struct fbbm_softc *sc = v; 1053 1.1 tsutsui 1054 1.1 tsutsui KASSERT(sc->sc_nscreens == 1); 1055 1.1 tsutsui KASSERT(cookie == sc->sc_dc); 1056 1.1 tsutsui KASSERT(sc->sc_dc != &fbbm_console_dc); 1057 1.1 tsutsui sc->sc_nscreens = 0; 1058 1.1 tsutsui } 1059 1.1 tsutsui 1060 1.1 tsutsui static int 1061 1.1 tsutsui fbbm_show_screen(void *v, void *cookie, int waitok, 1062 1.1 tsutsui void (*cb)(void *, int, int), void *cbarg) 1063 1.1 tsutsui { 1064 1.1 tsutsui 1065 1.1 tsutsui return 0; 1066 1.1 tsutsui } 1067 1.1 tsutsui 1068 1.1 tsutsui int 1069 1.1 tsutsui fbbm_cnattach(void) 1070 1.1 tsutsui { 1071 1.1 tsutsui struct fbbm_devconfig *dc; 1072 1.1 tsutsui long attr; 1073 1.1 tsutsui 1074 1.1 tsutsui if (fbbm_console_initialized()) 1075 1.1 tsutsui return 0; 1076 1.1 tsutsui 1077 1.1 tsutsui dc = &fbbm_console_dc; 1078 1.1 tsutsui memset(dc, 0, sizeof(*dc)); 1079 1.1 tsutsui if (fbbm_probe(NEWS68K_BUS_SPACE_EIO, NWB225_RCONT_BASE) == 0) 1080 1.1 tsutsui return ENXIO; 1081 1.1 tsutsui 1082 1.1 tsutsui if (nwb225_map(dc, NEWS68K_BUS_SPACE_EIO, NWB225_RCONT_BASE) != 0) 1083 1.1 tsutsui goto out_clear; 1084 1.1 tsutsui 1085 1.1 tsutsui if (nwb225_init_hardware(dc) != 0) 1086 1.1 tsutsui goto out_unmap; 1087 1.1 tsutsui 1088 1.1 tsutsui fbbm_init_screen(dc); 1089 1.1 tsutsui if (fbbm_clear_screen(dc) != 0) 1090 1.1 tsutsui goto out_unmap; 1091 1.1 tsutsui 1092 1.1 tsutsui if (fbbm_allocattr(dc, 0, 0, 0, &attr)) 1093 1.1 tsutsui goto out_unmap; 1094 1.1 tsutsui 1095 1.1 tsutsui wsdisplay_cnattach(&dc->dc_wsscrdescr, dc, 0, 0, attr); 1096 1.1 tsutsui return 0; 1097 1.1 tsutsui 1098 1.1 tsutsui out_unmap: 1099 1.1 tsutsui nwb225_unmap(dc); 1100 1.1 tsutsui out_clear: 1101 1.1 tsutsui memset(dc, 0, sizeof(*dc)); 1102 1.1 tsutsui return 1; 1103 1.1 tsutsui } 1104