Home | History | Annotate | Line # | Download | only in dev
fbbm.c revision 1.1
      1  1.1  tsutsui /*	$NetBSD: fbbm.c,v 1.1 2026/09/20 10:29:11 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.1 2026/09/20 10:29:11 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  1.1  tsutsui /*	$NetBSD: fbbm.c,v 1.1 2026/09/20 10:29:11 tsutsui Exp $	*/
   1105  1.1  tsutsui 
   1106  1.1  tsutsui /*-
   1107  1.1  tsutsui  * Copyright (c) 2026 Izumi Tsutsui.  All rights reserved.
   1108  1.1  tsutsui  *
   1109  1.1  tsutsui  * Redistribution and use in source and binary forms, with or without
   1110  1.1  tsutsui  * modification, are permitted provided that the following conditions
   1111  1.1  tsutsui  * are met:
   1112  1.1  tsutsui  * 1. Redistributions of source code must retain the above copyright
   1113  1.1  tsutsui  *    notice, this list of conditions and the following disclaimer.
   1114  1.1  tsutsui  * 2. Redistributions in binary form must reproduce the above copyright
   1115  1.1  tsutsui  *    notice, this list of conditions and the following disclaimer in the
   1116  1.1  tsutsui  *    documentation and/or other materials provided with the distribution.
   1117  1.1  tsutsui  *
   1118  1.1  tsutsui  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   1119  1.1  tsutsui  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   1120  1.1  tsutsui  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   1121  1.1  tsutsui  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   1122  1.1  tsutsui  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   1123  1.1  tsutsui  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   1124  1.1  tsutsui  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   1125  1.1  tsutsui  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   1126  1.1  tsutsui  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   1127  1.1  tsutsui  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   1128  1.1  tsutsui  */
   1129  1.1  tsutsui 
   1130  1.1  tsutsui #include <sys/cdefs.h>
   1131  1.1  tsutsui __KERNEL_RCSID(0, "$NetBSD: fbbm.c,v 1.1 2026/09/20 10:29:11 tsutsui Exp $");
   1132  1.1  tsutsui 
   1133  1.1  tsutsui #include <sys/param.h>
   1134  1.1  tsutsui #include <sys/device.h>
   1135  1.1  tsutsui #include <sys/errno.h>
   1136  1.1  tsutsui #include <sys/ioctl.h>
   1137  1.1  tsutsui #include <sys/kmem.h>
   1138  1.1  tsutsui #include <sys/systm.h>
   1139  1.1  tsutsui 
   1140  1.1  tsutsui #include <machine/bus.h>
   1141  1.1  tsutsui 
   1142  1.1  tsutsui #include <news68k/dev/hbvar.h>
   1143  1.1  tsutsui #include <news68k/dev/nwb225reg.h>
   1144  1.1  tsutsui 
   1145  1.1  tsutsui #include <dev/wscons/wsconsio.h>
   1146  1.1  tsutsui #include <dev/wscons/wsdisplayvar.h>
   1147  1.1  tsutsui 
   1148  1.1  tsutsui #define NWB225_WAIT_MAX	100000
   1149  1.1  tsutsui 
   1150  1.1  tsutsui struct fbbm_devconfig {
   1151  1.1  tsutsui 	bus_space_tag_t dc_bst;
   1152  1.1  tsutsui 	bus_space_handle_t dc_rcont_bsh;
   1153  1.1  tsutsui 	bus_space_handle_t dc_krom_bsh;
   1154  1.1  tsutsui 
   1155  1.1  tsutsui 	int dc_nplanes;
   1156  1.1  tsutsui 	uint32_t dc_planemask;
   1157  1.1  tsutsui 	int dc_dispver;
   1158  1.1  tsutsui 
   1159  1.1  tsutsui 	int dc_fbwidth;
   1160  1.1  tsutsui 	int dc_fbheight;
   1161  1.1  tsutsui 	int dc_width;
   1162  1.1  tsutsui 	int dc_height;
   1163  1.1  tsutsui 
   1164  1.1  tsutsui 	int dc_fontwidth;
   1165  1.1  tsutsui 	int dc_fontheight;
   1166  1.1  tsutsui 	int dc_cellwidth;
   1167  1.1  tsutsui 	int dc_cellheight;
   1168  1.1  tsutsui 
   1169  1.1  tsutsui 	int dc_ncols;
   1170  1.1  tsutsui 	int dc_nrows;
   1171  1.1  tsutsui 	int dc_xorigin;
   1172  1.1  tsutsui 	int dc_yorigin;
   1173  1.1  tsutsui 
   1174  1.1  tsutsui 	int dc_cursoron;
   1175  1.1  tsutsui 	int dc_cursorrow;
   1176  1.1  tsutsui 	int dc_cursorcol;
   1177  1.1  tsutsui 
   1178  1.1  tsutsui 	struct wsscreen_descr dc_wsscrdescr;
   1179  1.1  tsutsui };
   1180  1.1  tsutsui 
   1181  1.1  tsutsui struct fbbm_softc {
   1182  1.1  tsutsui 	device_t sc_dev;
   1183  1.1  tsutsui 	struct fbbm_devconfig *sc_dc;
   1184  1.1  tsutsui 	int sc_nscreens;
   1185  1.1  tsutsui 	const struct wsscreen_descr *sc_scrdescs[1];
   1186  1.1  tsutsui 	struct wsscreen_list sc_scrlist;
   1187  1.1  tsutsui };
   1188  1.1  tsutsui 
   1189  1.1  tsutsui static int fbbm_match(device_t, cfdata_t, void *);
   1190  1.1  tsutsui static void fbbm_attach(device_t, device_t, void *);
   1191  1.1  tsutsui 
   1192  1.1  tsutsui static int nwb225_map(struct fbbm_devconfig *, bus_space_tag_t, bus_addr_t);
   1193  1.1  tsutsui static void nwb225_unmap(struct fbbm_devconfig *);
   1194  1.1  tsutsui static void nwb225_rop_reset(struct fbbm_devconfig *);
   1195  1.1  tsutsui static int nwb225_rop_wait(struct fbbm_devconfig *);
   1196  1.1  tsutsui static void nwb225_ctl_write(struct fbbm_devconfig *, uint16_t, uint16_t);
   1197  1.1  tsutsui static void nwb225_rop_set_plane_mask(struct fbbm_devconfig *, uint32_t);
   1198  1.1  tsutsui static void nwb225_rop_make_funcvec(struct fbbm_devconfig *, unsigned int,
   1199  1.1  tsutsui     uint32_t, uint32_t, uint8_t *);
   1200  1.1  tsutsui static void nwb225_rop_setfunc(struct fbbm_devconfig *, const uint8_t *);
   1201  1.1  tsutsui static void nwb225_rop_cinit(struct fbbm_devconfig *, const uint8_t *,
   1202  1.1  tsutsui     uint32_t, unsigned int);
   1203  1.1  tsutsui static int nwb225_rop_copy_rect(struct fbbm_devconfig *, int, int, int, int,
   1204  1.1  tsutsui     int, int, unsigned int);
   1205  1.1  tsutsui static int nwb225_rop_fill_rect(struct fbbm_devconfig *, int, int, int, int,
   1206  1.1  tsutsui     uint32_t);
   1207  1.1  tsutsui static int nwb225_rop_hwrite(struct fbbm_devconfig *, const uint16_t *, int,
   1208  1.1  tsutsui     int, int, int, int, int, int, uint32_t, uint32_t);
   1209  1.1  tsutsui static bus_size_t nwb225_krom_ascii_offset(unsigned int);
   1210  1.1  tsutsui static void nwb225_krom_load_cell(struct fbbm_devconfig *, unsigned int,
   1211  1.1  tsutsui     uint16_t *);
   1212  1.1  tsutsui static int nwb225_init_hardware(struct fbbm_devconfig *);
   1213  1.1  tsutsui 
   1214  1.1  tsutsui static void fbbm_init_screen(struct fbbm_devconfig *);
   1215  1.1  tsutsui static int fbbm_clear_screen(struct fbbm_devconfig *);
   1216  1.1  tsutsui static void fbbm_cursor(void *, int, int, int);
   1217  1.1  tsutsui static int fbbm_mapchar(void *, int, unsigned int *);
   1218  1.1  tsutsui static void fbbm_putchar(void *, int, int, u_int, long);
   1219  1.1  tsutsui static void fbbm_copycols(void *, int, int, int, int);
   1220  1.1  tsutsui static void fbbm_erasecols(void *, int, int, int, long);
   1221  1.1  tsutsui static void fbbm_copyrows(void *, int, int, int);
   1222  1.1  tsutsui static void fbbm_eraserows(void *, int, int, long);
   1223  1.1  tsutsui static int fbbm_allocattr(void *, int, int, int, long *);
   1224  1.1  tsutsui static int fbbm_ioctl(void *, void *, u_long, void *, int, struct lwp *);
   1225  1.1  tsutsui static int fbbm_alloc_screen(void *, const struct wsscreen_descr *, void **,
   1226  1.1  tsutsui     int *, int *, long *);
   1227  1.1  tsutsui static void fbbm_free_screen(void *, void *);
   1228  1.1  tsutsui static int fbbm_show_screen(void *, void *, int, void (*)(void *, int, int),
   1229  1.1  tsutsui     void *);
   1230  1.1  tsutsui 
   1231  1.1  tsutsui CFATTACH_DECL_NEW(fbbm, sizeof(struct fbbm_softc),
   1232  1.1  tsutsui     fbbm_match, fbbm_attach, NULL, NULL);
   1233  1.1  tsutsui 
   1234  1.1  tsutsui static const struct wsdisplay_emulops fbbm_emulops = {
   1235  1.1  tsutsui 	.cursor = fbbm_cursor,
   1236  1.1  tsutsui 	.mapchar = fbbm_mapchar,
   1237  1.1  tsutsui 	.putchar = fbbm_putchar,
   1238  1.1  tsutsui 	.copycols = fbbm_copycols,
   1239  1.1  tsutsui 	.erasecols = fbbm_erasecols,
   1240  1.1  tsutsui 	.copyrows = fbbm_copyrows,
   1241  1.1  tsutsui 	.eraserows = fbbm_eraserows,
   1242  1.1  tsutsui 	.allocattr = fbbm_allocattr,
   1243  1.1  tsutsui 	.replaceattr = NULL,
   1244  1.1  tsutsui };
   1245  1.1  tsutsui 
   1246  1.1  tsutsui static const struct wsdisplay_accessops fbbm_accessops = {
   1247  1.1  tsutsui 	.ioctl = fbbm_ioctl,
   1248  1.1  tsutsui 	.mmap = NULL,
   1249  1.1  tsutsui 	.alloc_screen = fbbm_alloc_screen,
   1250  1.1  tsutsui 	.free_screen = fbbm_free_screen,
   1251  1.1  tsutsui 	.show_screen = fbbm_show_screen,
   1252  1.1  tsutsui 	.load_font = NULL,
   1253  1.1  tsutsui 	.pollc = NULL,
   1254  1.1  tsutsui 	.scroll = NULL,
   1255  1.1  tsutsui };
   1256  1.1  tsutsui 
   1257  1.1  tsutsui /* Sony FBBM logical Boolean functions used by the initial text backend. */
   1258  1.1  tsutsui #define NWB225_BF_0	0x0
   1259  1.1  tsutsui #define NWB225_BF_S	0x3
   1260  1.1  tsutsui #define NWB225_BF_DI	0xa
   1261  1.1  tsutsui #define NWB225_BF_1	0xf
   1262  1.1  tsutsui 
   1263  1.1  tsutsui /*
   1264  1.1  tsutsui  * Logical FBBM function to 51X hardware function conversion recovered from
   1265  1.1  tsutsui  * NEWS-OS fbbm_51x.o.
   1266  1.1  tsutsui  */
   1267  1.1  tsutsui static const uint8_t nwb225_fccnvtab[16] = {
   1268  1.1  tsutsui 	0x03, 0x0b, 0x07, 0x0f, 0x02, 0x0a, 0x06, 0x0e,
   1269  1.1  tsutsui 	0x01, 0x09, 0x05, 0x0d, 0x00, 0x08, 0x04, 0x0c,
   1270  1.1  tsutsui };
   1271  1.1  tsutsui 
   1272  1.1  tsutsui /*
   1273  1.1  tsutsui  * Function conversion for a constant 0/1 source, indexed by
   1274  1.1  tsutsui  * [logical_function][source_bit].
   1275  1.1  tsutsui  */
   1276  1.1  tsutsui static const uint8_t nwb225_func01tab[16][2] = {
   1277  1.1  tsutsui 	{ 0x03, 0x03 }, { 0x03, 0x0a }, { 0x03, 0x05 }, { 0x03, 0x0c },
   1278  1.1  tsutsui 	{ 0x0a, 0x03 }, { 0x0a, 0x0a }, { 0x0a, 0x05 }, { 0x0a, 0x0c },
   1279  1.1  tsutsui 	{ 0x05, 0x03 }, { 0x05, 0x0a }, { 0x05, 0x05 }, { 0x05, 0x0c },
   1280  1.1  tsutsui 	{ 0x0c, 0x03 }, { 0x0c, 0x0a }, { 0x0c, 0x05 }, { 0x0c, 0x0c },
   1281  1.1  tsutsui };
   1282  1.1  tsutsui 
   1283  1.1  tsutsui /*
   1284  1.1  tsutsui  * Fixed initialization words written by the NWS-1750 PROM and NEWS-OS
   1285  1.1  tsutsui  * 51X setup.  Their individual timing/control semantics are intentionally
   1286  1.1  tsutsui  * not inferred here.
   1287  1.1  tsutsui  */
   1288  1.1  tsutsui static const uint16_t nwb225_init_words[] = {
   1289  1.1  tsutsui 	0x0400, 0x0002, 0x0005, 0x00d8,
   1290  1.1  tsutsui 	0x0000, 0x0006, 0x0000,
   1291  1.1  tsutsui };
   1292  1.1  tsutsui 
   1293  1.1  tsutsui /*
   1294  1.1  tsutsui  * 4-bit component values from the NWS-1750 PROM NWB-225 module.  The PROM
   1295  1.1  tsutsui  * repeats this 16-entry table through all 256 palette indices and writes
   1296  1.1  tsutsui  * each component after shifting it left by four bits.
   1297  1.1  tsutsui  */
   1298  1.1  tsutsui static const uint8_t nwb225_prom_palette[16][3] = {
   1299  1.1  tsutsui 	{  0,  0,  0 }, {  0,  0,  4 },
   1300  1.1  tsutsui 	{  0,  4,  0 }, {  0,  4,  4 },
   1301  1.1  tsutsui 	{  4,  0,  0 }, {  4,  0,  4 },
   1302  1.1  tsutsui 	{  4,  4,  0 }, {  4,  4,  4 },
   1303  1.1  tsutsui 	{  8,  8,  8 }, {  0,  0, 15 },
   1304  1.1  tsutsui 	{  0, 15,  0 }, {  0, 15, 15 },
   1305  1.1  tsutsui 	{ 15,  0,  0 }, { 15,  0, 15 },
   1306  1.1  tsutsui 	{ 15, 15,  0 }, { 15, 15, 15 },
   1307  1.1  tsutsui };
   1308  1.1  tsutsui 
   1309  1.1  tsutsui static int
   1310  1.1  tsutsui fbbm_match(device_t parent, cfdata_t cf, void *aux)
   1311  1.1  tsutsui {
   1312  1.1  tsutsui 	struct hb_attach_args *ha = aux;
   1313  1.1  tsutsui 	bus_space_handle_t bsh;
   1314  1.1  tsutsui 	int rv;
   1315  1.1  tsutsui 
   1316  1.1  tsutsui 	__USE(parent);
   1317  1.1  tsutsui 	__USE(cf);
   1318  1.1  tsutsui 
   1319  1.1  tsutsui 	if (strcmp(ha->ha_name, "fbbm") != 0)
   1320  1.1  tsutsui 		return 0;
   1321  1.1  tsutsui 	if (ha->ha_address != NWB225_RCONT_BASE)
   1322  1.1  tsutsui 		return 0;
   1323  1.1  tsutsui 
   1324  1.1  tsutsui 	if (bus_space_map(ha->ha_bust, ha->ha_address, NWB225_RCONT_SIZE,
   1325  1.1  tsutsui 	    0, &bsh) != 0)
   1326  1.1  tsutsui 		return 0;
   1327  1.1  tsutsui 
   1328  1.1  tsutsui 	/* NEWS-OS fb225_probe() used a byte-sized badaddr() at this base. */
   1329  1.1  tsutsui 	rv = news68k_bus_space_probe(ha->ha_bust, bsh, 0, 1);
   1330  1.1  tsutsui 	bus_space_unmap(ha->ha_bust, bsh, NWB225_RCONT_SIZE);
   1331  1.1  tsutsui 
   1332  1.1  tsutsui 	return rv;
   1333  1.1  tsutsui }
   1334  1.1  tsutsui 
   1335  1.1  tsutsui static void
   1336  1.1  tsutsui fbbm_attach(device_t parent, device_t self, void *aux)
   1337  1.1  tsutsui {
   1338  1.1  tsutsui 	struct fbbm_softc *sc = device_private(self);
   1339  1.1  tsutsui 	struct hb_attach_args *ha = aux;
   1340  1.1  tsutsui 	struct fbbm_devconfig *dc;
   1341  1.1  tsutsui 	struct wsemuldisplaydev_attach_args waa;
   1342  1.1  tsutsui 	int error;
   1343  1.1  tsutsui 
   1344  1.1  tsutsui 	__USE(parent);
   1345  1.1  tsutsui 
   1346  1.1  tsutsui 	sc->sc_dev = self;
   1347  1.1  tsutsui 
   1348  1.1  tsutsui 	dc = kmem_zalloc(sizeof(*dc), KM_SLEEP);
   1349  1.1  tsutsui 	error = nwb225_map(dc, ha->ha_bust, ha->ha_address);
   1350  1.1  tsutsui 	if (error != 0) {
   1351  1.1  tsutsui 		aprint_error_dev(self, "unable to map device registers: %d\n",
   1352  1.1  tsutsui 		    error);
   1353  1.1  tsutsui 		kmem_free(dc, sizeof(*dc));
   1354  1.1  tsutsui 		return;
   1355  1.1  tsutsui 	}
   1356  1.1  tsutsui 
   1357  1.1  tsutsui 	error = nwb225_init_hardware(dc);
   1358  1.1  tsutsui 	if (error != 0) {
   1359  1.1  tsutsui 		aprint_error_dev(self, "controller initialization failed: %d\n",
   1360  1.1  tsutsui 		    error);
   1361  1.1  tsutsui 		nwb225_unmap(dc);
   1362  1.1  tsutsui 		kmem_free(dc, sizeof(*dc));
   1363  1.1  tsutsui 		return;
   1364  1.1  tsutsui 	}
   1365  1.1  tsutsui 
   1366  1.1  tsutsui 	fbbm_init_screen(dc);
   1367  1.1  tsutsui 	error = fbbm_clear_screen(dc);
   1368  1.1  tsutsui 	if (error != 0) {
   1369  1.1  tsutsui 		aprint_error_dev(self, "unable to clear text screen: %d\n", error);
   1370  1.1  tsutsui 		nwb225_unmap(dc);
   1371  1.1  tsutsui 		kmem_free(dc, sizeof(*dc));
   1372  1.1  tsutsui 		return;
   1373  1.1  tsutsui 	}
   1374  1.1  tsutsui 
   1375  1.1  tsutsui 	sc->sc_dc = dc;
   1376  1.1  tsutsui 	sc->sc_nscreens = 0;
   1377  1.1  tsutsui 	sc->sc_scrdescs[0] = &dc->dc_wsscrdescr;
   1378  1.1  tsutsui 	sc->sc_scrlist.nscreens = __arraycount(sc->sc_scrdescs);
   1379  1.1  tsutsui 	sc->sc_scrlist.screens = sc->sc_scrdescs;
   1380  1.1  tsutsui 
   1381  1.1  tsutsui 	aprint_normal(": NWB-225 compatible, %d x %d, %d planes, "
   1382  1.1  tsutsui 	    "display version %d\n", dc->dc_width, dc->dc_height,
   1383  1.1  tsutsui 	    dc->dc_nplanes, dc->dc_dispver);
   1384  1.1  tsutsui 
   1385  1.1  tsutsui 	waa.console = 0;
   1386  1.1  tsutsui 	waa.scrdata = &sc->sc_scrlist;
   1387  1.1  tsutsui 	waa.accessops = &fbbm_accessops;
   1388  1.1  tsutsui 	waa.accesscookie = sc;
   1389  1.1  tsutsui 
   1390  1.1  tsutsui 	config_found(self, &waa, wsemuldisplaydevprint, CFARGS_NONE);
   1391  1.1  tsutsui }
   1392  1.1  tsutsui 
   1393  1.1  tsutsui static int
   1394  1.1  tsutsui nwb225_map(struct fbbm_devconfig *dc, bus_space_tag_t bst,
   1395  1.1  tsutsui     bus_addr_t rcont_addr)
   1396  1.1  tsutsui {
   1397  1.1  tsutsui 	int error;
   1398  1.1  tsutsui 
   1399  1.1  tsutsui 	dc->dc_bst = bst;
   1400  1.1  tsutsui 
   1401  1.1  tsutsui 	error = bus_space_map(bst, rcont_addr, NWB225_RCONT_SIZE, 0,
   1402  1.1  tsutsui 	    &dc->dc_rcont_bsh);
   1403  1.1  tsutsui 	if (error != 0)
   1404  1.1  tsutsui 		return error;
   1405  1.1  tsutsui 
   1406  1.1  tsutsui 	error = bus_space_map(bst, NWB225_KROM_BASE, NWB225_KROM_SIZE, 0,
   1407  1.1  tsutsui 	    &dc->dc_krom_bsh);
   1408  1.1  tsutsui 	if (error != 0) {
   1409  1.1  tsutsui 		bus_space_unmap(bst, dc->dc_rcont_bsh, NWB225_RCONT_SIZE);
   1410  1.1  tsutsui 		return error;
   1411  1.1  tsutsui 	}
   1412  1.1  tsutsui 
   1413  1.1  tsutsui 	return 0;
   1414  1.1  tsutsui }
   1415  1.1  tsutsui 
   1416  1.1  tsutsui static void
   1417  1.1  tsutsui nwb225_unmap(struct fbbm_devconfig *dc)
   1418  1.1  tsutsui {
   1419  1.1  tsutsui 
   1420  1.1  tsutsui 	bus_space_unmap(dc->dc_bst, dc->dc_krom_bsh, NWB225_KROM_SIZE);
   1421  1.1  tsutsui 	bus_space_unmap(dc->dc_bst, dc->dc_rcont_bsh, NWB225_RCONT_SIZE);
   1422  1.1  tsutsui }
   1423  1.1  tsutsui 
   1424  1.1  tsutsui static void
   1425  1.1  tsutsui nwb225_rop_reset(struct fbbm_devconfig *dc)
   1426  1.1  tsutsui {
   1427  1.1  tsutsui 
   1428  1.1  tsutsui 	/* fb51X_rop_reset() and the PROM both perform this 0 -> 1 sequence. */
   1429  1.1  tsutsui 	bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh, NWB225_STATUS, 0);
   1430  1.1  tsutsui 	bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh, NWB225_STATUS, 1);
   1431  1.1  tsutsui }
   1432  1.1  tsutsui 
   1433  1.1  tsutsui static int
   1434  1.1  tsutsui nwb225_rop_wait(struct fbbm_devconfig *dc)
   1435  1.1  tsutsui {
   1436  1.1  tsutsui 	uint16_t status;
   1437  1.1  tsutsui 	int i;
   1438  1.1  tsutsui 
   1439  1.1  tsutsui 	for (i = 0; i < NWB225_WAIT_MAX; i++) {
   1440  1.1  tsutsui 		status = bus_space_read_2(dc->dc_bst, dc->dc_rcont_bsh,
   1441  1.1  tsutsui 		    NWB225_STATUS);
   1442  1.1  tsutsui 		if ((status & NWB225_STATUS_BUSY) == 0)
   1443  1.1  tsutsui 			return 0;
   1444  1.1  tsutsui 	}
   1445  1.1  tsutsui 
   1446  1.1  tsutsui 	/* Match the NEWS-OS recovery action, but report failure to K1 attach. */
   1447  1.1  tsutsui 	nwb225_rop_reset(dc);
   1448  1.1  tsutsui 	return ETIMEDOUT;
   1449  1.1  tsutsui }
   1450  1.1  tsutsui 
   1451  1.1  tsutsui static void
   1452  1.1  tsutsui nwb225_ctl_write(struct fbbm_devconfig *dc, uint16_t selector,
   1453  1.1  tsutsui     uint16_t value)
   1454  1.1  tsutsui {
   1455  1.1  tsutsui 
   1456  1.1  tsutsui 	bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
   1457  1.1  tsutsui 	    NWB225_CTL_SELECT, selector);
   1458  1.1  tsutsui 	bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
   1459  1.1  tsutsui 	    NWB225_CTL_DATA, value);
   1460  1.1  tsutsui }
   1461  1.1  tsutsui 
   1462  1.1  tsutsui static void
   1463  1.1  tsutsui nwb225_rop_set_plane_mask(struct fbbm_devconfig *dc, uint32_t planemask)
   1464  1.1  tsutsui {
   1465  1.1  tsutsui 	uint16_t hwmask;
   1466  1.1  tsutsui 
   1467  1.1  tsutsui 	hwmask = (uint16_t)(~(planemask << 8) & 0xff00);
   1468  1.1  tsutsui 	bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
   1469  1.1  tsutsui 	    NWB225_PLANE_CTRL, hwmask);
   1470  1.1  tsutsui }
   1471  1.1  tsutsui 
   1472  1.1  tsutsui static void
   1473  1.1  tsutsui nwb225_rop_make_funcvec(struct fbbm_devconfig *dc, unsigned int func,
   1474  1.1  tsutsui     uint32_t fore, uint32_t aux, uint8_t *funcvec)
   1475  1.1  tsutsui {
   1476  1.1  tsutsui 	uint8_t tmp[4];
   1477  1.1  tsutsui 	unsigned int i, index;
   1478  1.1  tsutsui 
   1479  1.1  tsutsui 	func &= 0x0f;
   1480  1.1  tsutsui 	tmp[0] = (func & 0x0c) | (func >> 2);
   1481  1.1  tsutsui 	tmp[1] = (func >> 2) | ((func << 2) & 0x0c);
   1482  1.1  tsutsui 	tmp[2] = func;
   1483  1.1  tsutsui 	tmp[3] = ((func << 2) & 0x0c) | (func & 0x03);
   1484  1.1  tsutsui 
   1485  1.1  tsutsui 	for (i = 0; i < (unsigned int)dc->dc_nplanes; i++) {
   1486  1.1  tsutsui 		index = ((fore & 1) << 1) | (aux & 1);
   1487  1.1  tsutsui 		funcvec[i] = tmp[index];
   1488  1.1  tsutsui 		fore >>= 1;
   1489  1.1  tsutsui 		aux >>= 1;
   1490  1.1  tsutsui 	}
   1491  1.1  tsutsui }
   1492  1.1  tsutsui 
   1493  1.1  tsutsui static void
   1494  1.1  tsutsui nwb225_rop_setfunc(struct fbbm_devconfig *dc, const uint8_t *funcvec)
   1495  1.1  tsutsui {
   1496  1.1  tsutsui 	unsigned int i;
   1497  1.1  tsutsui 
   1498  1.1  tsutsui 	for (i = 0; i < (unsigned int)dc->dc_nplanes; i++)
   1499  1.1  tsutsui 		bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
   1500  1.1  tsutsui 		    NWB225_ROP_FUNC + i * sizeof(uint16_t),
   1501  1.1  tsutsui 		    nwb225_fccnvtab[funcvec[i] & 0x0f]);
   1502  1.1  tsutsui }
   1503  1.1  tsutsui 
   1504  1.1  tsutsui static void
   1505  1.1  tsutsui nwb225_rop_cinit(struct fbbm_devconfig *dc, const uint8_t *funcvec,
   1506  1.1  tsutsui     uint32_t planemask, unsigned int source_bit)
   1507  1.1  tsutsui {
   1508  1.1  tsutsui 	unsigned int i;
   1509  1.1  tsutsui 
   1510  1.1  tsutsui 	nwb225_rop_set_plane_mask(dc, planemask);
   1511  1.1  tsutsui 	source_bit &= 1;
   1512  1.1  tsutsui 	for (i = 0; i < (unsigned int)dc->dc_nplanes; i++)
   1513  1.1  tsutsui 		bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
   1514  1.1  tsutsui 		    NWB225_ROP_FUNC + i * sizeof(uint16_t),
   1515  1.1  tsutsui 		    nwb225_func01tab[funcvec[i] & 0x0f][source_bit]);
   1516  1.1  tsutsui }
   1517  1.1  tsutsui 
   1518  1.1  tsutsui static int
   1519  1.1  tsutsui nwb225_rect_valid(struct fbbm_devconfig *dc, int x, int y, int width,
   1520  1.1  tsutsui     int height)
   1521  1.1  tsutsui {
   1522  1.1  tsutsui 
   1523  1.1  tsutsui 	if (x < 0 || y < 0 || width <= 0 || height <= 0)
   1524  1.1  tsutsui 		return 0;
   1525  1.1  tsutsui 	if (x >= dc->dc_fbwidth || y >= dc->dc_fbheight)
   1526  1.1  tsutsui 		return 0;
   1527  1.1  tsutsui 	if (width > dc->dc_fbwidth - x || height > dc->dc_fbheight - y)
   1528  1.1  tsutsui 		return 0;
   1529  1.1  tsutsui 
   1530  1.1  tsutsui 	return 1;
   1531  1.1  tsutsui }
   1532  1.1  tsutsui 
   1533  1.1  tsutsui static int
   1534  1.1  tsutsui nwb225_rop_copy_rect(struct fbbm_devconfig *dc, int sx, int sy, int width,
   1535  1.1  tsutsui     int height, int dx, int dy, unsigned int func)
   1536  1.1  tsutsui {
   1537  1.1  tsutsui 	uint8_t funcvec[8];
   1538  1.1  tsutsui 	bus_size_t command;
   1539  1.1  tsutsui 	int error;
   1540  1.1  tsutsui 
   1541  1.1  tsutsui 	if (width <= 0 || height <= 0)
   1542  1.1  tsutsui 		return 0;
   1543  1.1  tsutsui 	if (nwb225_rect_valid(dc, sx, sy, width, height) == 0 ||
   1544  1.1  tsutsui 	    nwb225_rect_valid(dc, dx, dy, width, height) == 0)
   1545  1.1  tsutsui 		return EINVAL;
   1546  1.1  tsutsui 
   1547  1.1  tsutsui 	error = nwb225_rop_wait(dc);
   1548  1.1  tsutsui 	if (error != 0)
   1549  1.1  tsutsui 		return error;
   1550  1.1  tsutsui 
   1551  1.1  tsutsui 	nwb225_rop_make_funcvec(dc, func, dc->dc_planemask, 0, funcvec);
   1552  1.1  tsutsui 	nwb225_rop_setfunc(dc, funcvec);
   1553  1.1  tsutsui 	nwb225_rop_set_plane_mask(dc, dc->dc_planemask);
   1554  1.1  tsutsui 
   1555  1.1  tsutsui 	if (sx >= dx) {
   1556  1.1  tsutsui 		if (sy >= dy) {
   1557  1.1  tsutsui 			command = NWB225_ROP_COPY_FF;
   1558  1.1  tsutsui 			bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
   1559  1.1  tsutsui 			    command, 0);
   1560  1.1  tsutsui 			bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
   1561  1.1  tsutsui 			    NWB225_DST_X + dy * sizeof(uint16_t), dx);
   1562  1.1  tsutsui 			bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
   1563  1.1  tsutsui 			    NWB225_SRC_X + sy * sizeof(uint16_t), sx);
   1564  1.1  tsutsui 		} else {
   1565  1.1  tsutsui 			command = NWB225_ROP_COPY_FR;
   1566  1.1  tsutsui 			bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
   1567  1.1  tsutsui 			    command, 0);
   1568  1.1  tsutsui 			bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
   1569  1.1  tsutsui 			    NWB225_DST_X + (dy + height - 1) *
   1570  1.1  tsutsui 			    sizeof(uint16_t), dx);
   1571  1.1  tsutsui 			bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
   1572  1.1  tsutsui 			    NWB225_SRC_X + (sy + height - 1) *
   1573  1.1  tsutsui 			    sizeof(uint16_t), sx);
   1574  1.1  tsutsui 		}
   1575  1.1  tsutsui 		bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
   1576  1.1  tsutsui 		    NWB225_ROP_EDGE + (height - 1) * sizeof(uint16_t),
   1577  1.1  tsutsui 		    dx + width);
   1578  1.1  tsutsui 	} else {
   1579  1.1  tsutsui 		if (sy >= dy) {
   1580  1.1  tsutsui 			command = NWB225_ROP_COPY_RF;
   1581  1.1  tsutsui 			bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
   1582  1.1  tsutsui 			    command, 0);
   1583  1.1  tsutsui 			bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
   1584  1.1  tsutsui 			    NWB225_DST_X + dy * sizeof(uint16_t), dx + width);
   1585  1.1  tsutsui 			bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
   1586  1.1  tsutsui 			    NWB225_SRC_X + sy * sizeof(uint16_t), sx + width);
   1587  1.1  tsutsui 		} else {
   1588  1.1  tsutsui 			command = NWB225_ROP_COPY_RR;
   1589  1.1  tsutsui 			bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
   1590  1.1  tsutsui 			    command, 0);
   1591  1.1  tsutsui 			bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
   1592  1.1  tsutsui 			    NWB225_DST_X + (dy + height - 1) *
   1593  1.1  tsutsui 			    sizeof(uint16_t), dx + width);
   1594  1.1  tsutsui 			bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
   1595  1.1  tsutsui 			    NWB225_SRC_X + (sy + height - 1) *
   1596  1.1  tsutsui 			    sizeof(uint16_t), sx + width);
   1597  1.1  tsutsui 		}
   1598  1.1  tsutsui 		bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
   1599  1.1  tsutsui 		    NWB225_ROP_EDGE + (height - 1) * sizeof(uint16_t), dx);
   1600  1.1  tsutsui 	}
   1601  1.1  tsutsui 
   1602  1.1  tsutsui 	return nwb225_rop_wait(dc);
   1603  1.1  tsutsui }
   1604  1.1  tsutsui 
   1605  1.1  tsutsui static int
   1606  1.1  tsutsui nwb225_rop_fill_rect(struct fbbm_devconfig *dc, int x, int y, int width,
   1607  1.1  tsutsui     int height, uint32_t color)
   1608  1.1  tsutsui {
   1609  1.1  tsutsui 	uint8_t funcvec[8];
   1610  1.1  tsutsui 	int error;
   1611  1.1  tsutsui 
   1612  1.1  tsutsui 	if (width <= 0 || height <= 0)
   1613  1.1  tsutsui 		return 0;
   1614  1.1  tsutsui 	if (nwb225_rect_valid(dc, x, y, width, height) == 0)
   1615  1.1  tsutsui 		return EINVAL;
   1616  1.1  tsutsui 
   1617  1.1  tsutsui 	error = nwb225_rop_wait(dc);
   1618  1.1  tsutsui 	if (error != 0)
   1619  1.1  tsutsui 		return error;
   1620  1.1  tsutsui 
   1621  1.1  tsutsui 	color &= dc->dc_planemask;
   1622  1.1  tsutsui 	nwb225_rop_make_funcvec(dc, NWB225_BF_S, color, 0, funcvec);
   1623  1.1  tsutsui 	nwb225_rop_cinit(dc, funcvec, dc->dc_planemask, 1);
   1624  1.1  tsutsui 
   1625  1.1  tsutsui 	bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
   1626  1.1  tsutsui 	    NWB225_ROP_CLEAR, 0);
   1627  1.1  tsutsui 	bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh, NWB225_DST_X, 0);
   1628  1.1  tsutsui 	bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh, NWB225_SRC_X, 0);
   1629  1.1  tsutsui 	bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
   1630  1.1  tsutsui 	    NWB225_DST_X + y * sizeof(uint16_t), x);
   1631  1.1  tsutsui 	bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
   1632  1.1  tsutsui 	    NWB225_ROP_EDGE + (height - 1) * sizeof(uint16_t), x + width);
   1633  1.1  tsutsui 
   1634  1.1  tsutsui 	return nwb225_rop_wait(dc);
   1635  1.1  tsutsui }
   1636  1.1  tsutsui 
   1637  1.1  tsutsui static int
   1638  1.1  tsutsui nwb225_rop_hwrite(struct fbbm_devconfig *dc, const uint16_t *src,
   1639  1.1  tsutsui     int srcwidth, int srcx, int srcy, int width, int height, int dx, int dy,
   1640  1.1  tsutsui     uint32_t foreground, uint32_t background)
   1641  1.1  tsutsui {
   1642  1.1  tsutsui 	uint8_t funcvec[8];
   1643  1.1  tsutsui 	const uint16_t *sp;
   1644  1.1  tsutsui 	int nwords, skip, row, word, error;
   1645  1.1  tsutsui 
   1646  1.1  tsutsui 	if (src == NULL || srcwidth <= 0 || srcx < 0 || srcy < 0 ||
   1647  1.1  tsutsui 	    width <= 0 || height <= 0)
   1648  1.1  tsutsui 		return EINVAL;
   1649  1.1  tsutsui 	if (nwb225_rect_valid(dc, dx, dy, width, height) == 0)
   1650  1.1  tsutsui 		return EINVAL;
   1651  1.1  tsutsui 
   1652  1.1  tsutsui 	nwords = ((srcx & 15) + width + 15) >> 4;
   1653  1.1  tsutsui 	if ((srcx >> 4) + nwords > srcwidth)
   1654  1.1  tsutsui 		return EINVAL;
   1655  1.1  tsutsui 
   1656  1.1  tsutsui 	error = nwb225_rop_wait(dc);
   1657  1.1  tsutsui 	if (error != 0)
   1658  1.1  tsutsui 		return error;
   1659  1.1  tsutsui 
   1660  1.1  tsutsui 	foreground &= dc->dc_planemask;
   1661  1.1  tsutsui 	background &= dc->dc_planemask;
   1662  1.1  tsutsui 	nwb225_rop_make_funcvec(dc, NWB225_BF_S, foreground, background,
   1663  1.1  tsutsui 	    funcvec);
   1664  1.1  tsutsui 	nwb225_rop_setfunc(dc, funcvec);
   1665  1.1  tsutsui 	nwb225_rop_set_plane_mask(dc, dc->dc_planemask);
   1666  1.1  tsutsui 
   1667  1.1  tsutsui 	bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
   1668  1.1  tsutsui 	    NWB225_DST_X + dy * sizeof(uint16_t), dx);
   1669  1.1  tsutsui 	bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
   1670  1.1  tsutsui 	    NWB225_SRC_X, srcx & 15);
   1671  1.1  tsutsui 	bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
   1672  1.1  tsutsui 	    NWB225_HWRITE_EDGE + (height - 1) * sizeof(uint16_t), dx + width);
   1673  1.1  tsutsui 
   1674  1.1  tsutsui 	sp = src + srcy * srcwidth + (srcx >> 4);
   1675  1.1  tsutsui 	skip = srcwidth - nwords;
   1676  1.1  tsutsui 	for (row = 0; row < height; row++) {
   1677  1.1  tsutsui 		for (word = 0; word < nwords; word++)
   1678  1.1  tsutsui 			bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
   1679  1.1  tsutsui 			    NWB225_HWRITE_DATA, *sp++);
   1680  1.1  tsutsui 		sp += skip;
   1681  1.1  tsutsui 	}
   1682  1.1  tsutsui 
   1683  1.1  tsutsui 	return nwb225_rop_wait(dc);
   1684  1.1  tsutsui }
   1685  1.1  tsutsui 
   1686  1.1  tsutsui static bus_size_t
   1687  1.1  tsutsui nwb225_krom_ascii_offset(unsigned int c)
   1688  1.1  tsutsui {
   1689  1.1  tsutsui 	unsigned int index;
   1690  1.1  tsutsui 
   1691  1.1  tsutsui 	index = c - NWB225_KROM_ASCII_FIRST;
   1692  1.1  tsutsui 	return ((index & 0xe0) << 9) | ((index & 0x1f) << 7);
   1693  1.1  tsutsui }
   1694  1.1  tsutsui 
   1695  1.1  tsutsui static void
   1696  1.1  tsutsui nwb225_krom_load_cell(struct fbbm_devconfig *dc, unsigned int c,
   1697  1.1  tsutsui     uint16_t *cell)
   1698  1.1  tsutsui {
   1699  1.1  tsutsui 	bus_size_t offset;
   1700  1.1  tsutsui 	int row;
   1701  1.1  tsutsui 
   1702  1.1  tsutsui 	memset(cell, 0, NWB225_CELL_HEIGHT * sizeof(*cell));
   1703  1.1  tsutsui 	offset = nwb225_krom_ascii_offset(c);
   1704  1.1  tsutsui 
   1705  1.1  tsutsui 	/*
   1706  1.1  tsutsui 	 * The PROM renderer reads one 32-bit KROM row, keeps the upper word,
   1707  1.1  tsutsui 	 * masks its low four bits, and places the 24 glyph rows after four
   1708  1.1  tsutsui 	 * blank rows in the 16x30 cell.
   1709  1.1  tsutsui 	 */
   1710  1.1  tsutsui 	for (row = 0; row < NWB225_FONT_HEIGHT; row++)
   1711  1.1  tsutsui 		cell[NWB225_GLYPH_YOFFSET + row] =
   1712  1.1  tsutsui 		    bus_space_read_2(dc->dc_bst, dc->dc_krom_bsh,
   1713  1.1  tsutsui 		    offset + row * NWB225_KROM_ROWBYTES) &
   1714  1.1  tsutsui 		    NWB225_KROM_ASCII_MASK;
   1715  1.1  tsutsui }
   1716  1.1  tsutsui 
   1717  1.1  tsutsui static int
   1718  1.1  tsutsui nwb225_init_hardware(struct fbbm_devconfig *dc)
   1719  1.1  tsutsui {
   1720  1.1  tsutsui 	uint16_t status, value;
   1721  1.1  tsutsui 	unsigned int i, component;
   1722  1.1  tsutsui 
   1723  1.1  tsutsui 	/*
   1724  1.1  tsutsui 	 * Keep the cold-init sequence in the same order as the NWS-1750 PROM
   1725  1.1  tsutsui 	 * NWB-225 module.  In particular, the second reset is intentional: the
   1726  1.1  tsutsui 	 * serial-console cold-boot experiment required the init block followed
   1727  1.1  tsutsui 	 * by this reset before stable sync was established.
   1728  1.1  tsutsui 	 */
   1729  1.1  tsutsui 	nwb225_rop_reset(dc);
   1730  1.1  tsutsui 
   1731  1.1  tsutsui 	for (i = 0; i < __arraycount(nwb225_init_words); i++)
   1732  1.1  tsutsui 		bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
   1733  1.1  tsutsui 		    NWB225_INIT_BASE + i * sizeof(uint16_t),
   1734  1.1  tsutsui 		    nwb225_init_words[i]);
   1735  1.1  tsutsui 
   1736  1.1  tsutsui 	status = bus_space_read_2(dc->dc_bst, dc->dc_rcont_bsh,
   1737  1.1  tsutsui 	    NWB225_STATUS);
   1738  1.1  tsutsui 	if ((status & NWB225_STATUS_4PLANE) != 0)
   1739  1.1  tsutsui 		dc->dc_nplanes = 4;
   1740  1.1  tsutsui 	else
   1741  1.1  tsutsui 		dc->dc_nplanes = 8;
   1742  1.1  tsutsui 	dc->dc_planemask = (1U << dc->dc_nplanes) - 1;
   1743  1.1  tsutsui 	dc->dc_dispver =
   1744  1.1  tsutsui 	    (status & NWB225_STATUS_DISPVER) >> NWB225_STATUS_DISPVER_SHIFT;
   1745  1.1  tsutsui 
   1746  1.1  tsutsui 	nwb225_ctl_write(dc, 4, dc->dc_planemask);
   1747  1.1  tsutsui 	nwb225_ctl_write(dc, 5, 0);
   1748  1.1  tsutsui 	nwb225_ctl_write(dc, 6, 0x40);
   1749  1.1  tsutsui 	nwb225_ctl_write(dc, 7, 0);
   1750  1.1  tsutsui 
   1751  1.1  tsutsui 	nwb225_rop_reset(dc);
   1752  1.1  tsutsui 
   1753  1.1  tsutsui 	/* Complete the fixed PROM palette/control initialization. */
   1754  1.1  tsutsui 	for (i = 0; i < 256; i++) {
   1755  1.1  tsutsui 		bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
   1756  1.1  tsutsui 		    NWB225_PAL_INDEX, i);
   1757  1.1  tsutsui 		for (component = 0; component < 3; component++) {
   1758  1.1  tsutsui 			value = nwb225_prom_palette[i & 0x0f][component] << 4;
   1759  1.1  tsutsui 			bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
   1760  1.1  tsutsui 			    NWB225_PAL_DATA, value);
   1761  1.1  tsutsui 		}
   1762  1.1  tsutsui 	}
   1763  1.1  tsutsui 
   1764  1.1  tsutsui 	bus_space_write_2(dc->dc_bst, dc->dc_rcont_bsh,
   1765  1.1  tsutsui 	    NWB225_PLANE_CTRL, 0);
   1766  1.1  tsutsui 
   1767  1.1  tsutsui 	return nwb225_rop_wait(dc);
   1768  1.1  tsutsui }
   1769  1.1  tsutsui 
   1770  1.1  tsutsui static void
   1771  1.1  tsutsui fbbm_init_screen(struct fbbm_devconfig *dc)
   1772  1.1  tsutsui {
   1773  1.1  tsutsui 
   1774  1.1  tsutsui 	dc->dc_fbwidth = NWB225_FB_WIDTH;
   1775  1.1  tsutsui 	dc->dc_fbheight = NWB225_FB_HEIGHT;
   1776  1.1  tsutsui 	dc->dc_width = NWB225_VIS_WIDTH;
   1777  1.1  tsutsui 	dc->dc_height = NWB225_VIS_HEIGHT;
   1778  1.1  tsutsui 
   1779  1.1  tsutsui 	dc->dc_fontwidth = NWB225_FONT_WIDTH;
   1780  1.1  tsutsui 	dc->dc_fontheight = NWB225_FONT_HEIGHT;
   1781  1.1  tsutsui 	dc->dc_cellwidth = NWB225_CELL_WIDTH;
   1782  1.1  tsutsui 	dc->dc_cellheight = NWB225_CELL_HEIGHT;
   1783  1.1  tsutsui 
   1784  1.1  tsutsui 	dc->dc_ncols = NWB225_TEXT_COLS;
   1785  1.1  tsutsui 	dc->dc_nrows = NWB225_TEXT_ROWS;
   1786  1.1  tsutsui 	dc->dc_xorigin = NWB225_TEXT_XORIGIN;
   1787  1.1  tsutsui 	dc->dc_yorigin = NWB225_TEXT_YORIGIN;
   1788  1.1  tsutsui 
   1789  1.1  tsutsui 	dc->dc_wsscrdescr.name = "std";
   1790  1.1  tsutsui 	dc->dc_wsscrdescr.ncols = dc->dc_ncols;
   1791  1.1  tsutsui 	dc->dc_wsscrdescr.nrows = dc->dc_nrows;
   1792  1.1  tsutsui 	dc->dc_wsscrdescr.textops = &fbbm_emulops;
   1793  1.1  tsutsui 	dc->dc_wsscrdescr.fontwidth = dc->dc_cellwidth;
   1794  1.1  tsutsui 	dc->dc_wsscrdescr.fontheight = dc->dc_cellheight;
   1795  1.1  tsutsui 	dc->dc_wsscrdescr.capabilities = WSSCREEN_REVERSE;
   1796  1.1  tsutsui 	dc->dc_wsscrdescr.modecookie = NULL;
   1797  1.1  tsutsui 
   1798  1.1  tsutsui 	dc->dc_cursoron = 0;
   1799  1.1  tsutsui 	dc->dc_cursorrow = 0;
   1800  1.1  tsutsui 	dc->dc_cursorcol = 0;
   1801  1.1  tsutsui }
   1802  1.1  tsutsui 
   1803  1.1  tsutsui /*
   1804  1.1  tsutsui  * Clear only the visible text display.  This is separate from logical screen
   1805  1.1  tsutsui  * initialization so that the C1 early-console path can perform the clear at
   1806  1.1  tsutsui  * takeover time before wsdisplay_cnattach(), while the later normal attach
   1807  1.1  tsutsui  * can reuse the established console state without clearing it again.
   1808  1.1  tsutsui  */
   1809  1.1  tsutsui static int
   1810  1.1  tsutsui fbbm_clear_screen(struct fbbm_devconfig *dc)
   1811  1.1  tsutsui {
   1812  1.1  tsutsui 
   1813  1.1  tsutsui 	return nwb225_rop_fill_rect(dc, 0, 0, dc->dc_width, dc->dc_height, 0);
   1814  1.1  tsutsui }
   1815  1.1  tsutsui 
   1816  1.1  tsutsui static uint32_t
   1817  1.1  tsutsui fbbm_attr_background(struct fbbm_devconfig *dc, long attr)
   1818  1.1  tsutsui {
   1819  1.1  tsutsui 
   1820  1.1  tsutsui 	return (attr & 1) != 0 ? dc->dc_planemask : 0;
   1821  1.1  tsutsui }
   1822  1.1  tsutsui 
   1823  1.1  tsutsui static void
   1824  1.1  tsutsui fbbm_cursor(void *cookie, int on, int row, int col)
   1825  1.1  tsutsui {
   1826  1.1  tsutsui 	struct fbbm_devconfig *dc = cookie;
   1827  1.1  tsutsui 	int x, y, error;
   1828  1.1  tsutsui 
   1829  1.1  tsutsui 	if (dc->dc_cursoron != 0) {
   1830  1.1  tsutsui 		x = dc->dc_xorigin + dc->dc_cursorcol * dc->dc_cellwidth;
   1831  1.1  tsutsui 		y = dc->dc_yorigin + dc->dc_cursorrow * dc->dc_cellheight;
   1832  1.1  tsutsui 		error = nwb225_rop_copy_rect(dc, x, y, dc->dc_cellwidth,
   1833  1.1  tsutsui 		    dc->dc_cellheight, x, y, NWB225_BF_DI);
   1834  1.1  tsutsui 		if (error != 0)
   1835  1.1  tsutsui 			return;
   1836  1.1  tsutsui 		dc->dc_cursoron = 0;
   1837  1.1  tsutsui 	}
   1838  1.1  tsutsui 
   1839  1.1  tsutsui 	dc->dc_cursorrow = row;
   1840  1.1  tsutsui 	dc->dc_cursorcol = col;
   1841  1.1  tsutsui 	if (on == 0)
   1842  1.1  tsutsui 		return;
   1843  1.1  tsutsui 	if (row < 0 || row >= dc->dc_nrows || col < 0 || col >= dc->dc_ncols)
   1844  1.1  tsutsui 		return;
   1845  1.1  tsutsui 
   1846  1.1  tsutsui 	x = dc->dc_xorigin + col * dc->dc_cellwidth;
   1847  1.1  tsutsui 	y = dc->dc_yorigin + row * dc->dc_cellheight;
   1848  1.1  tsutsui 	error = nwb225_rop_copy_rect(dc, x, y, dc->dc_cellwidth,
   1849  1.1  tsutsui 	    dc->dc_cellheight, x, y, NWB225_BF_DI);
   1850  1.1  tsutsui 	if (error == 0)
   1851  1.1  tsutsui 		dc->dc_cursoron = 1;
   1852  1.1  tsutsui }
   1853  1.1  tsutsui 
   1854  1.1  tsutsui static int
   1855  1.1  tsutsui fbbm_mapchar(void *cookie, int c, unsigned int *cp)
   1856  1.1  tsutsui {
   1857  1.1  tsutsui 
   1858  1.1  tsutsui 	__USE(cookie);
   1859  1.1  tsutsui 
   1860  1.1  tsutsui 	if (c < NWB225_KROM_ASCII_FIRST || c > NWB225_KROM_ASCII_LAST) {
   1861  1.1  tsutsui 		*cp = ' ';
   1862  1.1  tsutsui 		return 0;
   1863  1.1  tsutsui 	}
   1864  1.1  tsutsui 
   1865  1.1  tsutsui 	*cp = c;
   1866  1.1  tsutsui 	return 5;
   1867  1.1  tsutsui }
   1868  1.1  tsutsui 
   1869  1.1  tsutsui static void
   1870  1.1  tsutsui fbbm_putchar(void *cookie, int row, int col, u_int uc, long attr)
   1871  1.1  tsutsui {
   1872  1.1  tsutsui 	struct fbbm_devconfig *dc = cookie;
   1873  1.1  tsutsui 	uint16_t cell[NWB225_CELL_HEIGHT];
   1874  1.1  tsutsui 	uint32_t foreground, background;
   1875  1.1  tsutsui 	int x, y;
   1876  1.1  tsutsui 
   1877  1.1  tsutsui 	if (row < 0 || row >= dc->dc_nrows || col < 0 || col >= dc->dc_ncols)
   1878  1.1  tsutsui 		return;
   1879  1.1  tsutsui 	if (uc < NWB225_KROM_ASCII_FIRST || uc > NWB225_KROM_ASCII_LAST)
   1880  1.1  tsutsui 		uc = ' ';
   1881  1.1  tsutsui 
   1882  1.1  tsutsui 	nwb225_krom_load_cell(dc, uc, cell);
   1883  1.1  tsutsui 	background = fbbm_attr_background(dc, attr);
   1884  1.1  tsutsui 	foreground = dc->dc_planemask ^ background;
   1885  1.1  tsutsui 	x = dc->dc_xorigin + col * dc->dc_cellwidth;
   1886  1.1  tsutsui 	y = dc->dc_yorigin + row * dc->dc_cellheight;
   1887  1.1  tsutsui 
   1888  1.1  tsutsui 	(void)nwb225_rop_hwrite(dc, cell, 1, 0, 0, dc->dc_cellwidth,
   1889  1.1  tsutsui 	    dc->dc_cellheight, x, y, foreground, background);
   1890  1.1  tsutsui }
   1891  1.1  tsutsui 
   1892  1.1  tsutsui static void
   1893  1.1  tsutsui fbbm_copycols(void *cookie, int row, int srccol, int dstcol, int ncols)
   1894  1.1  tsutsui {
   1895  1.1  tsutsui 	struct fbbm_devconfig *dc = cookie;
   1896  1.1  tsutsui 	int sx, dx, y, width;
   1897  1.1  tsutsui 
   1898  1.1  tsutsui 	if (ncols <= 0 || row < 0 || row >= dc->dc_nrows)
   1899  1.1  tsutsui 		return;
   1900  1.1  tsutsui 	if (srccol < 0 || dstcol < 0 || srccol + ncols > dc->dc_ncols ||
   1901  1.1  tsutsui 	    dstcol + ncols > dc->dc_ncols)
   1902  1.1  tsutsui 		return;
   1903  1.1  tsutsui 	if (srccol == dstcol)
   1904  1.1  tsutsui 		return;
   1905  1.1  tsutsui 
   1906  1.1  tsutsui 	sx = dc->dc_xorigin + srccol * dc->dc_cellwidth;
   1907  1.1  tsutsui 	dx = dc->dc_xorigin + dstcol * dc->dc_cellwidth;
   1908  1.1  tsutsui 	y = dc->dc_yorigin + row * dc->dc_cellheight;
   1909  1.1  tsutsui 	width = ncols * dc->dc_cellwidth;
   1910  1.1  tsutsui 	(void)nwb225_rop_copy_rect(dc, sx, y, width, dc->dc_cellheight,
   1911  1.1  tsutsui 	    dx, y, NWB225_BF_S);
   1912  1.1  tsutsui }
   1913  1.1  tsutsui 
   1914  1.1  tsutsui static void
   1915  1.1  tsutsui fbbm_erasecols(void *cookie, int row, int col, int ncols, long attr)
   1916  1.1  tsutsui {
   1917  1.1  tsutsui 	struct fbbm_devconfig *dc = cookie;
   1918  1.1  tsutsui 	uint32_t background;
   1919  1.1  tsutsui 	int x, y, width;
   1920  1.1  tsutsui 
   1921  1.1  tsutsui 	if (ncols <= 0 || row < 0 || row >= dc->dc_nrows)
   1922  1.1  tsutsui 		return;
   1923  1.1  tsutsui 	if (col < 0 || col + ncols > dc->dc_ncols)
   1924  1.1  tsutsui 		return;
   1925  1.1  tsutsui 
   1926  1.1  tsutsui 	x = dc->dc_xorigin + col * dc->dc_cellwidth;
   1927  1.1  tsutsui 	y = dc->dc_yorigin + row * dc->dc_cellheight;
   1928  1.1  tsutsui 	width = ncols * dc->dc_cellwidth;
   1929  1.1  tsutsui 	background = fbbm_attr_background(dc, attr);
   1930  1.1  tsutsui 	(void)nwb225_rop_fill_rect(dc, x, y, width, dc->dc_cellheight,
   1931  1.1  tsutsui 	    background);
   1932  1.1  tsutsui }
   1933  1.1  tsutsui 
   1934  1.1  tsutsui static void
   1935  1.1  tsutsui fbbm_copyrows(void *cookie, int srcrow, int dstrow, int nrows)
   1936  1.1  tsutsui {
   1937  1.1  tsutsui 	struct fbbm_devconfig *dc = cookie;
   1938  1.1  tsutsui 	int x, sy, dy, height;
   1939  1.1  tsutsui 
   1940  1.1  tsutsui 	if (nrows <= 0 || srcrow < 0 || dstrow < 0 ||
   1941  1.1  tsutsui 	    srcrow + nrows > dc->dc_nrows || dstrow + nrows > dc->dc_nrows)
   1942  1.1  tsutsui 		return;
   1943  1.1  tsutsui 	if (srcrow == dstrow)
   1944  1.1  tsutsui 		return;
   1945  1.1  tsutsui 
   1946  1.1  tsutsui 	x = dc->dc_xorigin;
   1947  1.1  tsutsui 	sy = dc->dc_yorigin + srcrow * dc->dc_cellheight;
   1948  1.1  tsutsui 	dy = dc->dc_yorigin + dstrow * dc->dc_cellheight;
   1949  1.1  tsutsui 	height = nrows * dc->dc_cellheight;
   1950  1.1  tsutsui 	(void)nwb225_rop_copy_rect(dc, x, sy,
   1951  1.1  tsutsui 	    dc->dc_ncols * dc->dc_cellwidth, height, x, dy, NWB225_BF_S);
   1952  1.1  tsutsui }
   1953  1.1  tsutsui 
   1954  1.1  tsutsui static void
   1955  1.1  tsutsui fbbm_eraserows(void *cookie, int row, int nrows, long attr)
   1956  1.1  tsutsui {
   1957  1.1  tsutsui 	struct fbbm_devconfig *dc = cookie;
   1958  1.1  tsutsui 	uint32_t background;
   1959  1.1  tsutsui 	int x, y, height;
   1960  1.1  tsutsui 
   1961  1.1  tsutsui 	if (nrows <= 0 || row < 0 || row + nrows > dc->dc_nrows)
   1962  1.1  tsutsui 		return;
   1963  1.1  tsutsui 
   1964  1.1  tsutsui 	x = dc->dc_xorigin;
   1965  1.1  tsutsui 	y = dc->dc_yorigin + row * dc->dc_cellheight;
   1966  1.1  tsutsui 	height = nrows * dc->dc_cellheight;
   1967  1.1  tsutsui 	background = fbbm_attr_background(dc, attr);
   1968  1.1  tsutsui 	(void)nwb225_rop_fill_rect(dc, x, y,
   1969  1.1  tsutsui 	    dc->dc_ncols * dc->dc_cellwidth, height, background);
   1970  1.1  tsutsui }
   1971  1.1  tsutsui 
   1972  1.1  tsutsui static int
   1973  1.1  tsutsui fbbm_allocattr(void *cookie, int fg, int bg, int flags, long *attrp)
   1974  1.1  tsutsui {
   1975  1.1  tsutsui 
   1976  1.1  tsutsui 	__USE(cookie);
   1977  1.1  tsutsui 	__USE(fg);
   1978  1.1  tsutsui 	__USE(bg);
   1979  1.1  tsutsui 
   1980  1.1  tsutsui 	if ((flags & ~WSATTR_REVERSE) != 0)
   1981  1.1  tsutsui 		return EINVAL;
   1982  1.1  tsutsui 
   1983  1.1  tsutsui 	*attrp = (flags & WSATTR_REVERSE) != 0 ? 1 : 0;
   1984  1.1  tsutsui 	return 0;
   1985  1.1  tsutsui }
   1986  1.1  tsutsui 
   1987  1.1  tsutsui static int
   1988  1.1  tsutsui fbbm_ioctl(void *v, void *vs, u_long cmd, void *data, int flag,
   1989  1.1  tsutsui     struct lwp *l)
   1990  1.1  tsutsui {
   1991  1.1  tsutsui 	struct fbbm_softc *sc = v;
   1992  1.1  tsutsui 	struct fbbm_devconfig *dc = sc->sc_dc;
   1993  1.1  tsutsui 	struct wsdisplay_fbinfo *fbinfo;
   1994  1.1  tsutsui 
   1995  1.1  tsutsui 	__USE(vs);
   1996  1.1  tsutsui 	__USE(flag);
   1997  1.1  tsutsui 	__USE(l);
   1998  1.1  tsutsui 
   1999  1.1  tsutsui 	switch (cmd) {
   2000  1.1  tsutsui 	case WSDISPLAYIO_GTYPE:
   2001  1.1  tsutsui 		*(u_int *)data = WSDISPLAY_TYPE_NWB225;
   2002  1.1  tsutsui 		return 0;
   2003  1.1  tsutsui 
   2004  1.1  tsutsui 	case WSDISPLAYIO_GINFO:
   2005  1.1  tsutsui 		fbinfo = data;
   2006  1.1  tsutsui 		fbinfo->height = dc->dc_height;
   2007  1.1  tsutsui 		fbinfo->width = dc->dc_width;
   2008  1.1  tsutsui 		fbinfo->depth = dc->dc_nplanes;
   2009  1.1  tsutsui 		fbinfo->cmsize = 0;
   2010  1.1  tsutsui 		return 0;
   2011  1.1  tsutsui 
   2012  1.1  tsutsui 	default:
   2013  1.1  tsutsui 		return EPASSTHROUGH;
   2014  1.1  tsutsui 	}
   2015  1.1  tsutsui }
   2016  1.1  tsutsui 
   2017  1.1  tsutsui static int
   2018  1.1  tsutsui fbbm_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
   2019  1.1  tsutsui     int *ccolp, int *crowp, long *attrp)
   2020  1.1  tsutsui {
   2021  1.1  tsutsui 	struct fbbm_softc *sc = v;
   2022  1.1  tsutsui 	struct fbbm_devconfig *dc = sc->sc_dc;
   2023  1.1  tsutsui 	long attr;
   2024  1.1  tsutsui 	int error;
   2025  1.1  tsutsui 
   2026  1.1  tsutsui 	KASSERT(type == &dc->dc_wsscrdescr);
   2027  1.1  tsutsui 
   2028  1.1  tsutsui 	if (sc->sc_nscreens != 0)
   2029  1.1  tsutsui 		return ENOMEM;
   2030  1.1  tsutsui 
   2031  1.1  tsutsui 	error = fbbm_allocattr(dc, 0, 0, 0, &attr);
   2032  1.1  tsutsui 	if (error != 0)
   2033  1.1  tsutsui 		return error;
   2034  1.1  tsutsui 
   2035  1.1  tsutsui 	*cookiep = dc;
   2036  1.1  tsutsui 	*ccolp = 0;
   2037  1.1  tsutsui 	*crowp = 0;
   2038  1.1  tsutsui 	*attrp = attr;
   2039  1.1  tsutsui 	sc->sc_nscreens = 1;
   2040  1.1  tsutsui 
   2041  1.1  tsutsui 	return 0;
   2042  1.1  tsutsui }
   2043  1.1  tsutsui 
   2044  1.1  tsutsui static void
   2045  1.1  tsutsui fbbm_free_screen(void *v, void *cookie)
   2046  1.1  tsutsui {
   2047  1.1  tsutsui 	struct fbbm_softc *sc = v;
   2048  1.1  tsutsui 
   2049  1.1  tsutsui 	KASSERT(sc->sc_nscreens == 1);
   2050  1.1  tsutsui 	KASSERT(cookie == sc->sc_dc);
   2051  1.1  tsutsui 	sc->sc_nscreens = 0;
   2052  1.1  tsutsui }
   2053  1.1  tsutsui 
   2054  1.1  tsutsui static int
   2055  1.1  tsutsui fbbm_show_screen(void *v, void *cookie, int waitok,
   2056  1.1  tsutsui     void (*cb)(void *, int, int), void *cbarg)
   2057  1.1  tsutsui {
   2058  1.1  tsutsui 
   2059  1.1  tsutsui 	__USE(v);
   2060  1.1  tsutsui 	__USE(cookie);
   2061  1.1  tsutsui 	__USE(waitok);
   2062  1.1  tsutsui 	__USE(cb);
   2063  1.1  tsutsui 	__USE(cbarg);
   2064  1.1  tsutsui 
   2065  1.1  tsutsui 	return 0;
   2066  1.1  tsutsui }
   2067