1*6e9a937cStsutsui /* $NetBSD: topcat.c,v 1.13 2024/12/20 22:42:57 tsutsui Exp $ */ 2b04b7da8Stsutsui /* $OpenBSD: topcat.c,v 1.15 2006/08/11 18:33:13 miod Exp $ */ 3b04b7da8Stsutsui 4b04b7da8Stsutsui /* 5b04b7da8Stsutsui * Copyright (c) 2005, Miodrag Vallat. 6b04b7da8Stsutsui * All rights reserved. 7b04b7da8Stsutsui * 8b04b7da8Stsutsui * Redistribution and use in source and binary forms, with or without 9b04b7da8Stsutsui * modification, are permitted provided that the following conditions 10b04b7da8Stsutsui * are met: 11b04b7da8Stsutsui * 1. Redistributions of source code must retain the above copyright 12b04b7da8Stsutsui * notice, this list of conditions and the following disclaimer. 13b04b7da8Stsutsui * 2. Redistributions in binary form must reproduce the above copyright 14b04b7da8Stsutsui * notice, this list of conditions and the following disclaimer in the 15b04b7da8Stsutsui * documentation and/or other materials provided with the distribution. 16b04b7da8Stsutsui * 17b04b7da8Stsutsui * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18b04b7da8Stsutsui * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19b04b7da8Stsutsui * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20b04b7da8Stsutsui * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 21b04b7da8Stsutsui * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22b04b7da8Stsutsui * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23b04b7da8Stsutsui * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24b04b7da8Stsutsui * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 25b04b7da8Stsutsui * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 26b04b7da8Stsutsui * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27b04b7da8Stsutsui * POSSIBILITY OF SUCH DAMAGE. 28b04b7da8Stsutsui * 29b04b7da8Stsutsui */ 30b04b7da8Stsutsui /*- 31b04b7da8Stsutsui * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc. 32b04b7da8Stsutsui * All rights reserved. 33b04b7da8Stsutsui * 34b04b7da8Stsutsui * This code is derived from software contributed to The NetBSD Foundation 35b04b7da8Stsutsui * by Jason R. Thorpe. 36b04b7da8Stsutsui * 37b04b7da8Stsutsui * Redistribution and use in source and binary forms, with or without 38b04b7da8Stsutsui * modification, are permitted provided that the following conditions 39b04b7da8Stsutsui * are met: 40b04b7da8Stsutsui * 1. Redistributions of source code must retain the above copyright 41b04b7da8Stsutsui * notice, this list of conditions and the following disclaimer. 42b04b7da8Stsutsui * 2. Redistributions in binary form must reproduce the above copyright 43b04b7da8Stsutsui * notice, this list of conditions and the following disclaimer in the 44b04b7da8Stsutsui * documentation and/or other materials provided with the distribution. 45b04b7da8Stsutsui * 46b04b7da8Stsutsui * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 47b04b7da8Stsutsui * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 48b04b7da8Stsutsui * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 49b04b7da8Stsutsui * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 50b04b7da8Stsutsui * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 51b04b7da8Stsutsui * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 52b04b7da8Stsutsui * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 53b04b7da8Stsutsui * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 54b04b7da8Stsutsui * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 55b04b7da8Stsutsui * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 56b04b7da8Stsutsui * POSSIBILITY OF SUCH DAMAGE. 57b04b7da8Stsutsui */ 58b04b7da8Stsutsui 59b04b7da8Stsutsui /* 60b04b7da8Stsutsui * Copyright (c) 1988 University of Utah. 61b04b7da8Stsutsui * Copyright (c) 1990, 1993 62b04b7da8Stsutsui * The Regents of the University of California. All rights reserved. 63b04b7da8Stsutsui * 64b04b7da8Stsutsui * This code is derived from software contributed to Berkeley by 65b04b7da8Stsutsui * the Systems Programming Group of the University of Utah Computer 66b04b7da8Stsutsui * Science Department. 67b04b7da8Stsutsui * 68b04b7da8Stsutsui * Redistribution and use in source and binary forms, with or without 69b04b7da8Stsutsui * modification, are permitted provided that the following conditions 70b04b7da8Stsutsui * are met: 71b04b7da8Stsutsui * 1. Redistributions of source code must retain the above copyright 72b04b7da8Stsutsui * notice, this list of conditions and the following disclaimer. 73b04b7da8Stsutsui * 2. Redistributions in binary form must reproduce the above copyright 74b04b7da8Stsutsui * notice, this list of conditions and the following disclaimer in the 75b04b7da8Stsutsui * documentation and/or other materials provided with the distribution. 76b04b7da8Stsutsui * 3. Neither the name of the University nor the names of its contributors 77b04b7da8Stsutsui * may be used to endorse or promote products derived from this software 78b04b7da8Stsutsui * without specific prior written permission. 79b04b7da8Stsutsui * 80b04b7da8Stsutsui * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 81b04b7da8Stsutsui * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 82b04b7da8Stsutsui * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 83b04b7da8Stsutsui * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 84b04b7da8Stsutsui * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 85b04b7da8Stsutsui * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 86b04b7da8Stsutsui * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 87b04b7da8Stsutsui * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 88b04b7da8Stsutsui * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 89b04b7da8Stsutsui * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 90b04b7da8Stsutsui * SUCH DAMAGE. 91b04b7da8Stsutsui * 92b04b7da8Stsutsui * from: Utah $Hdr: grf_tc.c 1.20 93/08/13$ 93b04b7da8Stsutsui * 94b04b7da8Stsutsui * @(#)grf_tc.c 8.4 (Berkeley) 1/12/94 95b04b7da8Stsutsui */ 96b04b7da8Stsutsui 97b04b7da8Stsutsui /* 98b04b7da8Stsutsui * Graphics routines for TOPCAT, CATSEYE and KATHMANDU frame buffers 99b04b7da8Stsutsui */ 100b04b7da8Stsutsui 101b04b7da8Stsutsui #include <sys/param.h> 102b04b7da8Stsutsui #include <sys/systm.h> 103b04b7da8Stsutsui #include <sys/conf.h> 104b04b7da8Stsutsui #include <sys/device.h> 105b04b7da8Stsutsui #include <sys/proc.h> 106b04b7da8Stsutsui #include <sys/ioctl.h> 107b04b7da8Stsutsui #include <sys/bus.h> 108b04b7da8Stsutsui #include <sys/cpu.h> 109b04b7da8Stsutsui 110b04b7da8Stsutsui #include <machine/autoconf.h> 111b04b7da8Stsutsui 112b04b7da8Stsutsui #include <hp300/dev/dioreg.h> 113b04b7da8Stsutsui #include <hp300/dev/diovar.h> 114b04b7da8Stsutsui #include <hp300/dev/diodevs.h> 115b04b7da8Stsutsui #include <hp300/dev/intiovar.h> 116b04b7da8Stsutsui 117b04b7da8Stsutsui #include <dev/wscons/wsconsio.h> 118b04b7da8Stsutsui #include <dev/wscons/wsdisplayvar.h> 119b04b7da8Stsutsui #include <dev/rasops/rasops.h> 120b04b7da8Stsutsui 121b04b7da8Stsutsui #include <hp300/dev/diofbreg.h> 122b04b7da8Stsutsui #include <hp300/dev/diofbvar.h> 123b04b7da8Stsutsui #include <hp300/dev/topcatreg.h> 124b04b7da8Stsutsui 125b04b7da8Stsutsui struct topcat_softc { 126b04b7da8Stsutsui device_t sc_dev; 127b04b7da8Stsutsui struct diofb *sc_fb; 128b04b7da8Stsutsui struct diofb sc_fb_store; 129b04b7da8Stsutsui int sc_scode; 130b04b7da8Stsutsui }; 131b04b7da8Stsutsui 1321c458de2Stsutsui static int topcat_dio_match(device_t, cfdata_t, void *); 1331c458de2Stsutsui static void topcat_dio_attach(device_t, device_t, void *); 1341c458de2Stsutsui static int topcat_intio_match(device_t, cfdata_t, void *); 1351c458de2Stsutsui static void topcat_intio_attach(device_t, device_t, void *); 136b04b7da8Stsutsui 137b04b7da8Stsutsui CFATTACH_DECL_NEW(topcat_dio, sizeof(struct topcat_softc), 138b04b7da8Stsutsui topcat_dio_match, topcat_dio_attach, NULL, NULL); 139b04b7da8Stsutsui 140b04b7da8Stsutsui CFATTACH_DECL_NEW(topcat_intio, sizeof(struct topcat_softc), 141b04b7da8Stsutsui topcat_intio_match, topcat_intio_attach, NULL, NULL); 142b04b7da8Stsutsui 1431c458de2Stsutsui static void topcat_end_attach(struct topcat_softc *, uint8_t); 1441c458de2Stsutsui static int topcat_reset(struct diofb *, int, struct diofbreg *); 1451c458de2Stsutsui static void topcat_restore(struct diofb *); 1461c458de2Stsutsui static int topcat_setcmap(struct diofb *, struct wsdisplay_cmap *); 1471c458de2Stsutsui static void topcat_setcolor(struct diofb *, u_int); 1481c458de2Stsutsui static int topcat_windowmove(struct diofb *, uint16_t, uint16_t, uint16_t, 1495d7f465dStsutsui uint16_t, uint16_t, uint16_t, int16_t, int16_t); 150b04b7da8Stsutsui 1511c458de2Stsutsui static int topcat_ioctl(void *, void *, u_long, void *, int, struct lwp *); 152f4485e64Stsutsui static void topcat_putchar8(void *, int, int, u_int, long); 153f4485e64Stsutsui static void topcat_putchar1_4(void *, int, int, u_int, long); 154b04b7da8Stsutsui 1551c458de2Stsutsui static struct wsdisplay_accessops topcat_accessops = { 156b04b7da8Stsutsui topcat_ioctl, 157b04b7da8Stsutsui diofb_mmap, 158b04b7da8Stsutsui diofb_alloc_screen, 159b04b7da8Stsutsui diofb_free_screen, 160b04b7da8Stsutsui diofb_show_screen, 161b04b7da8Stsutsui NULL, /* load_font */ 162b04b7da8Stsutsui }; 163b04b7da8Stsutsui 164b04b7da8Stsutsui /* 165b04b7da8Stsutsui * Attachment glue 166b04b7da8Stsutsui */ 167b04b7da8Stsutsui 168b04b7da8Stsutsui int 169b04b7da8Stsutsui topcat_intio_match(device_t parent, cfdata_t cf, void *aux) 170b04b7da8Stsutsui { 171b04b7da8Stsutsui struct intio_attach_args *ia = aux; 172b04b7da8Stsutsui struct diofbreg *fbr; 173b04b7da8Stsutsui 174b04b7da8Stsutsui if (strcmp("fb", ia->ia_modname) != 0) 175b04b7da8Stsutsui return 0; 176b04b7da8Stsutsui 177b04b7da8Stsutsui fbr = (struct diofbreg *)ia->ia_addr; 178b04b7da8Stsutsui 179b04b7da8Stsutsui if (badaddr((void *)fbr)) 1805d7f465dStsutsui return 0; 181b04b7da8Stsutsui 182b04b7da8Stsutsui if (fbr->id == GRFHWID) { 183b04b7da8Stsutsui switch (fbr->fbid) { 184b04b7da8Stsutsui case GID_TOPCAT: 185b04b7da8Stsutsui case GID_LRCATSEYE: 186b04b7da8Stsutsui case GID_HRCCATSEYE: 187b04b7da8Stsutsui case GID_HRMCATSEYE: 188b04b7da8Stsutsui #if 0 189b04b7da8Stsutsui case GID_XXXCATSEYE: 190b04b7da8Stsutsui #endif 1915d7f465dStsutsui return 1; 192b04b7da8Stsutsui } 193b04b7da8Stsutsui } 194b04b7da8Stsutsui 1955d7f465dStsutsui return 0; 196b04b7da8Stsutsui } 197b04b7da8Stsutsui 198b04b7da8Stsutsui void 199b04b7da8Stsutsui topcat_intio_attach(device_t parent, device_t self, void *aux) 200b04b7da8Stsutsui { 201b04b7da8Stsutsui struct topcat_softc *sc = device_private(self); 202b04b7da8Stsutsui struct intio_attach_args *ia = aux; 203b04b7da8Stsutsui struct diofbreg *fbr; 204b04b7da8Stsutsui 205b04b7da8Stsutsui sc->sc_dev = self; 206b04b7da8Stsutsui fbr = (struct diofbreg *)ia->ia_addr; 207b04b7da8Stsutsui sc->sc_scode = CONSCODE_INTERNAL; 208b04b7da8Stsutsui 209b04b7da8Stsutsui if (sc->sc_scode == conscode) { 210b04b7da8Stsutsui sc->sc_fb = &diofb_cn; 211b04b7da8Stsutsui } else { 212b04b7da8Stsutsui sc->sc_fb = &sc->sc_fb_store; 213b04b7da8Stsutsui topcat_reset(sc->sc_fb, sc->sc_scode, fbr); 214b04b7da8Stsutsui } 215b04b7da8Stsutsui 216b04b7da8Stsutsui topcat_end_attach(sc, fbr->fbid); 217b04b7da8Stsutsui } 218b04b7da8Stsutsui 219b04b7da8Stsutsui int 220b04b7da8Stsutsui topcat_dio_match(device_t parent, cfdata_t cf, void *aux) 221b04b7da8Stsutsui { 222b04b7da8Stsutsui struct dio_attach_args *da = aux; 223b04b7da8Stsutsui 224b04b7da8Stsutsui if (da->da_id == DIO_DEVICE_ID_FRAMEBUFFER) { 225b04b7da8Stsutsui switch (da->da_secid) { 226b04b7da8Stsutsui case DIO_DEVICE_SECID_TOPCAT: 227b04b7da8Stsutsui case DIO_DEVICE_SECID_LRCATSEYE: 228b04b7da8Stsutsui case DIO_DEVICE_SECID_HRCCATSEYE: 229b04b7da8Stsutsui case DIO_DEVICE_SECID_HRMCATSEYE: 230b04b7da8Stsutsui #if 0 231b04b7da8Stsutsui case DIO_DEVICE_SECID_XXXCATSEYE: 232b04b7da8Stsutsui #endif 2335d7f465dStsutsui return 1; 234b04b7da8Stsutsui } 235b04b7da8Stsutsui } 236b04b7da8Stsutsui 2375d7f465dStsutsui return 0; 238b04b7da8Stsutsui } 239b04b7da8Stsutsui 240b04b7da8Stsutsui void 241b04b7da8Stsutsui topcat_dio_attach(device_t parent, device_t self, void *aux) 242b04b7da8Stsutsui { 243b04b7da8Stsutsui struct topcat_softc *sc = device_private(self); 244b04b7da8Stsutsui struct dio_attach_args *da = aux; 245b04b7da8Stsutsui bus_space_handle_t bsh; 246b04b7da8Stsutsui struct diofbreg *fbr; 247b04b7da8Stsutsui 248b04b7da8Stsutsui sc->sc_dev = self; 249b04b7da8Stsutsui sc->sc_scode = da->da_scode; 250b04b7da8Stsutsui if (sc->sc_scode == conscode) { 251b04b7da8Stsutsui fbr = (struct diofbreg *)conaddr; /* already mapped */ 252b04b7da8Stsutsui sc->sc_fb = &diofb_cn; 253b04b7da8Stsutsui } else { 254b04b7da8Stsutsui sc->sc_fb = &sc->sc_fb_store; 255b04b7da8Stsutsui if (bus_space_map(da->da_bst, da->da_addr, da->da_size, 0, 256b04b7da8Stsutsui &bsh)) { 257b04b7da8Stsutsui aprint_error(": can't map framebuffer\n"); 258b04b7da8Stsutsui return; 259b04b7da8Stsutsui } 260b04b7da8Stsutsui fbr = bus_space_vaddr(da->da_bst, bsh); 261b04b7da8Stsutsui if (topcat_reset(sc->sc_fb, sc->sc_scode, fbr) != 0) { 2622ba8a55cStsutsui aprint_error(": can't reset framebuffer\n"); 263b04b7da8Stsutsui return; 264b04b7da8Stsutsui } 265b04b7da8Stsutsui } 266b04b7da8Stsutsui 267b04b7da8Stsutsui topcat_end_attach(sc, fbr->fbid); 268b04b7da8Stsutsui } 269b04b7da8Stsutsui 270b04b7da8Stsutsui void 2715d7f465dStsutsui topcat_end_attach(struct topcat_softc *sc, uint8_t id) 272b04b7da8Stsutsui { 273b04b7da8Stsutsui const char *fbname = "unknown"; 274b04b7da8Stsutsui 275b04b7da8Stsutsui switch (id) { 276b04b7da8Stsutsui case GID_TOPCAT: 277b04b7da8Stsutsui switch (sc->sc_fb->planes) { 278b04b7da8Stsutsui case 1: 27966933893Stsutsui if (sc->sc_fb->dheight == 400) 28066933893Stsutsui fbname = "HP98542 topcat"; 28166933893Stsutsui else 282b04b7da8Stsutsui fbname = "HP98544 topcat"; 283b04b7da8Stsutsui break; 284b04b7da8Stsutsui case 4: 285b04b7da8Stsutsui if (sc->sc_fb->dheight == 400) 286b04b7da8Stsutsui fbname = "HP98543 topcat"; 287b04b7da8Stsutsui else 288b04b7da8Stsutsui fbname = "HP98545 topcat"; 289b04b7da8Stsutsui break; 290b04b7da8Stsutsui case 6: 291b04b7da8Stsutsui fbname = "HP98547 topcat"; 292b04b7da8Stsutsui break; 293b04b7da8Stsutsui } 294b04b7da8Stsutsui break; 295b04b7da8Stsutsui case GID_HRCCATSEYE: 296b04b7da8Stsutsui fbname = "HP98550 catseye"; /* also A1416 kathmandu */ 297b04b7da8Stsutsui break; 298b04b7da8Stsutsui case GID_LRCATSEYE: 299b04b7da8Stsutsui fbname = "HP98549 catseye"; 300b04b7da8Stsutsui break; 301b04b7da8Stsutsui case GID_HRMCATSEYE: 302b04b7da8Stsutsui fbname = "HP98548 catseye"; 303b04b7da8Stsutsui break; 304b04b7da8Stsutsui } 305b04b7da8Stsutsui 306b04b7da8Stsutsui diofb_end_attach(sc->sc_dev, &topcat_accessops, sc->sc_fb, 307b04b7da8Stsutsui sc->sc_scode == conscode, fbname); 308b04b7da8Stsutsui } 309b04b7da8Stsutsui 310b04b7da8Stsutsui /* 311b04b7da8Stsutsui * Initialize hardware and display routines. 312b04b7da8Stsutsui */ 313b04b7da8Stsutsui int 314b04b7da8Stsutsui topcat_reset(struct diofb *fb, int scode, struct diofbreg *fbr) 315b04b7da8Stsutsui { 316b04b7da8Stsutsui volatile struct tcboxfb *tc = (struct tcboxfb *)fbr; 317f4485e64Stsutsui struct rasops_info *ri = &fb->ri; 318b04b7da8Stsutsui int rc; 319b04b7da8Stsutsui u_int i; 320f4485e64Stsutsui bool sparse = false; 321b04b7da8Stsutsui 322b04b7da8Stsutsui if ((rc = diofb_fbinquire(fb, scode, fbr)) != 0) 3235d7f465dStsutsui return rc; 324b04b7da8Stsutsui 325b04b7da8Stsutsui /* 326b04b7da8Stsutsui * If we could not get a valid number of planes, determine it 327b04b7da8Stsutsui * by writing to the first frame buffer display location, 328b04b7da8Stsutsui * then reading it back. 329b04b7da8Stsutsui */ 330b04b7da8Stsutsui if (fb->planes == 0) { 3315d7f465dStsutsui volatile uint8_t *fbp; 3325d7f465dStsutsui uint8_t save; 333b04b7da8Stsutsui 3345d7f465dStsutsui fbp = (uint8_t *)fb->fbkva; 335b04b7da8Stsutsui tc->fben = ~0; 336b04b7da8Stsutsui tc->wen = ~0; 337b04b7da8Stsutsui tc->ren = ~0; 338b04b7da8Stsutsui tc->prr = RR_COPY; 339b04b7da8Stsutsui save = *fbp; 340b04b7da8Stsutsui *fbp = 0xff; 341b04b7da8Stsutsui fb->planemask = *fbp; 342b04b7da8Stsutsui *fbp = save; 343b04b7da8Stsutsui 344b04b7da8Stsutsui for (fb->planes = 1; fb->planemask >= (1 << fb->planes); 345b04b7da8Stsutsui fb->planes++); 346b04b7da8Stsutsui if (fb->planes > 8) 347b04b7da8Stsutsui fb->planes = 8; 348b04b7da8Stsutsui fb->planemask = (1 << fb->planes) - 1; 349b04b7da8Stsutsui } 350b04b7da8Stsutsui 35118c9e2cfStsutsui /* 35218c9e2cfStsutsui * Some displays, such as the HP332 and HP340 internal video 35318c9e2cfStsutsui * and HP98542/98543 appear to return a display width of 1024 354e812a166Stsutsui * instead of 512. It looks these boards have actually have 355e812a166Stsutsui * enough 64KB (1bpp) or 256KB (4bpp) VRAM and RAMDAC capabilities 356e812a166Stsutsui * to display 1024x400 pixels. 35718c9e2cfStsutsui * 358e812a166Stsutsui * However HP's officlal "Service Information Manual" for 359e812a166Stsutsui * "HP 900 Series 300 Computers Models 330/350" says: 360e812a166Stsutsui * "The medium-resolution board uses eight memory chips per plane. 361e812a166Stsutsui * This is enough to display 512 doubled pixels by 400 scan lines." 362e812a166Stsutsui * 363e812a166Stsutsui * This "512 doubled pixels" implies that the native HP-UX treated 364e812a166Stsutsui * these 1024x400 framebuffers as pseudo 512x400 ones because 365e812a166Stsutsui * ancient 1980s CRTs (such as 35741) didn't display such higher 366e812a166Stsutsui * resolution. Furthermore, even modern LCDs can only handle 367e812a166Stsutsui * upto 720 pixels in the "400 line" as VGA compatible mode. 368e812a166Stsutsui * 369e812a166Stsutsui * As mentioned above, we treat these 1024x400 1 bit or 4 bit 370e812a166Stsutsui * framebuffers as "2 bytes per pixel" ones, so we have to handle 371e812a166Stsutsui * 512 pixels per line with 1024 bytes per line. 37218c9e2cfStsutsui */ 37318c9e2cfStsutsui if (fb->planes <= 4 && fb->dwidth == 1024 && fb->dheight == 400) { 37418c9e2cfStsutsui fb->dwidth = 512; 375f4485e64Stsutsui sparse = true; 37618c9e2cfStsutsui } 37718c9e2cfStsutsui 378b04b7da8Stsutsui fb->bmv = topcat_windowmove; 379b04b7da8Stsutsui topcat_restore(fb); 380b04b7da8Stsutsui diofb_fbsetup(fb); 381f4485e64Stsutsui if (!sparse) { 382f4485e64Stsutsui /* save original rasops putchar op */ 383f4485e64Stsutsui fb->wsputchar = ri->ri_ops.putchar; 384f4485e64Stsutsui ri->ri_ops.putchar = topcat_putchar8; 385f4485e64Stsutsui } else { 386f4485e64Stsutsui ri->ri_ops.putchar = topcat_putchar1_4; 387f4485e64Stsutsui /* copycols and erasecols ops require byte size of fontwidth */ 388f4485e64Stsutsui fb->wsd.fontwidth *= 2; 389f4485e64Stsutsui /* copyrows and eraserows ops require byte size per line */ 390f4485e64Stsutsui ri->ri_emuwidth *= 2; 391f4485e64Stsutsui } 392b04b7da8Stsutsui for (i = 0; i <= fb->planemask; i++) 393b04b7da8Stsutsui topcat_setcolor(fb, i); 394b04b7da8Stsutsui 3955d7f465dStsutsui return 0; 396b04b7da8Stsutsui } 397b04b7da8Stsutsui 398b04b7da8Stsutsui void 399b04b7da8Stsutsui topcat_restore(struct diofb *fb) 400b04b7da8Stsutsui { 401b04b7da8Stsutsui volatile struct tcboxfb *tc = (struct tcboxfb *)fb->regkva; 402b04b7da8Stsutsui 403b04b7da8Stsutsui /* 404b04b7da8Stsutsui * Catseye looks a lot like a topcat, but not completely. 405b04b7da8Stsutsui * So, we set some bits to make it work. 406b04b7da8Stsutsui */ 407b04b7da8Stsutsui if (tc->regs.fbid != GID_TOPCAT) { 408b04b7da8Stsutsui while ((tc->catseye_status & 1)) 409b04b7da8Stsutsui ; 410b04b7da8Stsutsui tc->catseye_status = 0x0; 411b04b7da8Stsutsui tc->vb_select = 0x0; 412b04b7da8Stsutsui tc->tcntrl = 0x0; 413b04b7da8Stsutsui tc->acntrl = 0x0; 414b04b7da8Stsutsui tc->pncntrl = 0x0; 415b04b7da8Stsutsui tc->rug_cmdstat = 0x90; 416b04b7da8Stsutsui } 417b04b7da8Stsutsui 418b04b7da8Stsutsui /* 419b04b7da8Stsutsui * Enable reading/writing of all the planes. 420b04b7da8Stsutsui */ 421b04b7da8Stsutsui tc->fben = fb->planemask; 422b04b7da8Stsutsui tc->wen = fb->planemask; 423b04b7da8Stsutsui tc->ren = fb->planemask; 424b04b7da8Stsutsui tc->prr = RR_COPY; 425b04b7da8Stsutsui 426b04b7da8Stsutsui /* Enable display */ 427edce15e3Stsutsui tc->nblank = fb->planemask; 428b04b7da8Stsutsui } 429b04b7da8Stsutsui 430b04b7da8Stsutsui int 431b04b7da8Stsutsui topcat_ioctl(void *v, void *vs, u_long cmd, void *data, int flags, 432b04b7da8Stsutsui struct lwp *l) 433b04b7da8Stsutsui { 434b04b7da8Stsutsui struct diofb *fb = v; 435b04b7da8Stsutsui struct wsdisplay_fbinfo *wdf; 436b04b7da8Stsutsui u_int i; 437b04b7da8Stsutsui 438b04b7da8Stsutsui switch (cmd) { 439b04b7da8Stsutsui case WSDISPLAYIO_GTYPE: 440b04b7da8Stsutsui *(u_int *)data = WSDISPLAY_TYPE_TOPCAT; 441b04b7da8Stsutsui return 0; 442b04b7da8Stsutsui case WSDISPLAYIO_SMODE: 443b04b7da8Stsutsui fb->mapmode = *(u_int *)data; 444b04b7da8Stsutsui if (fb->mapmode == WSDISPLAYIO_MODE_EMUL) { 445b04b7da8Stsutsui topcat_restore(fb); 446b04b7da8Stsutsui for (i = 0; i <= fb->planemask; i++) 447b04b7da8Stsutsui topcat_setcolor(fb, i); 448b04b7da8Stsutsui } 449b04b7da8Stsutsui return 0; 450b04b7da8Stsutsui case WSDISPLAYIO_GINFO: 451b04b7da8Stsutsui wdf = (void *)data; 452b04b7da8Stsutsui wdf->width = fb->ri.ri_width; 453b04b7da8Stsutsui wdf->height = fb->ri.ri_height; 454b04b7da8Stsutsui wdf->depth = fb->ri.ri_depth; 455b04b7da8Stsutsui wdf->cmsize = 1 << fb->planes; 456b04b7da8Stsutsui return 0; 457b04b7da8Stsutsui case WSDISPLAYIO_LINEBYTES: 458b04b7da8Stsutsui *(u_int *)data = fb->ri.ri_stride; 459b04b7da8Stsutsui return 0; 460b04b7da8Stsutsui case WSDISPLAYIO_GETCMAP: 46166933893Stsutsui if (fb->planemask == 1) 46266933893Stsutsui return EPASSTHROUGH; 4635d7f465dStsutsui return diofb_getcmap(fb, (struct wsdisplay_cmap *)data); 464b04b7da8Stsutsui case WSDISPLAYIO_PUTCMAP: 46566933893Stsutsui if (fb->planemask == 1) 46666933893Stsutsui return EPASSTHROUGH; 4675d7f465dStsutsui return topcat_setcmap(fb, (struct wsdisplay_cmap *)data); 468b04b7da8Stsutsui case WSDISPLAYIO_GVIDEO: 469b04b7da8Stsutsui case WSDISPLAYIO_SVIDEO: 470b04b7da8Stsutsui return EPASSTHROUGH; 471b04b7da8Stsutsui } 472b04b7da8Stsutsui 473b04b7da8Stsutsui return EPASSTHROUGH; 474b04b7da8Stsutsui } 475b04b7da8Stsutsui 476b04b7da8Stsutsui void 477b04b7da8Stsutsui topcat_setcolor(struct diofb *fb, u_int index) 478b04b7da8Stsutsui { 479b04b7da8Stsutsui volatile struct tcboxfb *tc = (struct tcboxfb *)fb->regkva; 480b04b7da8Stsutsui 48166933893Stsutsui /* No color map registers on monochrome framebuffers. */ 48266933893Stsutsui if (fb->planemask == 1) 48366933893Stsutsui return; 48466933893Stsutsui 485801e6655Stsutsui tc_waitbusy(tc, fb->planemask); 486801e6655Stsutsui 487b04b7da8Stsutsui if (tc->regs.fbid != GID_TOPCAT) { 488b04b7da8Stsutsui tccm_waitbusy(tc); 489edce15e3Stsutsui tc->plane_mask = fb->planemask; 490b04b7da8Stsutsui tc->cindex = ~index; 491b04b7da8Stsutsui tc->rdata = fb->cmap.r[index]; 492b04b7da8Stsutsui tc->gdata = fb->cmap.g[index]; 493b04b7da8Stsutsui tc->bdata = fb->cmap.b[index]; 494b04b7da8Stsutsui tc->strobe = 0xff; 49560d13f5dStsutsui /* XXX delay required on 68020/30 to avoid bus error */ 49660d13f5dStsutsui DELAY(100); 497b04b7da8Stsutsui 498b04b7da8Stsutsui tccm_waitbusy(tc); 499b04b7da8Stsutsui tc->cindex = 0; 500b04b7da8Stsutsui } else { 501b04b7da8Stsutsui tccm_waitbusy(tc); 502edce15e3Stsutsui tc->plane_mask = fb->planemask; 503b04b7da8Stsutsui tc->rdata = fb->cmap.r[index]; 504b04b7da8Stsutsui tc->gdata = fb->cmap.g[index]; 505b04b7da8Stsutsui tc->bdata = fb->cmap.b[index]; 50629856787Stsutsui DELAY(1); /* necessary for at least old HP98543 */ 507b04b7da8Stsutsui tc->cindex = ~index; 50829856787Stsutsui DELAY(1); /* necessary for at least old HP98543 */ 509b04b7da8Stsutsui tc->strobe = 0xff; 51060d13f5dStsutsui /* XXX delay required on 68020/30 to avoid bus error */ 51160d13f5dStsutsui DELAY(100); 512b04b7da8Stsutsui 513b04b7da8Stsutsui tccm_waitbusy(tc); 514b04b7da8Stsutsui tc->rdata = 0; 515b04b7da8Stsutsui tc->gdata = 0; 516b04b7da8Stsutsui tc->bdata = 0; 517b04b7da8Stsutsui tc->cindex = 0; 518b04b7da8Stsutsui } 519b04b7da8Stsutsui } 520b04b7da8Stsutsui 521b04b7da8Stsutsui int 522b04b7da8Stsutsui topcat_setcmap(struct diofb *fb, struct wsdisplay_cmap *cm) 523b04b7da8Stsutsui { 5245d7f465dStsutsui uint8_t r[256], g[256], b[256]; 525b04b7da8Stsutsui u_int index = cm->index, count = cm->count; 526b04b7da8Stsutsui u_int colcount = 1 << fb->planes; 527b04b7da8Stsutsui int error; 528b04b7da8Stsutsui 529b04b7da8Stsutsui if (index >= colcount || count > colcount - index) 5305d7f465dStsutsui return EINVAL; 531b04b7da8Stsutsui 532b04b7da8Stsutsui if ((error = copyin(cm->red, r, count)) != 0) 5335d7f465dStsutsui return error; 534b04b7da8Stsutsui if ((error = copyin(cm->green, g, count)) != 0) 5355d7f465dStsutsui return error; 536b04b7da8Stsutsui if ((error = copyin(cm->blue, b, count)) != 0) 5375d7f465dStsutsui return error; 538b04b7da8Stsutsui 539b04b7da8Stsutsui memcpy(fb->cmap.r + index, r, count); 540b04b7da8Stsutsui memcpy(fb->cmap.g + index, g, count); 541b04b7da8Stsutsui memcpy(fb->cmap.b + index, b, count); 542b04b7da8Stsutsui 543b04b7da8Stsutsui while (count-- != 0) 544b04b7da8Stsutsui topcat_setcolor(fb, index++); 545b04b7da8Stsutsui 5465d7f465dStsutsui return 0; 547b04b7da8Stsutsui } 548b04b7da8Stsutsui 549b04b7da8Stsutsui /* 550b04b7da8Stsutsui * Accelerated routines 551b04b7da8Stsutsui */ 552b04b7da8Stsutsui 553b04b7da8Stsutsui int 5545d7f465dStsutsui topcat_windowmove(struct diofb *fb, uint16_t sx, uint16_t sy, 5555d7f465dStsutsui uint16_t dx, uint16_t dy, uint16_t cx, uint16_t cy, int16_t rop, 556b04b7da8Stsutsui int16_t planemask) 557b04b7da8Stsutsui { 558b04b7da8Stsutsui volatile struct tcboxfb *tc = (struct tcboxfb *)fb->regkva; 559b04b7da8Stsutsui 560b04b7da8Stsutsui tc_waitbusy(tc, fb->planemask); 561b04b7da8Stsutsui 562b04b7da8Stsutsui if (planemask != 0xff) { 563b04b7da8Stsutsui tc->wen = planemask ^ 0xff; 564b04b7da8Stsutsui tc->wmrr = rop ^ 0x0f; 565b04b7da8Stsutsui tc->wen = fb->planemask; 566edce15e3Stsutsui } else { 567edce15e3Stsutsui tc->wen = planemask; 568edce15e3Stsutsui tc->wmrr = rop; 569b04b7da8Stsutsui } 570b04b7da8Stsutsui tc->source_y = sy; 571b04b7da8Stsutsui tc->source_x = sx; 572b04b7da8Stsutsui tc->dest_y = dy; 573b04b7da8Stsutsui tc->dest_x = dx; 574b04b7da8Stsutsui tc->wheight = cy; 575b04b7da8Stsutsui tc->wwidth = cx; 576b04b7da8Stsutsui tc->wmove = fb->planemask; 577b04b7da8Stsutsui 5785d7f465dStsutsui return 0; 579b04b7da8Stsutsui } 580b04b7da8Stsutsui 581f4485e64Stsutsui static void 582f4485e64Stsutsui topcat_putchar8(void *cookie, int row, int col, u_int uc, long attr) 583f4485e64Stsutsui { 584f4485e64Stsutsui struct rasops_info *ri = (struct rasops_info *)cookie; 585f4485e64Stsutsui struct diofb *diofb = ri->ri_hw; 586f4485e64Stsutsui volatile struct tcboxfb *tc = (struct tcboxfb *)diofb->regkva; 587f4485e64Stsutsui 588f4485e64Stsutsui /* Wait windowmove ops complete before drawing a glyph */ 589f4485e64Stsutsui tc_waitbusy(tc, diofb->planemask); 590f4485e64Stsutsui 591f4485e64Stsutsui /* Call the original rasops putchar */ 592f4485e64Stsutsui (*diofb->wsputchar)(cookie, row, col, uc, attr); 593f4485e64Stsutsui } 594f4485e64Stsutsui 595f4485e64Stsutsui /* 596e812a166Stsutsui * Put a single character on 1 bpp (98542) or 4 bpp (98543) variants 597e812a166Stsutsui * with 1024x400 VRAM to treat them as a pseudo 512x400 bitmap. 598f4485e64Stsutsui */ 599f4485e64Stsutsui static void 600f4485e64Stsutsui topcat_putchar1_4(void *cookie, int row, int col, u_int uc, long attr) 601f4485e64Stsutsui { 602f4485e64Stsutsui int width, height, cnt, fs; 603f4485e64Stsutsui uint32_t fb; 604f4485e64Stsutsui uint8_t *fr, clr[2]; 605f4485e64Stsutsui uint8_t *dp, *rp; 606f4485e64Stsutsui struct rasops_info *ri; 607f4485e64Stsutsui struct diofb *diofb; 608f4485e64Stsutsui volatile struct tcboxfb *tc; 609f4485e64Stsutsui 610f4485e64Stsutsui ri = (struct rasops_info *)cookie; 611f4485e64Stsutsui 612f4485e64Stsutsui if (!CHAR_IN_FONT(uc, ri->ri_font)) 613f4485e64Stsutsui return; 614f4485e64Stsutsui 615f4485e64Stsutsui rp = ri->ri_bits + (row * ri->ri_yscale) + 616f4485e64Stsutsui (col * ri->ri_xscale * 2); 617f4485e64Stsutsui 618f4485e64Stsutsui height = ri->ri_font->fontheight; 619f4485e64Stsutsui width = ri->ri_font->fontwidth; 620f4485e64Stsutsui clr[0] = (uint8_t)ri->ri_devcmap[(attr >> 16) & 0xf]; 621f4485e64Stsutsui clr[1] = (uint8_t)ri->ri_devcmap[(attr >> 24) & 0xf]; 622f4485e64Stsutsui 623f4485e64Stsutsui /* Wait windowmove ops complete before drawing a glyph */ 624f4485e64Stsutsui diofb = ri->ri_hw; 625f4485e64Stsutsui tc = (struct tcboxfb *)diofb->regkva; 626f4485e64Stsutsui tc_waitbusy(tc, diofb->planemask); 627f4485e64Stsutsui 628f4485e64Stsutsui /* 629e812a166Stsutsui * We have to put pixel data to both odd and even addresses 630e812a166Stsutsui * to handle "doubled pixels" as noted above. 631f4485e64Stsutsui */ 632f4485e64Stsutsui if (uc == ' ') { 633f4485e64Stsutsui uint16_t c = clr[0]; 634f4485e64Stsutsui 635f4485e64Stsutsui c = c << 8 | c; 636f4485e64Stsutsui while (height--) { 637f4485e64Stsutsui dp = rp; 638f4485e64Stsutsui rp += ri->ri_stride; 639f4485e64Stsutsui 640f4485e64Stsutsui for (cnt = width; cnt; cnt--) { 641f4485e64Stsutsui *(uint16_t *)dp = c; 642f4485e64Stsutsui dp += 2; 643f4485e64Stsutsui } 644f4485e64Stsutsui } 645f4485e64Stsutsui } else { 646f4485e64Stsutsui uc -= ri->ri_font->firstchar; 647f4485e64Stsutsui fr = (uint8_t *)ri->ri_font->data + uc * ri->ri_fontscale; 648f4485e64Stsutsui fs = ri->ri_font->stride; 649f4485e64Stsutsui 650f4485e64Stsutsui while (height--) { 651f4485e64Stsutsui dp = rp; 652f4485e64Stsutsui fb = be32dec(fr); 653f4485e64Stsutsui fr += fs; 654f4485e64Stsutsui rp += ri->ri_stride; 655f4485e64Stsutsui 656f4485e64Stsutsui for (cnt = width; cnt; cnt--) { 657f4485e64Stsutsui uint16_t c = clr[(fb >> 31) & 1]; 658f4485e64Stsutsui 659f4485e64Stsutsui c = c << 8 | c; 660f4485e64Stsutsui *(uint16_t *)dp = c; 661f4485e64Stsutsui dp += 2; 662f4485e64Stsutsui fb <<= 1; 663f4485e64Stsutsui } 664f4485e64Stsutsui } 665f4485e64Stsutsui } 666f4485e64Stsutsui 667f4485e64Stsutsui /* Do underline */ 668f4485e64Stsutsui if ((attr & WSATTR_UNDERLINE) != 0) { 669f4485e64Stsutsui uint16_t c = clr[1]; 670f4485e64Stsutsui 671f4485e64Stsutsui c = c << 8 | c; 672f4485e64Stsutsui rp -= ri->ri_stride * ri->ri_ul.off; 673f4485e64Stsutsui 674f4485e64Stsutsui while (width--) { 675f4485e64Stsutsui *(uint16_t *)rp = c; 676f4485e64Stsutsui rp += 2; 677f4485e64Stsutsui } 678f4485e64Stsutsui } 679f4485e64Stsutsui } 680b04b7da8Stsutsui 681b04b7da8Stsutsui /* 682b04b7da8Stsutsui * Topcat/catseye console attachment 683b04b7da8Stsutsui */ 684b04b7da8Stsutsui 685b04b7da8Stsutsui int 686b04b7da8Stsutsui topcatcnattach(bus_space_tag_t bst, bus_addr_t addr, int scode) 687b04b7da8Stsutsui { 688b04b7da8Stsutsui bus_space_handle_t bsh; 689b04b7da8Stsutsui void *va; 690b04b7da8Stsutsui struct diofbreg *fbr; 691b04b7da8Stsutsui struct diofb *fb = &diofb_cn; 692b04b7da8Stsutsui int size; 693b04b7da8Stsutsui 694b04b7da8Stsutsui if (bus_space_map(bst, addr, PAGE_SIZE, 0, &bsh)) 695b04b7da8Stsutsui return 1; 696b04b7da8Stsutsui va = bus_space_vaddr(bst, bsh); 697b04b7da8Stsutsui fbr = va; 698b04b7da8Stsutsui 699b04b7da8Stsutsui if (badaddr(va) || fbr->id != GRFHWID) { 700b04b7da8Stsutsui bus_space_unmap(bst, bsh, PAGE_SIZE); 701b04b7da8Stsutsui return 1; 702b04b7da8Stsutsui } 703b04b7da8Stsutsui 704b04b7da8Stsutsui switch (fbr->fbid) { 705b04b7da8Stsutsui case GID_TOPCAT: 706b04b7da8Stsutsui case GID_LRCATSEYE: 707b04b7da8Stsutsui case GID_HRCCATSEYE: 708b04b7da8Stsutsui case GID_HRMCATSEYE: 709b04b7da8Stsutsui break; 710b04b7da8Stsutsui 711b04b7da8Stsutsui default: 712b04b7da8Stsutsui bus_space_unmap(bst, bsh, PAGE_SIZE); 713b04b7da8Stsutsui return 1; 714b04b7da8Stsutsui } 715b04b7da8Stsutsui 716b04b7da8Stsutsui size = DIO_SIZE(scode, va); 717b04b7da8Stsutsui 718b04b7da8Stsutsui bus_space_unmap(bst, bsh, PAGE_SIZE); 719b04b7da8Stsutsui if (bus_space_map(bst, addr, size, 0, &bsh)) 720b04b7da8Stsutsui return 1; 721b04b7da8Stsutsui va = bus_space_vaddr(bst, bsh); 722b04b7da8Stsutsui 723b04b7da8Stsutsui /* 724b04b7da8Stsutsui * Initialize the framebuffer hardware. 725b04b7da8Stsutsui */ 726b04b7da8Stsutsui conscode = scode; 727b04b7da8Stsutsui conaddr = va; 728b04b7da8Stsutsui topcat_reset(fb, conscode, (struct diofbreg *)conaddr); 729b04b7da8Stsutsui 730b04b7da8Stsutsui /* 731b04b7da8Stsutsui * Initialize the terminal emulator. 732b04b7da8Stsutsui */ 733b04b7da8Stsutsui diofb_cnattach(fb); 734b04b7da8Stsutsui return 0; 735b04b7da8Stsutsui } 736