1*f5dff4bdSjmcneill /* $NetBSD: wiifb.c,v 1.7 2024/10/13 16:21:37 jmcneill Exp $ */ 28d626ee2Sjmcneill 38d626ee2Sjmcneill /*- 48d626ee2Sjmcneill * Copyright (c) 2024 Jared McNeill <jmcneill@invisible.ca> 58d626ee2Sjmcneill * All rights reserved. 68d626ee2Sjmcneill * 78d626ee2Sjmcneill * Redistribution and use in source and binary forms, with or without 88d626ee2Sjmcneill * modification, are permitted provided that the following conditions 98d626ee2Sjmcneill * are met: 108d626ee2Sjmcneill * 1. Redistributions of source code must retain the above copyright 118d626ee2Sjmcneill * notice, this list of conditions and the following disclaimer. 128d626ee2Sjmcneill * 2. Redistributions in binary form must reproduce the above copyright 138d626ee2Sjmcneill * notice, this list of conditions and the following disclaimer in the 148d626ee2Sjmcneill * documentation and/or other materials provided with the distribution. 158d626ee2Sjmcneill * 168d626ee2Sjmcneill * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 178d626ee2Sjmcneill * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 188d626ee2Sjmcneill * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 198d626ee2Sjmcneill * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 208d626ee2Sjmcneill * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 218d626ee2Sjmcneill * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 228d626ee2Sjmcneill * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 238d626ee2Sjmcneill * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 248d626ee2Sjmcneill * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 258d626ee2Sjmcneill * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 268d626ee2Sjmcneill * SUCH DAMAGE. 278d626ee2Sjmcneill */ 288d626ee2Sjmcneill 298d626ee2Sjmcneill #include <sys/cdefs.h> 30*f5dff4bdSjmcneill __KERNEL_RCSID(0, "$NetBSD: wiifb.c,v 1.7 2024/10/13 16:21:37 jmcneill Exp $"); 318d626ee2Sjmcneill 328d626ee2Sjmcneill #include <sys/param.h> 338d626ee2Sjmcneill #include <sys/bus.h> 348d626ee2Sjmcneill #include <sys/device.h> 358d626ee2Sjmcneill #include <sys/systm.h> 368d626ee2Sjmcneill 378d626ee2Sjmcneill #include <machine/wii.h> 388d626ee2Sjmcneill 398d626ee2Sjmcneill #include <dev/videomode/videomode.h> 408d626ee2Sjmcneill #include <dev/wsfb/genfbvar.h> 418d626ee2Sjmcneill 428d626ee2Sjmcneill #include "mainbus.h" 438d626ee2Sjmcneill #include "vireg.h" 44d6982a45Sjmcneill #include "viio.h" 458d626ee2Sjmcneill 468d626ee2Sjmcneill #define WIIFB_ERROR_BLINK_INTERVAL 1000000 478d626ee2Sjmcneill 48c11be502Sjmcneill #define WIIFB_TOP_BOTTOM_BORDER 16 49c11be502Sjmcneill #define WIIFB_EFFECTIVE_START(p, w) \ 50c11be502Sjmcneill ((uintptr_t)(p) + WIIFB_TOP_BOTTOM_BORDER * (w) * 2) 51c11be502Sjmcneill #define WIIFB_EFFECTIVE_HEIGHT(h) \ 52c11be502Sjmcneill ((h) - WIIFB_TOP_BOTTOM_BORDER * 2) 53c11be502Sjmcneill 54c11be502Sjmcneill 558d626ee2Sjmcneill struct wiifb_mode { 568d626ee2Sjmcneill const char * name; 578d626ee2Sjmcneill u_int width; 588d626ee2Sjmcneill u_int height; 598d626ee2Sjmcneill u_int lines; 608d626ee2Sjmcneill }; 618d626ee2Sjmcneill 628d626ee2Sjmcneill static uint32_t wiifb_devcmap[16] = { 638d626ee2Sjmcneill 0x00800080, /* Black */ 648d626ee2Sjmcneill 0x1dff1d6b, /* Blue */ 658d626ee2Sjmcneill 0x4b554b4a, /* Green */ 668d626ee2Sjmcneill 0x80808080, /* Cyan */ 678d626ee2Sjmcneill 0x4c544cff, /* Red */ 688d626ee2Sjmcneill 0x3aaa34b5, /* Magenta */ 698d626ee2Sjmcneill 0x7140718a, /* Brown */ 708d626ee2Sjmcneill 0xff80ff80, /* White */ 718d626ee2Sjmcneill 0x80808080, /* Gray */ 728d626ee2Sjmcneill 0xc399c36a, /* Bright Blue */ 738d626ee2Sjmcneill 0xd076d074, /* Bright Green */ 748d626ee2Sjmcneill 0x80808080, /* Bright Cyan */ 758d626ee2Sjmcneill 0x4c544cff, /* Bright Red */ 768d626ee2Sjmcneill 0x3aaa34b5, /* Bright Magenta */ 778d626ee2Sjmcneill 0xe100e194, /* Bright Yellow */ 788d626ee2Sjmcneill 0xff80ff80 /* Bright White */ 798d626ee2Sjmcneill }; 808d626ee2Sjmcneill 818d626ee2Sjmcneill #define WIIFB_MODE_INDEX(fmt, interlaced) ((fmt << 1) | interlaced) 828d626ee2Sjmcneill 838d626ee2Sjmcneill static const struct wiifb_mode wiifb_modes[] = { 848d626ee2Sjmcneill [WIIFB_MODE_INDEX(VI_DCR_FMT_NTSC, 0)] = { 858d626ee2Sjmcneill .name = "NTSC 480p", 868d626ee2Sjmcneill .width = 640, 878d626ee2Sjmcneill .height = 480, 888d626ee2Sjmcneill .lines = 525, 898d626ee2Sjmcneill }, 908d626ee2Sjmcneill [WIIFB_MODE_INDEX(VI_DCR_FMT_NTSC, 1)] = { 918d626ee2Sjmcneill .name = "NTSC 480i", 928d626ee2Sjmcneill .width = 640, 938d626ee2Sjmcneill .height = 480, 948d626ee2Sjmcneill .lines = 525, 958d626ee2Sjmcneill }, 968e1eb2f4Shgutch [WIIFB_MODE_INDEX(VI_DCR_FMT_PAL, 1)] = { 978e1eb2f4Shgutch .name = "PAL 576i", 988e1eb2f4Shgutch .width = 640, 998e1eb2f4Shgutch .height = 574, 1008e1eb2f4Shgutch .lines = 625, 1018e1eb2f4Shgutch }, 1028e1eb2f4Shgutch 1038d626ee2Sjmcneill }; 1048d626ee2Sjmcneill #define WIIFB_NMODES __arraycount(wiifb_modes) 1058d626ee2Sjmcneill 1068d626ee2Sjmcneill struct wiifb_softc { 1078d626ee2Sjmcneill struct genfb_softc sc_gen; 1088d626ee2Sjmcneill 1098d626ee2Sjmcneill bus_space_tag_t sc_bst; 1108d626ee2Sjmcneill bus_space_handle_t sc_bsh; 1118d626ee2Sjmcneill 1128d626ee2Sjmcneill void *sc_bits; 1138d626ee2Sjmcneill 1148d626ee2Sjmcneill uint8_t sc_format; 1158d626ee2Sjmcneill bool sc_interlaced; 1168d626ee2Sjmcneill 1178d626ee2Sjmcneill const struct wiifb_mode *sc_curmode; 1188d626ee2Sjmcneill }; 1198d626ee2Sjmcneill 1208d626ee2Sjmcneill #define RD2(sc, reg) \ 1218d626ee2Sjmcneill bus_space_read_2((sc)->sc_bst, (sc)->sc_bsh, (reg)) 1228d626ee2Sjmcneill #define RD4(sc, reg) \ 1238d626ee2Sjmcneill bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) 1248d626ee2Sjmcneill #define WR2(sc, reg, val) \ 1258d626ee2Sjmcneill bus_space_write_2((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) 1268d626ee2Sjmcneill #define WR4(sc, reg, val) \ 1278d626ee2Sjmcneill bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) 1288d626ee2Sjmcneill 1298d626ee2Sjmcneill static int wiifb_match(device_t, cfdata_t, void *); 1308d626ee2Sjmcneill static void wiifb_attach(device_t, device_t, void *); 1318d626ee2Sjmcneill 1328d626ee2Sjmcneill static void wiifb_init(struct wiifb_softc *); 1338d626ee2Sjmcneill static void wiifb_set_mode(struct wiifb_softc *, uint8_t, bool); 1348d626ee2Sjmcneill static void wiifb_set_fb(struct wiifb_softc *); 1358d626ee2Sjmcneill 1368d626ee2Sjmcneill static int wiifb_ioctl(void *, void *, u_long, void *, int, lwp_t *); 1378d626ee2Sjmcneill static paddr_t wiifb_mmap(void *, void *, off_t, int); 1388d626ee2Sjmcneill 1398d626ee2Sjmcneill static struct genfb_ops wiifb_ops = { 1408d626ee2Sjmcneill .genfb_ioctl = wiifb_ioctl, 1418d626ee2Sjmcneill .genfb_mmap = wiifb_mmap, 1428d626ee2Sjmcneill }; 1438d626ee2Sjmcneill 1448d626ee2Sjmcneill CFATTACH_DECL_NEW(wiifb, sizeof(struct wiifb_softc), 1458d626ee2Sjmcneill wiifb_match, wiifb_attach, NULL, NULL); 1468d626ee2Sjmcneill 1478d626ee2Sjmcneill static int 1488d626ee2Sjmcneill wiifb_match(device_t parent, cfdata_t cf, void *aux) 1498d626ee2Sjmcneill { 1508d626ee2Sjmcneill struct mainbus_attach_args *maa = aux; 1518d626ee2Sjmcneill 1528d626ee2Sjmcneill return strcmp(maa->maa_name, "genfb") == 0; 1538d626ee2Sjmcneill } 1548d626ee2Sjmcneill 1558d626ee2Sjmcneill static void 1568d626ee2Sjmcneill wiifb_attach(device_t parent, device_t self, void *aux) 1578d626ee2Sjmcneill { 1588d626ee2Sjmcneill struct wiifb_softc *sc = device_private(self); 1598d626ee2Sjmcneill prop_dictionary_t dict = device_properties(self); 1608d626ee2Sjmcneill struct mainbus_attach_args *maa = aux; 161c11be502Sjmcneill u_int offset; 162c11be502Sjmcneill uint32_t *p; 1638d626ee2Sjmcneill int error; 1648d626ee2Sjmcneill 1658d626ee2Sjmcneill sc->sc_gen.sc_dev = self; 1668d626ee2Sjmcneill sc->sc_bst = maa->maa_bst; 1678d626ee2Sjmcneill error = bus_space_map(sc->sc_bst, maa->maa_addr, VI_SIZE, 0, 1688d626ee2Sjmcneill &sc->sc_bsh); 1698d626ee2Sjmcneill if (error != 0) { 1708d626ee2Sjmcneill panic("couldn't map registers"); 1718d626ee2Sjmcneill } 1728d626ee2Sjmcneill sc->sc_bits = mapiodev(XFB_START, XFB_SIZE, true); 1738d626ee2Sjmcneill 174c11be502Sjmcneill /* 175c11be502Sjmcneill * Paint the entire FB black. Use 4-byte accesses as the Wii will 176c11be502Sjmcneill * ignore 1- and 2- byte writes to uncached memory. 177c11be502Sjmcneill */ 178c11be502Sjmcneill for (p = sc->sc_bits, offset = 0; 179c11be502Sjmcneill offset < XFB_SIZE; 180c11be502Sjmcneill offset += 4, p++) { 181c11be502Sjmcneill *p = 0x00800080; 182c11be502Sjmcneill } 183c11be502Sjmcneill 1848d626ee2Sjmcneill wiifb_init(sc); 1858d626ee2Sjmcneill wiifb_set_mode(sc, sc->sc_format, sc->sc_interlaced); 1868d626ee2Sjmcneill 1878d626ee2Sjmcneill prop_dictionary_set_uint32(dict, "width", sc->sc_curmode->width); 188c11be502Sjmcneill prop_dictionary_set_uint32(dict, "height", 189c11be502Sjmcneill WIIFB_EFFECTIVE_HEIGHT(sc->sc_curmode->height)); 1908d626ee2Sjmcneill prop_dictionary_set_uint8(dict, "depth", 16); 1918d626ee2Sjmcneill prop_dictionary_set_uint32(dict, "address", XFB_START); 1928d626ee2Sjmcneill prop_dictionary_set_uint32(dict, "virtual_address", 193c11be502Sjmcneill WIIFB_EFFECTIVE_START(sc->sc_bits, sc->sc_curmode->width)); 1948d626ee2Sjmcneill prop_dictionary_set_uint64(dict, "devcmap", (uintptr_t)wiifb_devcmap); 1958d626ee2Sjmcneill 1968d626ee2Sjmcneill genfb_init(&sc->sc_gen); 1978d626ee2Sjmcneill 1988d626ee2Sjmcneill aprint_naive("\n"); 1998d626ee2Sjmcneill aprint_normal(": %s\n", sc->sc_curmode->name); 2008d626ee2Sjmcneill 2018d626ee2Sjmcneill genfb_cnattach(); 2028d626ee2Sjmcneill prop_dictionary_set_bool(dict, "is_console", true); 2038d626ee2Sjmcneill genfb_attach(&sc->sc_gen, &wiifb_ops); 2048d626ee2Sjmcneill } 2058d626ee2Sjmcneill 2068d626ee2Sjmcneill static void 2078d626ee2Sjmcneill wiifb_init(struct wiifb_softc *sc) 2088d626ee2Sjmcneill { 2098d626ee2Sjmcneill uint16_t dcr; 210d6982a45Sjmcneill uint16_t visel; 2118d626ee2Sjmcneill 2128d626ee2Sjmcneill /* Read current display format and interlaced settings. */ 2138d626ee2Sjmcneill dcr = RD2(sc, VI_DCR); 214d6982a45Sjmcneill if ((dcr & VI_DCR_ENB) != 0) { 2158d626ee2Sjmcneill sc->sc_format = __SHIFTOUT(dcr, VI_DCR_FMT); 2168d626ee2Sjmcneill sc->sc_interlaced = (dcr & VI_DCR_NIN) == 0; 217d6982a45Sjmcneill } else { 218d6982a45Sjmcneill visel = RD2(sc, VI_VISEL); 219d6982a45Sjmcneill sc->sc_format = VI_DCR_FMT_NTSC; 220d6982a45Sjmcneill sc->sc_interlaced = (visel & VI_VISEL_COMPONENT_CABLE) == 0; 221d6982a45Sjmcneill } 2228d626ee2Sjmcneill 2238d626ee2Sjmcneill /* Reset video interface. */ 224*f5dff4bdSjmcneill WR2(sc, VI_DCR, VI_DCR_RST); 225*f5dff4bdSjmcneill delay(1000); 226*f5dff4bdSjmcneill 227*f5dff4bdSjmcneill /* Initialize video format and interlace selector. */ 228*f5dff4bdSjmcneill dcr = __SHIFTIN(sc->sc_format, VI_DCR_FMT) | 229*f5dff4bdSjmcneill (sc->sc_interlaced ? 0 : VI_DCR_NIN); 230*f5dff4bdSjmcneill WR2(sc, VI_DCR, dcr); 2318d626ee2Sjmcneill } 2328d626ee2Sjmcneill 2338d626ee2Sjmcneill static void 2348d626ee2Sjmcneill wiifb_set_mode(struct wiifb_softc *sc, uint8_t format, bool interlaced) 2358d626ee2Sjmcneill { 2368d626ee2Sjmcneill u_int modeidx; 2379e64f9afSjmcneill u_int strides, reads; 2388d626ee2Sjmcneill 2398d626ee2Sjmcneill modeidx = WIIFB_MODE_INDEX(format, interlaced); 2408d626ee2Sjmcneill if (modeidx == WIIFB_MODE_INDEX(VI_DCR_FMT_NTSC, 1)) { 241d6982a45Sjmcneill /* NTSC 480i Magic numbers from YAGCD. */ 2428d626ee2Sjmcneill WR2(sc, VI_VTR, 0x0f06); 2438d626ee2Sjmcneill WR4(sc, VI_HTR0, 0x476901AD); 2448d626ee2Sjmcneill WR4(sc, VI_HTR1, 0x02EA5140); 2458d626ee2Sjmcneill WR4(sc, VI_VTO, 0x00030018); 2468d626ee2Sjmcneill WR4(sc, VI_VTE, 0x00020019); 2478d626ee2Sjmcneill WR4(sc, VI_BBOI, 0x410C410C); 2488d626ee2Sjmcneill WR4(sc, VI_BBEI, 0x40ED40ED); 249*f5dff4bdSjmcneill WR2(sc, VI_DPV, 0x0000); 250*f5dff4bdSjmcneill WR2(sc, VI_DPH, 0x0000); 251d6982a45Sjmcneill } else if (modeidx == WIIFB_MODE_INDEX(VI_DCR_FMT_NTSC, 0)) { 252d6982a45Sjmcneill /* NTSC 480p */ 253d6982a45Sjmcneill WR2(sc, VI_VTR, 0x1e0c); 254d6982a45Sjmcneill WR4(sc, VI_HTR0, 0x476901ad); 255d6982a45Sjmcneill WR4(sc, VI_HTR1, 0x030a4940); 256d6982a45Sjmcneill WR4(sc, VI_VTO, 0x00060030); 257d6982a45Sjmcneill WR4(sc, VI_VTE, 0x00060030); 258d6982a45Sjmcneill WR4(sc, VI_BBOI, 0x81d881d8); 259d6982a45Sjmcneill WR4(sc, VI_BBEI, 0x81d881d8); 260*f5dff4bdSjmcneill WR2(sc, VI_DPV, 0x0000); 261*f5dff4bdSjmcneill WR2(sc, VI_DPH, 0x0000); 2628e1eb2f4Shgutch } else if (modeidx == WIIFB_MODE_INDEX(VI_DCR_FMT_PAL, 1)) { 2638e1eb2f4Shgutch /* PAL 576i */ 2648e1eb2f4Shgutch WR2(sc, VI_VTR, 0x11f5); 2658e1eb2f4Shgutch WR4(sc, VI_HTR0, 0x4b6a01b0); 2668e1eb2f4Shgutch WR4(sc, VI_HTR1, 0x02f85640); 2678e1eb2f4Shgutch WR4(sc, VI_VTO, 0x00010023); 2688e1eb2f4Shgutch WR4(sc, VI_VTE, 0x00000024); 2698e1eb2f4Shgutch WR4(sc, VI_BBOI, 0x4d2b4d6d); 2708e1eb2f4Shgutch WR4(sc, VI_BBEI, 0x4d8a4d4c); 271*f5dff4bdSjmcneill WR2(sc, VI_DPV, 0x013c); 272*f5dff4bdSjmcneill WR2(sc, VI_DPH, 0x0144); 2738d626ee2Sjmcneill } else { 2748d626ee2Sjmcneill /* 2758d626ee2Sjmcneill * Display mode is not supported. Blink the slot LED to 2768d626ee2Sjmcneill * indicate failure. 2778d626ee2Sjmcneill */ 2788d626ee2Sjmcneill wii_slot_led_blink(WIIFB_ERROR_BLINK_INTERVAL); 2798d626ee2Sjmcneill } 2808d626ee2Sjmcneill 281c11be502Sjmcneill if (modeidx >= WIIFB_NMODES || wiifb_modes[modeidx].name == NULL) { 282c11be502Sjmcneill panic("Unsupported format (0x%x) / interlaced (%d) settings", 283c11be502Sjmcneill sc->sc_format, sc->sc_interlaced); 284c11be502Sjmcneill } 285c11be502Sjmcneill sc->sc_curmode = &wiifb_modes[modeidx]; 286c11be502Sjmcneill 287*f5dff4bdSjmcneill /* Filter coefficient table, values from YAGCD. */ 288*f5dff4bdSjmcneill WR4(sc, VI_FCT0, 0x1ae771f0); 289*f5dff4bdSjmcneill WR4(sc, VI_FCT1, 0x0db4a574); 290*f5dff4bdSjmcneill WR4(sc, VI_FCT2, 0x00c1188e); 291*f5dff4bdSjmcneill WR4(sc, VI_FCT3, 0xc4c0cbe2); 292*f5dff4bdSjmcneill WR4(sc, VI_FCT4, 0xfcecdecf); 293*f5dff4bdSjmcneill WR4(sc, VI_FCT5, 0x13130f08); 294*f5dff4bdSjmcneill WR4(sc, VI_FCT6, 0x00080C0f); 295*f5dff4bdSjmcneill 296*f5dff4bdSjmcneill /* Unknown registers. */ 297*f5dff4bdSjmcneill WR4(sc, VI_UNKNOWN_68H, 0x00ff0000); 298*f5dff4bdSjmcneill WR2(sc, VI_UNKNOWN_76H, 0x00ff); 299*f5dff4bdSjmcneill WR4(sc, VI_UNKNOWN_78H, 0x00ff00ff); 300*f5dff4bdSjmcneill WR4(sc, VI_UNKNOWN_7CH, 0x00ff00ff); 301*f5dff4bdSjmcneill 3028d626ee2Sjmcneill /* Picture configuration */ 3039e64f9afSjmcneill strides = (sc->sc_curmode->width * 2) / (interlaced ? 16 : 32); 3049e64f9afSjmcneill reads = (sc->sc_curmode->width * 2) / 32; 3059e64f9afSjmcneill WR2(sc, VI_PICCONF, 3069e64f9afSjmcneill __SHIFTIN(strides, VI_PICCONF_STRIDES) | 3079e64f9afSjmcneill __SHIFTIN(reads, VI_PICCONF_READS)); 3088d626ee2Sjmcneill 309d6982a45Sjmcneill /* Horizontal scaler configuration */ 310d6982a45Sjmcneill if (interlaced) { 3118d626ee2Sjmcneill WR2(sc, VI_HSR, __SHIFTIN(256, VI_HSR_STP)); 312d6982a45Sjmcneill } else { 313d6982a45Sjmcneill WR2(sc, VI_HSR, __SHIFTIN(244, VI_HSR_STP) | VI_HSR_HS_EN); 314d6982a45Sjmcneill } 3158d626ee2Sjmcneill 3168d626ee2Sjmcneill /* Video clock configuration */ 3178d626ee2Sjmcneill WR2(sc, VI_VICLK, 3188d626ee2Sjmcneill interlaced ? VI_VICLK_SEL_27MHZ : VI_VICLK_SEL_54MHZ); 3198d626ee2Sjmcneill 3208d626ee2Sjmcneill /* Horizontal scaling width */ 3218d626ee2Sjmcneill WR2(sc, VI_HSCALINGW, sc->sc_curmode->width); 3228d626ee2Sjmcneill 3238d626ee2Sjmcneill /* Set framebuffer address */ 3248d626ee2Sjmcneill wiifb_set_fb(sc); 325*f5dff4bdSjmcneill 326*f5dff4bdSjmcneill /* Finally, enable the framebuffer */ 327*f5dff4bdSjmcneill WR2(sc, VI_DCR, RD2(sc, VI_DCR) | VI_DCR_ENB); 3288d626ee2Sjmcneill } 3298d626ee2Sjmcneill 3308d626ee2Sjmcneill static void 3318d626ee2Sjmcneill wiifb_set_fb(struct wiifb_softc *sc) 3328d626ee2Sjmcneill { 3338d626ee2Sjmcneill uint32_t taddr = XFB_START; 3348d626ee2Sjmcneill uint32_t baddr = taddr + (sc->sc_interlaced ? 3358d626ee2Sjmcneill sc->sc_curmode->width * 2 : 0); 3368d626ee2Sjmcneill 3378d626ee2Sjmcneill WR4(sc, VI_TFBL, 3388d626ee2Sjmcneill VI_TFBL_PGOFF | 3398d626ee2Sjmcneill __SHIFTIN((taddr >> 5), VI_TFBL_FBB) | 3408d626ee2Sjmcneill __SHIFTIN((taddr / 2) & 0xf, VI_TFBL_XOF)); 3418d626ee2Sjmcneill WR4(sc, VI_TFBR, 0); 3428d626ee2Sjmcneill 3438d626ee2Sjmcneill WR4(sc, VI_BFBL, 3448d626ee2Sjmcneill VI_BFBL_PGOFF | 3458d626ee2Sjmcneill __SHIFTIN((baddr >> 5), VI_BFBL_FBB) | 3468d626ee2Sjmcneill __SHIFTIN((baddr / 2) & 0xf, VI_BFBL_XOF)); 3478d626ee2Sjmcneill WR4(sc, VI_BFBR, 0); 3488d626ee2Sjmcneill } 3498d626ee2Sjmcneill 3508d626ee2Sjmcneill static int 3518d626ee2Sjmcneill wiifb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, lwp_t *l) 3528d626ee2Sjmcneill { 3538d626ee2Sjmcneill struct wiifb_softc *sc = v; 3548d626ee2Sjmcneill struct wsdisplayio_bus_id *busid; 3558d626ee2Sjmcneill struct wsdisplayio_fbinfo *fbi; 356d6982a45Sjmcneill struct vi_regs *vr; 35740d8bddeSjmcneill u_int video; 3588d626ee2Sjmcneill 3598d626ee2Sjmcneill switch (cmd) { 3608d626ee2Sjmcneill case WSDISPLAYIO_GTYPE: 3618d626ee2Sjmcneill *(u_int *)data = WSDISPLAY_TYPE_HOLLYWOOD; 3628d626ee2Sjmcneill return 0; 3638d626ee2Sjmcneill case WSDISPLAYIO_GET_BUSID: 3648d626ee2Sjmcneill busid = data; 3658d626ee2Sjmcneill busid->bus_type = WSDISPLAYIO_BUS_SOC; 3668d626ee2Sjmcneill return 0; 3678d626ee2Sjmcneill case WSDISPLAYIO_GET_FBINFO: 3688d626ee2Sjmcneill fbi = data; 3698d626ee2Sjmcneill /* 3708d626ee2Sjmcneill * rasops info does not match the pixel encoding due to our 3718d626ee2Sjmcneill * devcmap, so fill out fbinfo manually instead of relying 3728d626ee2Sjmcneill * on wsdisplayio_get_fbinfo. 3738d626ee2Sjmcneill */ 3748d626ee2Sjmcneill fbi->fbi_fboffset = 0; 3758d626ee2Sjmcneill fbi->fbi_width = sc->sc_curmode->width; 376c11be502Sjmcneill fbi->fbi_height = 377c11be502Sjmcneill WIIFB_EFFECTIVE_HEIGHT(sc->sc_curmode->height); 3788d626ee2Sjmcneill fbi->fbi_stride = fbi->fbi_width * 2; 379c11be502Sjmcneill fbi->fbi_fbsize = fbi->fbi_height * fbi->fbi_stride; 3808d626ee2Sjmcneill fbi->fbi_bitsperpixel = 16; 3818d626ee2Sjmcneill fbi->fbi_pixeltype = WSFB_YUY2; 3828d626ee2Sjmcneill fbi->fbi_flags = WSFB_VRAM_IS_RAM; 3838d626ee2Sjmcneill return 0; 384d6982a45Sjmcneill 38540d8bddeSjmcneill case WSDISPLAYIO_SVIDEO: 38640d8bddeSjmcneill video = *(u_int *)data; 38740d8bddeSjmcneill switch (video) { 38840d8bddeSjmcneill case WSDISPLAYIO_VIDEO_OFF: 3899e64f9afSjmcneill out32(HW_VIDIM, __SHIFTIN(7, VIDIM_Y) | 3909e64f9afSjmcneill __SHIFTIN(7, VIDIM_C) | 3919e64f9afSjmcneill VIDIM_E); 39240d8bddeSjmcneill return 0; 39340d8bddeSjmcneill case WSDISPLAYIO_VIDEO_ON: 3949e64f9afSjmcneill out32(HW_VIDIM, 0); 39540d8bddeSjmcneill return 0; 39640d8bddeSjmcneill default: 39740d8bddeSjmcneill return EINVAL; 39840d8bddeSjmcneill } 39940d8bddeSjmcneill 400d6982a45Sjmcneill case VIIO_GETREGS: 401d6982a45Sjmcneill case VIIO_SETREGS: 402d6982a45Sjmcneill vr = data; 403d6982a45Sjmcneill switch (vr->bits) { 404d6982a45Sjmcneill case 16: 405d6982a45Sjmcneill if ((vr->reg & 1) != 0) { 406d6982a45Sjmcneill return EINVAL; 407d6982a45Sjmcneill } 408d6982a45Sjmcneill if (cmd == VIIO_GETREGS) { 409d6982a45Sjmcneill vr->val16 = RD2(sc, vr->reg); 410d6982a45Sjmcneill } else { 411d6982a45Sjmcneill WR2(sc, vr->reg, vr->val16); 412d6982a45Sjmcneill } 413d6982a45Sjmcneill return 0; 414d6982a45Sjmcneill case 32: 415d6982a45Sjmcneill if ((vr->reg & 3) != 0) { 416d6982a45Sjmcneill return EINVAL; 417d6982a45Sjmcneill } 418d6982a45Sjmcneill if (cmd == VIIO_GETREGS) { 419d6982a45Sjmcneill vr->val32 = RD4(sc, vr->reg); 420d6982a45Sjmcneill } else { 421d6982a45Sjmcneill WR4(sc, vr->reg, vr->val32); 422d6982a45Sjmcneill } 423d6982a45Sjmcneill return 0; 424d6982a45Sjmcneill default: 425d6982a45Sjmcneill return EINVAL; 426d6982a45Sjmcneill } 427d6982a45Sjmcneill return 0; 4288d626ee2Sjmcneill } 4298d626ee2Sjmcneill 4308d626ee2Sjmcneill return EPASSTHROUGH; 4318d626ee2Sjmcneill } 4328d626ee2Sjmcneill 4338d626ee2Sjmcneill static paddr_t 4348d626ee2Sjmcneill wiifb_mmap(void *v, void *vs, off_t off, int prot) 4358d626ee2Sjmcneill { 4368d626ee2Sjmcneill struct wiifb_softc *sc = v; 437c11be502Sjmcneill bus_addr_t start; 438c11be502Sjmcneill bus_size_t size; 4398d626ee2Sjmcneill 440c11be502Sjmcneill start = WIIFB_EFFECTIVE_START(XFB_START, sc->sc_curmode->width); 441c11be502Sjmcneill size = WIIFB_EFFECTIVE_HEIGHT(sc->sc_curmode->height) * 442c11be502Sjmcneill sc->sc_curmode->width * 2; 443c11be502Sjmcneill 444c11be502Sjmcneill if (off < 0 || off >= size) { 4458d626ee2Sjmcneill return -1; 4468d626ee2Sjmcneill } 4478d626ee2Sjmcneill 448c11be502Sjmcneill return bus_space_mmap(sc->sc_bst, start, off, prot, 4498d626ee2Sjmcneill BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE); 4508d626ee2Sjmcneill } 451