1 1.7 jmcneill /* $NetBSD: wiifb.c,v 1.7 2024/10/13 16:21:37 jmcneill Exp $ */ 2 1.1 jmcneill 3 1.1 jmcneill /*- 4 1.1 jmcneill * Copyright (c) 2024 Jared McNeill <jmcneill (at) invisible.ca> 5 1.1 jmcneill * All rights reserved. 6 1.1 jmcneill * 7 1.1 jmcneill * Redistribution and use in source and binary forms, with or without 8 1.1 jmcneill * modification, are permitted provided that the following conditions 9 1.1 jmcneill * are met: 10 1.1 jmcneill * 1. Redistributions of source code must retain the above copyright 11 1.1 jmcneill * notice, this list of conditions and the following disclaimer. 12 1.1 jmcneill * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 jmcneill * notice, this list of conditions and the following disclaimer in the 14 1.1 jmcneill * documentation and/or other materials provided with the distribution. 15 1.1 jmcneill * 16 1.1 jmcneill * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 1.1 jmcneill * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 1.1 jmcneill * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 1.1 jmcneill * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 1.1 jmcneill * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 1.1 jmcneill * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 1.1 jmcneill * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 1.1 jmcneill * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 1.1 jmcneill * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 1.1 jmcneill * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 1.1 jmcneill * SUCH DAMAGE. 27 1.1 jmcneill */ 28 1.1 jmcneill 29 1.1 jmcneill #include <sys/cdefs.h> 30 1.7 jmcneill __KERNEL_RCSID(0, "$NetBSD: wiifb.c,v 1.7 2024/10/13 16:21:37 jmcneill Exp $"); 31 1.1 jmcneill 32 1.1 jmcneill #include <sys/param.h> 33 1.1 jmcneill #include <sys/bus.h> 34 1.1 jmcneill #include <sys/device.h> 35 1.1 jmcneill #include <sys/systm.h> 36 1.1 jmcneill 37 1.1 jmcneill #include <machine/wii.h> 38 1.1 jmcneill 39 1.1 jmcneill #include <dev/videomode/videomode.h> 40 1.1 jmcneill #include <dev/wsfb/genfbvar.h> 41 1.1 jmcneill 42 1.1 jmcneill #include "mainbus.h" 43 1.1 jmcneill #include "vireg.h" 44 1.2 jmcneill #include "viio.h" 45 1.1 jmcneill 46 1.6 jmcneill #define WIIFB_ERROR_BLINK_INTERVAL 1000000 47 1.6 jmcneill 48 1.6 jmcneill #define WIIFB_TOP_BOTTOM_BORDER 16 49 1.6 jmcneill #define WIIFB_EFFECTIVE_START(p, w) \ 50 1.6 jmcneill ((uintptr_t)(p) + WIIFB_TOP_BOTTOM_BORDER * (w) * 2) 51 1.6 jmcneill #define WIIFB_EFFECTIVE_HEIGHT(h) \ 52 1.6 jmcneill ((h) - WIIFB_TOP_BOTTOM_BORDER * 2) 53 1.6 jmcneill 54 1.1 jmcneill 55 1.1 jmcneill struct wiifb_mode { 56 1.1 jmcneill const char * name; 57 1.1 jmcneill u_int width; 58 1.1 jmcneill u_int height; 59 1.1 jmcneill u_int lines; 60 1.1 jmcneill }; 61 1.1 jmcneill 62 1.1 jmcneill static uint32_t wiifb_devcmap[16] = { 63 1.1 jmcneill 0x00800080, /* Black */ 64 1.1 jmcneill 0x1dff1d6b, /* Blue */ 65 1.1 jmcneill 0x4b554b4a, /* Green */ 66 1.1 jmcneill 0x80808080, /* Cyan */ 67 1.1 jmcneill 0x4c544cff, /* Red */ 68 1.1 jmcneill 0x3aaa34b5, /* Magenta */ 69 1.1 jmcneill 0x7140718a, /* Brown */ 70 1.1 jmcneill 0xff80ff80, /* White */ 71 1.1 jmcneill 0x80808080, /* Gray */ 72 1.1 jmcneill 0xc399c36a, /* Bright Blue */ 73 1.1 jmcneill 0xd076d074, /* Bright Green */ 74 1.1 jmcneill 0x80808080, /* Bright Cyan */ 75 1.1 jmcneill 0x4c544cff, /* Bright Red */ 76 1.1 jmcneill 0x3aaa34b5, /* Bright Magenta */ 77 1.1 jmcneill 0xe100e194, /* Bright Yellow */ 78 1.1 jmcneill 0xff80ff80 /* Bright White */ 79 1.1 jmcneill }; 80 1.1 jmcneill 81 1.1 jmcneill #define WIIFB_MODE_INDEX(fmt, interlaced) ((fmt << 1) | interlaced) 82 1.1 jmcneill 83 1.1 jmcneill static const struct wiifb_mode wiifb_modes[] = { 84 1.1 jmcneill [WIIFB_MODE_INDEX(VI_DCR_FMT_NTSC, 0)] = { 85 1.1 jmcneill .name = "NTSC 480p", 86 1.1 jmcneill .width = 640, 87 1.1 jmcneill .height = 480, 88 1.1 jmcneill .lines = 525, 89 1.1 jmcneill }, 90 1.1 jmcneill [WIIFB_MODE_INDEX(VI_DCR_FMT_NTSC, 1)] = { 91 1.1 jmcneill .name = "NTSC 480i", 92 1.1 jmcneill .width = 640, 93 1.1 jmcneill .height = 480, 94 1.1 jmcneill .lines = 525, 95 1.1 jmcneill }, 96 1.5 hgutch [WIIFB_MODE_INDEX(VI_DCR_FMT_PAL, 1)] = { 97 1.5 hgutch .name = "PAL 576i", 98 1.5 hgutch .width = 640, 99 1.5 hgutch .height = 574, 100 1.5 hgutch .lines = 625, 101 1.5 hgutch }, 102 1.5 hgutch 103 1.1 jmcneill }; 104 1.1 jmcneill #define WIIFB_NMODES __arraycount(wiifb_modes) 105 1.1 jmcneill 106 1.1 jmcneill struct wiifb_softc { 107 1.1 jmcneill struct genfb_softc sc_gen; 108 1.1 jmcneill 109 1.1 jmcneill bus_space_tag_t sc_bst; 110 1.1 jmcneill bus_space_handle_t sc_bsh; 111 1.1 jmcneill 112 1.1 jmcneill void *sc_bits; 113 1.1 jmcneill 114 1.1 jmcneill uint8_t sc_format; 115 1.1 jmcneill bool sc_interlaced; 116 1.1 jmcneill 117 1.1 jmcneill const struct wiifb_mode *sc_curmode; 118 1.1 jmcneill }; 119 1.1 jmcneill 120 1.1 jmcneill #define RD2(sc, reg) \ 121 1.1 jmcneill bus_space_read_2((sc)->sc_bst, (sc)->sc_bsh, (reg)) 122 1.1 jmcneill #define RD4(sc, reg) \ 123 1.1 jmcneill bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) 124 1.1 jmcneill #define WR2(sc, reg, val) \ 125 1.1 jmcneill bus_space_write_2((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) 126 1.1 jmcneill #define WR4(sc, reg, val) \ 127 1.1 jmcneill bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) 128 1.1 jmcneill 129 1.1 jmcneill static int wiifb_match(device_t, cfdata_t, void *); 130 1.1 jmcneill static void wiifb_attach(device_t, device_t, void *); 131 1.1 jmcneill 132 1.1 jmcneill static void wiifb_init(struct wiifb_softc *); 133 1.1 jmcneill static void wiifb_set_mode(struct wiifb_softc *, uint8_t, bool); 134 1.1 jmcneill static void wiifb_set_fb(struct wiifb_softc *); 135 1.1 jmcneill 136 1.1 jmcneill static int wiifb_ioctl(void *, void *, u_long, void *, int, lwp_t *); 137 1.1 jmcneill static paddr_t wiifb_mmap(void *, void *, off_t, int); 138 1.1 jmcneill 139 1.1 jmcneill static struct genfb_ops wiifb_ops = { 140 1.1 jmcneill .genfb_ioctl = wiifb_ioctl, 141 1.1 jmcneill .genfb_mmap = wiifb_mmap, 142 1.1 jmcneill }; 143 1.1 jmcneill 144 1.1 jmcneill CFATTACH_DECL_NEW(wiifb, sizeof(struct wiifb_softc), 145 1.1 jmcneill wiifb_match, wiifb_attach, NULL, NULL); 146 1.1 jmcneill 147 1.1 jmcneill static int 148 1.1 jmcneill wiifb_match(device_t parent, cfdata_t cf, void *aux) 149 1.1 jmcneill { 150 1.1 jmcneill struct mainbus_attach_args *maa = aux; 151 1.1 jmcneill 152 1.1 jmcneill return strcmp(maa->maa_name, "genfb") == 0; 153 1.1 jmcneill } 154 1.1 jmcneill 155 1.1 jmcneill static void 156 1.1 jmcneill wiifb_attach(device_t parent, device_t self, void *aux) 157 1.1 jmcneill { 158 1.1 jmcneill struct wiifb_softc *sc = device_private(self); 159 1.1 jmcneill prop_dictionary_t dict = device_properties(self); 160 1.1 jmcneill struct mainbus_attach_args *maa = aux; 161 1.6 jmcneill u_int offset; 162 1.6 jmcneill uint32_t *p; 163 1.1 jmcneill int error; 164 1.1 jmcneill 165 1.1 jmcneill sc->sc_gen.sc_dev = self; 166 1.1 jmcneill sc->sc_bst = maa->maa_bst; 167 1.1 jmcneill error = bus_space_map(sc->sc_bst, maa->maa_addr, VI_SIZE, 0, 168 1.1 jmcneill &sc->sc_bsh); 169 1.1 jmcneill if (error != 0) { 170 1.1 jmcneill panic("couldn't map registers"); 171 1.1 jmcneill } 172 1.1 jmcneill sc->sc_bits = mapiodev(XFB_START, XFB_SIZE, true); 173 1.1 jmcneill 174 1.6 jmcneill /* 175 1.6 jmcneill * Paint the entire FB black. Use 4-byte accesses as the Wii will 176 1.6 jmcneill * ignore 1- and 2- byte writes to uncached memory. 177 1.6 jmcneill */ 178 1.6 jmcneill for (p = sc->sc_bits, offset = 0; 179 1.6 jmcneill offset < XFB_SIZE; 180 1.6 jmcneill offset += 4, p++) { 181 1.6 jmcneill *p = 0x00800080; 182 1.6 jmcneill } 183 1.6 jmcneill 184 1.1 jmcneill wiifb_init(sc); 185 1.1 jmcneill wiifb_set_mode(sc, sc->sc_format, sc->sc_interlaced); 186 1.1 jmcneill 187 1.1 jmcneill prop_dictionary_set_uint32(dict, "width", sc->sc_curmode->width); 188 1.6 jmcneill prop_dictionary_set_uint32(dict, "height", 189 1.6 jmcneill WIIFB_EFFECTIVE_HEIGHT(sc->sc_curmode->height)); 190 1.1 jmcneill prop_dictionary_set_uint8(dict, "depth", 16); 191 1.1 jmcneill prop_dictionary_set_uint32(dict, "address", XFB_START); 192 1.1 jmcneill prop_dictionary_set_uint32(dict, "virtual_address", 193 1.6 jmcneill WIIFB_EFFECTIVE_START(sc->sc_bits, sc->sc_curmode->width)); 194 1.1 jmcneill prop_dictionary_set_uint64(dict, "devcmap", (uintptr_t)wiifb_devcmap); 195 1.1 jmcneill 196 1.1 jmcneill genfb_init(&sc->sc_gen); 197 1.1 jmcneill 198 1.1 jmcneill aprint_naive("\n"); 199 1.1 jmcneill aprint_normal(": %s\n", sc->sc_curmode->name); 200 1.1 jmcneill 201 1.1 jmcneill genfb_cnattach(); 202 1.1 jmcneill prop_dictionary_set_bool(dict, "is_console", true); 203 1.1 jmcneill genfb_attach(&sc->sc_gen, &wiifb_ops); 204 1.1 jmcneill } 205 1.1 jmcneill 206 1.1 jmcneill static void 207 1.1 jmcneill wiifb_init(struct wiifb_softc *sc) 208 1.1 jmcneill { 209 1.1 jmcneill uint16_t dcr; 210 1.2 jmcneill uint16_t visel; 211 1.1 jmcneill 212 1.1 jmcneill /* Read current display format and interlaced settings. */ 213 1.1 jmcneill dcr = RD2(sc, VI_DCR); 214 1.2 jmcneill if ((dcr & VI_DCR_ENB) != 0) { 215 1.2 jmcneill sc->sc_format = __SHIFTOUT(dcr, VI_DCR_FMT); 216 1.2 jmcneill sc->sc_interlaced = (dcr & VI_DCR_NIN) == 0; 217 1.2 jmcneill } else { 218 1.2 jmcneill visel = RD2(sc, VI_VISEL); 219 1.2 jmcneill sc->sc_format = VI_DCR_FMT_NTSC; 220 1.2 jmcneill sc->sc_interlaced = (visel & VI_VISEL_COMPONENT_CABLE) == 0; 221 1.2 jmcneill } 222 1.1 jmcneill 223 1.1 jmcneill /* Reset video interface. */ 224 1.7 jmcneill WR2(sc, VI_DCR, VI_DCR_RST); 225 1.7 jmcneill delay(1000); 226 1.7 jmcneill 227 1.7 jmcneill /* Initialize video format and interlace selector. */ 228 1.7 jmcneill dcr = __SHIFTIN(sc->sc_format, VI_DCR_FMT) | 229 1.7 jmcneill (sc->sc_interlaced ? 0 : VI_DCR_NIN); 230 1.7 jmcneill WR2(sc, VI_DCR, dcr); 231 1.1 jmcneill } 232 1.1 jmcneill 233 1.1 jmcneill static void 234 1.1 jmcneill wiifb_set_mode(struct wiifb_softc *sc, uint8_t format, bool interlaced) 235 1.1 jmcneill { 236 1.1 jmcneill u_int modeidx; 237 1.4 jmcneill u_int strides, reads; 238 1.1 jmcneill 239 1.1 jmcneill modeidx = WIIFB_MODE_INDEX(format, interlaced); 240 1.1 jmcneill if (modeidx == WIIFB_MODE_INDEX(VI_DCR_FMT_NTSC, 1)) { 241 1.2 jmcneill /* NTSC 480i Magic numbers from YAGCD. */ 242 1.1 jmcneill WR2(sc, VI_VTR, 0x0f06); 243 1.1 jmcneill WR4(sc, VI_HTR0, 0x476901AD); 244 1.1 jmcneill WR4(sc, VI_HTR1, 0x02EA5140); 245 1.1 jmcneill WR4(sc, VI_VTO, 0x00030018); 246 1.1 jmcneill WR4(sc, VI_VTE, 0x00020019); 247 1.1 jmcneill WR4(sc, VI_BBOI, 0x410C410C); 248 1.1 jmcneill WR4(sc, VI_BBEI, 0x40ED40ED); 249 1.7 jmcneill WR2(sc, VI_DPV, 0x0000); 250 1.7 jmcneill WR2(sc, VI_DPH, 0x0000); 251 1.2 jmcneill } else if (modeidx == WIIFB_MODE_INDEX(VI_DCR_FMT_NTSC, 0)) { 252 1.2 jmcneill /* NTSC 480p */ 253 1.2 jmcneill WR2(sc, VI_VTR, 0x1e0c); 254 1.2 jmcneill WR4(sc, VI_HTR0, 0x476901ad); 255 1.2 jmcneill WR4(sc, VI_HTR1, 0x030a4940); 256 1.2 jmcneill WR4(sc, VI_VTO, 0x00060030); 257 1.2 jmcneill WR4(sc, VI_VTE, 0x00060030); 258 1.2 jmcneill WR4(sc, VI_BBOI, 0x81d881d8); 259 1.2 jmcneill WR4(sc, VI_BBEI, 0x81d881d8); 260 1.7 jmcneill WR2(sc, VI_DPV, 0x0000); 261 1.7 jmcneill WR2(sc, VI_DPH, 0x0000); 262 1.5 hgutch } else if (modeidx == WIIFB_MODE_INDEX(VI_DCR_FMT_PAL, 1)) { 263 1.5 hgutch /* PAL 576i */ 264 1.5 hgutch WR2(sc, VI_VTR, 0x11f5); 265 1.5 hgutch WR4(sc, VI_HTR0, 0x4b6a01b0); 266 1.5 hgutch WR4(sc, VI_HTR1, 0x02f85640); 267 1.5 hgutch WR4(sc, VI_VTO, 0x00010023); 268 1.5 hgutch WR4(sc, VI_VTE, 0x00000024); 269 1.5 hgutch WR4(sc, VI_BBOI, 0x4d2b4d6d); 270 1.5 hgutch WR4(sc, VI_BBEI, 0x4d8a4d4c); 271 1.7 jmcneill WR2(sc, VI_DPV, 0x013c); 272 1.7 jmcneill WR2(sc, VI_DPH, 0x0144); 273 1.1 jmcneill } else { 274 1.1 jmcneill /* 275 1.1 jmcneill * Display mode is not supported. Blink the slot LED to 276 1.1 jmcneill * indicate failure. 277 1.1 jmcneill */ 278 1.1 jmcneill wii_slot_led_blink(WIIFB_ERROR_BLINK_INTERVAL); 279 1.1 jmcneill } 280 1.1 jmcneill 281 1.6 jmcneill if (modeidx >= WIIFB_NMODES || wiifb_modes[modeidx].name == NULL) { 282 1.6 jmcneill panic("Unsupported format (0x%x) / interlaced (%d) settings", 283 1.6 jmcneill sc->sc_format, sc->sc_interlaced); 284 1.6 jmcneill } 285 1.6 jmcneill sc->sc_curmode = &wiifb_modes[modeidx]; 286 1.6 jmcneill 287 1.7 jmcneill /* Filter coefficient table, values from YAGCD. */ 288 1.7 jmcneill WR4(sc, VI_FCT0, 0x1ae771f0); 289 1.7 jmcneill WR4(sc, VI_FCT1, 0x0db4a574); 290 1.7 jmcneill WR4(sc, VI_FCT2, 0x00c1188e); 291 1.7 jmcneill WR4(sc, VI_FCT3, 0xc4c0cbe2); 292 1.7 jmcneill WR4(sc, VI_FCT4, 0xfcecdecf); 293 1.7 jmcneill WR4(sc, VI_FCT5, 0x13130f08); 294 1.7 jmcneill WR4(sc, VI_FCT6, 0x00080C0f); 295 1.7 jmcneill 296 1.7 jmcneill /* Unknown registers. */ 297 1.7 jmcneill WR4(sc, VI_UNKNOWN_68H, 0x00ff0000); 298 1.7 jmcneill WR2(sc, VI_UNKNOWN_76H, 0x00ff); 299 1.7 jmcneill WR4(sc, VI_UNKNOWN_78H, 0x00ff00ff); 300 1.7 jmcneill WR4(sc, VI_UNKNOWN_7CH, 0x00ff00ff); 301 1.7 jmcneill 302 1.1 jmcneill /* Picture configuration */ 303 1.4 jmcneill strides = (sc->sc_curmode->width * 2) / (interlaced ? 16 : 32); 304 1.4 jmcneill reads = (sc->sc_curmode->width * 2) / 32; 305 1.4 jmcneill WR2(sc, VI_PICCONF, 306 1.4 jmcneill __SHIFTIN(strides, VI_PICCONF_STRIDES) | 307 1.4 jmcneill __SHIFTIN(reads, VI_PICCONF_READS)); 308 1.1 jmcneill 309 1.2 jmcneill /* Horizontal scaler configuration */ 310 1.2 jmcneill if (interlaced) { 311 1.2 jmcneill WR2(sc, VI_HSR, __SHIFTIN(256, VI_HSR_STP)); 312 1.2 jmcneill } else { 313 1.2 jmcneill WR2(sc, VI_HSR, __SHIFTIN(244, VI_HSR_STP) | VI_HSR_HS_EN); 314 1.2 jmcneill } 315 1.1 jmcneill 316 1.1 jmcneill /* Video clock configuration */ 317 1.1 jmcneill WR2(sc, VI_VICLK, 318 1.1 jmcneill interlaced ? VI_VICLK_SEL_27MHZ : VI_VICLK_SEL_54MHZ); 319 1.1 jmcneill 320 1.1 jmcneill /* Horizontal scaling width */ 321 1.1 jmcneill WR2(sc, VI_HSCALINGW, sc->sc_curmode->width); 322 1.1 jmcneill 323 1.1 jmcneill /* Set framebuffer address */ 324 1.1 jmcneill wiifb_set_fb(sc); 325 1.7 jmcneill 326 1.7 jmcneill /* Finally, enable the framebuffer */ 327 1.7 jmcneill WR2(sc, VI_DCR, RD2(sc, VI_DCR) | VI_DCR_ENB); 328 1.1 jmcneill } 329 1.1 jmcneill 330 1.1 jmcneill static void 331 1.1 jmcneill wiifb_set_fb(struct wiifb_softc *sc) 332 1.1 jmcneill { 333 1.1 jmcneill uint32_t taddr = XFB_START; 334 1.1 jmcneill uint32_t baddr = taddr + (sc->sc_interlaced ? 335 1.1 jmcneill sc->sc_curmode->width * 2 : 0); 336 1.1 jmcneill 337 1.1 jmcneill WR4(sc, VI_TFBL, 338 1.1 jmcneill VI_TFBL_PGOFF | 339 1.1 jmcneill __SHIFTIN((taddr >> 5), VI_TFBL_FBB) | 340 1.1 jmcneill __SHIFTIN((taddr / 2) & 0xf, VI_TFBL_XOF)); 341 1.1 jmcneill WR4(sc, VI_TFBR, 0); 342 1.1 jmcneill 343 1.1 jmcneill WR4(sc, VI_BFBL, 344 1.1 jmcneill VI_BFBL_PGOFF | 345 1.1 jmcneill __SHIFTIN((baddr >> 5), VI_BFBL_FBB) | 346 1.1 jmcneill __SHIFTIN((baddr / 2) & 0xf, VI_BFBL_XOF)); 347 1.1 jmcneill WR4(sc, VI_BFBR, 0); 348 1.1 jmcneill } 349 1.1 jmcneill 350 1.1 jmcneill static int 351 1.1 jmcneill wiifb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, lwp_t *l) 352 1.1 jmcneill { 353 1.1 jmcneill struct wiifb_softc *sc = v; 354 1.1 jmcneill struct wsdisplayio_bus_id *busid; 355 1.1 jmcneill struct wsdisplayio_fbinfo *fbi; 356 1.2 jmcneill struct vi_regs *vr; 357 1.3 jmcneill u_int video; 358 1.1 jmcneill 359 1.1 jmcneill switch (cmd) { 360 1.1 jmcneill case WSDISPLAYIO_GTYPE: 361 1.1 jmcneill *(u_int *)data = WSDISPLAY_TYPE_HOLLYWOOD; 362 1.1 jmcneill return 0; 363 1.1 jmcneill case WSDISPLAYIO_GET_BUSID: 364 1.1 jmcneill busid = data; 365 1.1 jmcneill busid->bus_type = WSDISPLAYIO_BUS_SOC; 366 1.1 jmcneill return 0; 367 1.1 jmcneill case WSDISPLAYIO_GET_FBINFO: 368 1.1 jmcneill fbi = data; 369 1.1 jmcneill /* 370 1.1 jmcneill * rasops info does not match the pixel encoding due to our 371 1.1 jmcneill * devcmap, so fill out fbinfo manually instead of relying 372 1.1 jmcneill * on wsdisplayio_get_fbinfo. 373 1.1 jmcneill */ 374 1.1 jmcneill fbi->fbi_fboffset = 0; 375 1.1 jmcneill fbi->fbi_width = sc->sc_curmode->width; 376 1.6 jmcneill fbi->fbi_height = 377 1.6 jmcneill WIIFB_EFFECTIVE_HEIGHT(sc->sc_curmode->height); 378 1.1 jmcneill fbi->fbi_stride = fbi->fbi_width * 2; 379 1.6 jmcneill fbi->fbi_fbsize = fbi->fbi_height * fbi->fbi_stride; 380 1.1 jmcneill fbi->fbi_bitsperpixel = 16; 381 1.1 jmcneill fbi->fbi_pixeltype = WSFB_YUY2; 382 1.1 jmcneill fbi->fbi_flags = WSFB_VRAM_IS_RAM; 383 1.1 jmcneill return 0; 384 1.2 jmcneill 385 1.3 jmcneill case WSDISPLAYIO_SVIDEO: 386 1.3 jmcneill video = *(u_int *)data; 387 1.3 jmcneill switch (video) { 388 1.3 jmcneill case WSDISPLAYIO_VIDEO_OFF: 389 1.4 jmcneill out32(HW_VIDIM, __SHIFTIN(7, VIDIM_Y) | 390 1.4 jmcneill __SHIFTIN(7, VIDIM_C) | 391 1.4 jmcneill VIDIM_E); 392 1.3 jmcneill return 0; 393 1.3 jmcneill case WSDISPLAYIO_VIDEO_ON: 394 1.4 jmcneill out32(HW_VIDIM, 0); 395 1.3 jmcneill return 0; 396 1.3 jmcneill default: 397 1.3 jmcneill return EINVAL; 398 1.3 jmcneill } 399 1.3 jmcneill 400 1.2 jmcneill case VIIO_GETREGS: 401 1.2 jmcneill case VIIO_SETREGS: 402 1.2 jmcneill vr = data; 403 1.2 jmcneill switch (vr->bits) { 404 1.2 jmcneill case 16: 405 1.2 jmcneill if ((vr->reg & 1) != 0) { 406 1.2 jmcneill return EINVAL; 407 1.2 jmcneill } 408 1.2 jmcneill if (cmd == VIIO_GETREGS) { 409 1.2 jmcneill vr->val16 = RD2(sc, vr->reg); 410 1.2 jmcneill } else { 411 1.2 jmcneill WR2(sc, vr->reg, vr->val16); 412 1.2 jmcneill } 413 1.2 jmcneill return 0; 414 1.2 jmcneill case 32: 415 1.2 jmcneill if ((vr->reg & 3) != 0) { 416 1.2 jmcneill return EINVAL; 417 1.2 jmcneill } 418 1.2 jmcneill if (cmd == VIIO_GETREGS) { 419 1.2 jmcneill vr->val32 = RD4(sc, vr->reg); 420 1.2 jmcneill } else { 421 1.2 jmcneill WR4(sc, vr->reg, vr->val32); 422 1.2 jmcneill } 423 1.2 jmcneill return 0; 424 1.2 jmcneill default: 425 1.2 jmcneill return EINVAL; 426 1.2 jmcneill } 427 1.2 jmcneill return 0; 428 1.1 jmcneill } 429 1.1 jmcneill 430 1.1 jmcneill return EPASSTHROUGH; 431 1.1 jmcneill } 432 1.1 jmcneill 433 1.1 jmcneill static paddr_t 434 1.1 jmcneill wiifb_mmap(void *v, void *vs, off_t off, int prot) 435 1.1 jmcneill { 436 1.1 jmcneill struct wiifb_softc *sc = v; 437 1.6 jmcneill bus_addr_t start; 438 1.6 jmcneill bus_size_t size; 439 1.6 jmcneill 440 1.6 jmcneill start = WIIFB_EFFECTIVE_START(XFB_START, sc->sc_curmode->width); 441 1.6 jmcneill size = WIIFB_EFFECTIVE_HEIGHT(sc->sc_curmode->height) * 442 1.6 jmcneill sc->sc_curmode->width * 2; 443 1.1 jmcneill 444 1.6 jmcneill if (off < 0 || off >= size) { 445 1.1 jmcneill return -1; 446 1.1 jmcneill } 447 1.1 jmcneill 448 1.6 jmcneill return bus_space_mmap(sc->sc_bst, start, off, prot, 449 1.1 jmcneill BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE); 450 1.1 jmcneill } 451