1 1.68 thorpej /* $NetBSD: ffb.c,v 1.68 2023/12/20 05:33:58 thorpej Exp $ */ 2 1.1 petrov /* $OpenBSD: creator.c,v 1.20 2002/07/30 19:48:15 jason Exp $ */ 3 1.1 petrov 4 1.1 petrov /* 5 1.1 petrov * Copyright (c) 2002 Jason L. Wright (jason (at) thought.net) 6 1.1 petrov * All rights reserved. 7 1.1 petrov * 8 1.1 petrov * Redistribution and use in source and binary forms, with or without 9 1.1 petrov * modification, are permitted provided that the following conditions 10 1.1 petrov * are met: 11 1.1 petrov * 1. Redistributions of source code must retain the above copyright 12 1.1 petrov * notice, this list of conditions and the following disclaimer. 13 1.1 petrov * 2. Redistributions in binary form must reproduce the above copyright 14 1.1 petrov * notice, this list of conditions and the following disclaimer in the 15 1.1 petrov * documentation and/or other materials provided with the distribution. 16 1.1 petrov * 3. All advertising materials mentioning features or use of this software 17 1.1 petrov * must display the following acknowledgement: 18 1.1 petrov * This product includes software developed by Jason L. Wright 19 1.1 petrov * 4. The name of the author may not be used to endorse or promote products 20 1.1 petrov * derived from this software without specific prior written permission. 21 1.1 petrov * 22 1.1 petrov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 1.1 petrov * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 24 1.1 petrov * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 25 1.1 petrov * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 26 1.1 petrov * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 27 1.1 petrov * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 28 1.1 petrov * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 1.1 petrov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 30 1.1 petrov * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 31 1.1 petrov * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 1.1 petrov * POSSIBILITY OF SUCH DAMAGE. 33 1.1 petrov */ 34 1.3 lukem 35 1.3 lukem #include <sys/cdefs.h> 36 1.68 thorpej __KERNEL_RCSID(0, "$NetBSD: ffb.c,v 1.68 2023/12/20 05:33:58 thorpej Exp $"); 37 1.1 petrov 38 1.1 petrov #include <sys/types.h> 39 1.1 petrov #include <sys/param.h> 40 1.1 petrov #include <sys/systm.h> 41 1.1 petrov #include <sys/kernel.h> 42 1.1 petrov #include <sys/device.h> 43 1.1 petrov #include <sys/conf.h> 44 1.16 macallan #include <sys/ioctl.h> 45 1.16 macallan #include <sys/mman.h> 46 1.1 petrov 47 1.44 dyoung #include <sys/bus.h> 48 1.1 petrov #include <machine/autoconf.h> 49 1.1 petrov #include <machine/openfirm.h> 50 1.11 martin #include <machine/vmparam.h> 51 1.1 petrov 52 1.1 petrov #include <dev/wscons/wsconsio.h> 53 1.11 martin #include <dev/sun/fbio.h> 54 1.11 martin #include <dev/sun/fbvar.h> 55 1.1 petrov 56 1.30 martin #include <dev/wsfont/wsfont.h> 57 1.30 martin #include <dev/wscons/wsdisplay_vconsvar.h> 58 1.30 martin 59 1.48 jdc #include <prop/proplib.h> 60 1.48 jdc 61 1.39 jdc #include <dev/i2c/i2cvar.h> 62 1.39 jdc #include <dev/i2c/i2c_bitbang.h> 63 1.39 jdc #include <dev/i2c/ddcvar.h> 64 1.39 jdc 65 1.1 petrov #include <sparc64/dev/ffbreg.h> 66 1.1 petrov #include <sparc64/dev/ffbvar.h> 67 1.1 petrov 68 1.38 macallan #include "opt_wsdisplay_compat.h" 69 1.38 macallan #include "opt_ffb.h" 70 1.38 macallan 71 1.16 macallan #ifndef WS_DEFAULT_BG 72 1.16 macallan /* Sun -> background should be white */ 73 1.16 macallan #define WS_DEFAULT_BG 0xf 74 1.16 macallan #endif 75 1.16 macallan 76 1.38 macallan #ifdef FFB_SYNC 77 1.38 macallan #define SYNC ffb_ras_wait(sc) 78 1.38 macallan #else 79 1.38 macallan #define SYNC 80 1.38 macallan #endif 81 1.38 macallan 82 1.39 jdc /* Debugging */ 83 1.39 jdc #if !defined FFB_DEBUG 84 1.39 jdc #define FFB_DEBUG 0 85 1.39 jdc #endif 86 1.39 jdc #define DPRINTF(x) if (ffb_debug) printf x 87 1.39 jdc /* Patchable */ 88 1.39 jdc extern int ffb_debug; 89 1.39 jdc #if FFB_DEBUG > 0 90 1.39 jdc int ffb_debug = 1; 91 1.39 jdc #else 92 1.39 jdc int ffb_debug = 0; 93 1.39 jdc #endif 94 1.39 jdc 95 1.11 martin extern struct cfdriver ffb_cd; 96 1.11 martin 97 1.1 petrov struct wsscreen_descr ffb_stdscreen = { 98 1.6 heas "sunffb", 99 1.1 petrov 0, 0, /* will be filled in -- XXX shouldn't, it's global. */ 100 1.1 petrov 0, 101 1.1 petrov 0, 0, 102 1.61 macallan WSSCREEN_REVERSE | WSSCREEN_WSCOLORS | WSSCREEN_UNDERLINE | 103 1.61 macallan WSSCREEN_RESIZE, 104 1.31 martin NULL /* modecookie */ 105 1.1 petrov }; 106 1.1 petrov 107 1.1 petrov const struct wsscreen_descr *ffb_scrlist[] = { 108 1.1 petrov &ffb_stdscreen, 109 1.1 petrov /* XXX other formats? */ 110 1.1 petrov }; 111 1.1 petrov 112 1.1 petrov struct wsscreen_list ffb_screenlist = { 113 1.1 petrov sizeof(ffb_scrlist) / sizeof(struct wsscreen_descr *), 114 1.1 petrov ffb_scrlist 115 1.1 petrov }; 116 1.1 petrov 117 1.30 martin static struct vcons_screen ffb_console_screen; 118 1.16 macallan 119 1.32 christos int ffb_ioctl(void *, void *, u_long, void *, int, struct lwp *); 120 1.7 heas static int ffb_blank(struct ffb_softc *, u_long, u_int *); 121 1.24 jmmv paddr_t ffb_mmap(void *, void *, off_t, int); 122 1.1 petrov void ffb_ras_fifo_wait(struct ffb_softc *, int); 123 1.1 petrov void ffb_ras_wait(struct ffb_softc *); 124 1.1 petrov void ffb_ras_init(struct ffb_softc *); 125 1.1 petrov void ffb_ras_copyrows(void *, int, int, int); 126 1.1 petrov void ffb_ras_erasecols(void *, int, int, int, long int); 127 1.1 petrov void ffb_ras_eraserows(void *, int, int, long int); 128 1.1 petrov void ffb_ras_fill(struct ffb_softc *); 129 1.52 macallan void ffb_ras_invert(struct ffb_softc *); 130 1.38 macallan static void ffb_ras_setfg(struct ffb_softc *, int32_t); 131 1.38 macallan static void ffb_ras_setbg(struct ffb_softc *, int32_t); 132 1.1 petrov 133 1.16 macallan void ffb_clearscreen(struct ffb_softc *); 134 1.30 martin void ffb_init_screen(void *, struct vcons_screen *, int, 135 1.16 macallan long *); 136 1.16 macallan int ffb_allocattr(void *, int, int, int, long *); 137 1.52 macallan void ffb_putchar_mono(void *, int, int, u_int, long); 138 1.52 macallan void ffb_putchar_aa(void *, int, int, u_int, long); 139 1.16 macallan void ffb_cursor(void *, int, int, int); 140 1.16 macallan 141 1.11 martin /* frame buffer generic driver */ 142 1.43 christos static void ffbfb_unblank(device_t); 143 1.11 martin dev_type_open(ffbfb_open); 144 1.11 martin dev_type_close(ffbfb_close); 145 1.11 martin dev_type_ioctl(ffbfb_ioctl); 146 1.11 martin dev_type_mmap(ffbfb_mmap); 147 1.16 macallan 148 1.11 martin static struct fbdriver ffb_fbdriver = { 149 1.11 martin ffbfb_unblank, ffbfb_open, ffbfb_close, ffbfb_ioctl, nopoll, 150 1.11 martin ffbfb_mmap, nokqfilter 151 1.11 martin }; 152 1.11 martin 153 1.1 petrov struct wsdisplay_accessops ffb_accessops = { 154 1.30 martin .ioctl = ffb_ioctl, 155 1.30 martin .mmap = ffb_mmap, 156 1.1 petrov }; 157 1.1 petrov 158 1.39 jdc /* I2C glue */ 159 1.39 jdc static int ffb_i2c_send_start(void *, int); 160 1.39 jdc static int ffb_i2c_send_stop(void *, int); 161 1.39 jdc static int ffb_i2c_initiate_xfer(void *, i2c_addr_t, int); 162 1.39 jdc static int ffb_i2c_read_byte(void *, uint8_t *, int); 163 1.39 jdc static int ffb_i2c_write_byte(void *, uint8_t, int); 164 1.39 jdc 165 1.39 jdc /* I2C bitbang glue */ 166 1.39 jdc static void ffb_i2cbb_set_bits(void *, uint32_t); 167 1.39 jdc static void ffb_i2cbb_set_dir(void *, uint32_t); 168 1.39 jdc static uint32_t ffb_i2cbb_read(void *); 169 1.39 jdc 170 1.39 jdc static const struct i2c_bitbang_ops ffb_i2cbb_ops = { 171 1.39 jdc ffb_i2cbb_set_bits, 172 1.39 jdc ffb_i2cbb_set_dir, 173 1.39 jdc ffb_i2cbb_read, 174 1.39 jdc { 175 1.39 jdc FFB_DAC_CFG_MPDATA_SDA, 176 1.39 jdc FFB_DAC_CFG_MPDATA_SCL, 177 1.39 jdc 0, 178 1.39 jdc 0 179 1.39 jdc } 180 1.39 jdc }; 181 1.39 jdc 182 1.39 jdc void ffb_attach_i2c(struct ffb_softc *); 183 1.39 jdc 184 1.39 jdc /* Video mode setting */ 185 1.39 jdc int ffb_tgc_disable(struct ffb_softc *); 186 1.39 jdc void ffb_get_pclk(int, uint32_t *, int *); 187 1.39 jdc int ffb_set_vmode(struct ffb_softc *, struct videomode *, int, int *, int *); 188 1.39 jdc 189 1.39 jdc 190 1.1 petrov void 191 1.48 jdc ffb_attach(device_t self) 192 1.1 petrov { 193 1.48 jdc struct ffb_softc *sc = device_private(self); 194 1.1 petrov struct wsemuldisplaydev_attach_args waa; 195 1.16 macallan struct rasops_info *ri; 196 1.16 macallan long defattr; 197 1.39 jdc const char *model, *out_dev; 198 1.1 petrov int btype; 199 1.30 martin uint32_t dac; 200 1.54 martin int maxrow; 201 1.7 heas u_int blank = WSDISPLAYIO_VIDEO_ON; 202 1.4 pk char buf[6+1]; 203 1.39 jdc int i, try_edid; 204 1.48 jdc prop_data_t data; 205 1.1 petrov 206 1.1 petrov printf(":"); 207 1.38 macallan 208 1.1 petrov if (sc->sc_type == FFB_CREATOR) { 209 1.5 pk btype = prom_getpropint(sc->sc_node, "board_type", 0); 210 1.1 petrov if ((btype & 7) == 3) 211 1.1 petrov printf(" Creator3D"); 212 1.1 petrov else 213 1.1 petrov printf(" Creator"); 214 1.39 jdc } else { 215 1.1 petrov printf(" Elite3D"); 216 1.39 jdc btype = 0; 217 1.39 jdc } 218 1.1 petrov 219 1.5 pk model = prom_getpropstring(sc->sc_node, "model"); 220 1.1 petrov if (model == NULL || strlen(model) == 0) 221 1.1 petrov model = "unknown"; 222 1.1 petrov 223 1.1 petrov sc->sc_depth = 24; 224 1.1 petrov sc->sc_linebytes = 8192; 225 1.39 jdc /* We might alter these during EDID mode setting */ 226 1.5 pk sc->sc_height = prom_getpropint(sc->sc_node, "height", 0); 227 1.5 pk sc->sc_width = prom_getpropint(sc->sc_node, "width", 0); 228 1.30 martin 229 1.30 martin sc->sc_locked = 0; 230 1.30 martin sc->sc_mode = WSDISPLAYIO_MODE_EMUL; 231 1.30 martin 232 1.30 martin maxrow = (prom_getoption("screen-#rows", buf, sizeof buf) != 0) 233 1.4 pk ? strtoul(buf, NULL, 10) 234 1.4 pk : 34; 235 1.4 pk 236 1.8 heas /* collect DAC version, as Elite3D cursor enable bit is reversed */ 237 1.39 jdc DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_DEVID); 238 1.30 martin dac = DAC_READ(sc, FFB_DAC_VALUE); 239 1.30 martin sc->sc_dacrev = (dac >> 28) & 0xf; 240 1.8 heas 241 1.30 martin if (sc->sc_type == FFB_AFB) { 242 1.8 heas sc->sc_dacrev = 10; 243 1.30 martin sc->sc_needredraw = 0; 244 1.30 martin } else { 245 1.30 martin /* see what kind of DAC we have */ 246 1.30 martin int pnum = (dac & 0x0ffff000) >> 12; 247 1.30 martin if (pnum == 0x236e) { 248 1.30 martin sc->sc_needredraw = 0; 249 1.30 martin } else { 250 1.30 martin sc->sc_needredraw = 1; 251 1.30 martin } 252 1.30 martin } 253 1.8 heas printf(", model %s, dac %u\n", model, sc->sc_dacrev); 254 1.30 martin if (sc->sc_needredraw) 255 1.30 martin printf("%s: found old DAC, enabling redraw on unblank\n", 256 1.43 christos device_xname(sc->sc_dev)); 257 1.8 heas 258 1.39 jdc /* Check if a console resolution "<device>:r<res>" is set. */ 259 1.39 jdc if (sc->sc_console) { 260 1.62 jdc out_dev = prom_getpropstring(sc->sc_node, "output-device"); 261 1.39 jdc if (out_dev != NULL && strlen(out_dev) != 0 && 262 1.39 jdc strstr(out_dev, ":r") != NULL) 263 1.39 jdc try_edid = 0; 264 1.39 jdc else 265 1.39 jdc try_edid = 1; 266 1.39 jdc } else 267 1.39 jdc try_edid = 1; 268 1.39 jdc 269 1.46 macallan #if FFB_DEBUG > 0 270 1.45 macallan DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_TGC); 271 1.45 macallan printf("tgc: %08x\n", DAC_READ(sc, FFB_DAC_VALUE)); 272 1.45 macallan DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_DAC_CTRL); 273 1.45 macallan printf("dcl: %08x\n", DAC_READ(sc, FFB_DAC_VALUE)); 274 1.45 macallan #endif 275 1.39 jdc ffb_attach_i2c(sc); 276 1.39 jdc 277 1.39 jdc /* Need to set asynchronous blank during DDC write/read */ 278 1.39 jdc DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_USR_CTRL); 279 1.39 jdc dac = DAC_READ(sc, FFB_DAC_VALUE); 280 1.39 jdc DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_USR_CTRL); 281 1.39 jdc DAC_WRITE(sc, FFB_DAC_VALUE, dac | FFB_DAC_USR_CTRL_BLANK); 282 1.39 jdc 283 1.39 jdc /* Some monitors don't respond first time */ 284 1.39 jdc i = 0; 285 1.39 jdc while (sc->sc_edid_data[1] == 0 && i++ < 3) 286 1.39 jdc ddc_read_edid(&sc->sc_i2c, sc->sc_edid_data, EDID_DATA_LEN); 287 1.39 jdc 288 1.39 jdc /* Remove asynchronous blank */ 289 1.39 jdc DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_USR_CTRL); 290 1.39 jdc DAC_WRITE(sc, FFB_DAC_VALUE, dac); 291 1.39 jdc 292 1.39 jdc if (edid_parse(&sc->sc_edid_data[0], &sc->sc_edid_info) != -1) { 293 1.39 jdc sort_modes(sc->sc_edid_info.edid_modes, 294 1.39 jdc &sc->sc_edid_info.edid_preferred_mode, 295 1.39 jdc sc->sc_edid_info.edid_nmodes); 296 1.43 christos DPRINTF(("%s: EDID data:\n ", device_xname(sc->sc_dev))); 297 1.39 jdc for (i = 0; i < EDID_DATA_LEN; i++) { 298 1.39 jdc if (i && !(i % 32)) 299 1.39 jdc DPRINTF(("\n ")); 300 1.39 jdc if (i && !(i % 4)) 301 1.39 jdc DPRINTF((" ")); 302 1.39 jdc DPRINTF(("%02x", sc->sc_edid_data[i])); 303 1.39 jdc } 304 1.39 jdc DPRINTF(("\n")); 305 1.39 jdc if (ffb_debug) 306 1.39 jdc edid_print(&sc->sc_edid_info); 307 1.39 jdc 308 1.65 martin data = prop_data_create_copy(sc->sc_edid_data, EDID_DATA_LEN); 309 1.48 jdc prop_dictionary_set(device_properties(self), "EDID", data); 310 1.48 jdc prop_object_release(data); 311 1.48 jdc 312 1.39 jdc if (try_edid) 313 1.39 jdc for (i = 0; i < sc->sc_edid_info.edid_nmodes; i++) { 314 1.39 jdc if (ffb_set_vmode(sc, 315 1.39 jdc &(sc->sc_edid_info.edid_modes[i]), btype, 316 1.39 jdc &(sc->sc_width), &(sc->sc_height))) 317 1.39 jdc break; 318 1.39 jdc } 319 1.39 jdc } else { 320 1.43 christos DPRINTF(("%s: No EDID data.\n", device_xname(sc->sc_dev))); 321 1.39 jdc } 322 1.39 jdc 323 1.39 jdc ffb_ras_init(sc); 324 1.39 jdc 325 1.7 heas ffb_blank(sc, WSDISPLAYIO_SVIDEO, &blank); 326 1.7 heas 327 1.43 christos sc->sc_accel = ((device_cfdata(sc->sc_dev)->cf_flags & 328 1.23 thorpej FFB_CFFLAG_NOACCEL) == 0); 329 1.16 macallan 330 1.16 macallan wsfont_init(); 331 1.16 macallan 332 1.30 martin vcons_init(&sc->vd, sc, &ffb_stdscreen, &ffb_accessops); 333 1.30 martin sc->vd.init_screen = ffb_init_screen; 334 1.53 macallan ri = &ffb_console_screen.scr_ri; 335 1.30 martin 336 1.19 jdc /* we mess with ffb_console_screen only once */ 337 1.19 jdc if (sc->sc_console) { 338 1.61 macallan ffb_console_screen.scr_flags = VCONS_SCREEN_IS_STATIC; 339 1.30 martin vcons_init_screen(&sc->vd, &ffb_console_screen, 1, &defattr); 340 1.30 martin SCREEN_VISIBLE((&ffb_console_screen)); 341 1.30 martin /* 342 1.30 martin * XXX we shouldn't use a global variable for the console 343 1.30 martin * screen 344 1.30 martin */ 345 1.30 martin sc->vd.active = &ffb_console_screen; 346 1.30 martin } else { 347 1.30 martin if (ffb_console_screen.scr_ri.ri_rows == 0) { 348 1.30 martin /* do some minimal setup to avoid weirdnesses later */ 349 1.30 martin vcons_init_screen(&sc->vd, &ffb_console_screen, 1, &defattr); 350 1.53 macallan } else 351 1.53 macallan (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr); 352 1.19 jdc } 353 1.16 macallan 354 1.16 macallan ffb_stdscreen.nrows = ri->ri_rows; 355 1.16 macallan ffb_stdscreen.ncols = ri->ri_cols; 356 1.16 macallan ffb_stdscreen.textops = &ri->ri_ops; 357 1.16 macallan 358 1.11 martin sc->sc_fb.fb_driver = &ffb_fbdriver; 359 1.11 martin sc->sc_fb.fb_type.fb_cmsize = 0; 360 1.11 martin sc->sc_fb.fb_type.fb_size = maxrow * sc->sc_linebytes; 361 1.11 martin sc->sc_fb.fb_type.fb_type = FBTYPE_CREATOR; 362 1.12 mhitch sc->sc_fb.fb_type.fb_width = sc->sc_width; 363 1.12 mhitch sc->sc_fb.fb_type.fb_depth = sc->sc_depth; 364 1.12 mhitch sc->sc_fb.fb_type.fb_height = sc->sc_height; 365 1.43 christos sc->sc_fb.fb_device = sc->sc_dev; 366 1.11 martin fb_attach(&sc->sc_fb, sc->sc_console); 367 1.11 martin 368 1.37 macallan ffb_clearscreen(sc); 369 1.37 macallan 370 1.1 petrov if (sc->sc_console) { 371 1.16 macallan wsdisplay_cnattach(&ffb_stdscreen, ri, 0, 0, defattr); 372 1.37 macallan vcons_replay_msgbuf(&ffb_console_screen); 373 1.1 petrov } 374 1.16 macallan 375 1.1 petrov waa.console = sc->sc_console; 376 1.1 petrov waa.scrdata = &ffb_screenlist; 377 1.1 petrov waa.accessops = &ffb_accessops; 378 1.30 martin waa.accesscookie = &sc->vd; 379 1.67 thorpej config_found(sc->sc_dev, &waa, wsemuldisplaydevprint, CFARGS_NONE); 380 1.1 petrov } 381 1.1 petrov 382 1.39 jdc void 383 1.39 jdc ffb_attach_i2c(struct ffb_softc *sc) 384 1.39 jdc { 385 1.39 jdc 386 1.39 jdc /* Fill in the i2c tag */ 387 1.64 thorpej iic_tag_init(&sc->sc_i2c); 388 1.39 jdc sc->sc_i2c.ic_cookie = sc; 389 1.39 jdc sc->sc_i2c.ic_send_start = ffb_i2c_send_start; 390 1.39 jdc sc->sc_i2c.ic_send_stop = ffb_i2c_send_stop; 391 1.39 jdc sc->sc_i2c.ic_initiate_xfer = ffb_i2c_initiate_xfer; 392 1.39 jdc sc->sc_i2c.ic_read_byte = ffb_i2c_read_byte; 393 1.39 jdc sc->sc_i2c.ic_write_byte = ffb_i2c_write_byte; 394 1.39 jdc } 395 1.39 jdc 396 1.1 petrov int 397 1.32 christos ffb_ioctl(void *v, void *vs, u_long cmd, void *data, int flags, struct lwp *l) 398 1.1 petrov { 399 1.30 martin struct vcons_data *vd = v; 400 1.30 martin struct ffb_softc *sc = vd->cookie; 401 1.1 petrov struct wsdisplay_fbinfo *wdf; 402 1.30 martin struct vcons_screen *ms = vd->active; 403 1.39 jdc 404 1.39 jdc DPRINTF(("ffb_ioctl: %s cmd _IO%s%s('%c', %lu)\n", 405 1.43 christos device_xname(sc->sc_dev), 406 1.1 petrov (cmd & IOC_IN) ? "W" : "", (cmd & IOC_OUT) ? "R" : "", 407 1.39 jdc (char)IOCGROUP(cmd), cmd & 0xff)); 408 1.1 petrov 409 1.1 petrov switch (cmd) { 410 1.11 martin case FBIOGTYPE: 411 1.11 martin *(struct fbtype *)data = sc->sc_fb.fb_type; 412 1.11 martin break; 413 1.11 martin case FBIOGATTR: 414 1.11 martin #define fba ((struct fbgattr *)data) 415 1.11 martin fba->real_type = sc->sc_fb.fb_type.fb_type; 416 1.11 martin fba->owner = 0; /* XXX ??? */ 417 1.11 martin fba->fbtype = sc->sc_fb.fb_type; 418 1.11 martin fba->sattr.flags = 0; 419 1.11 martin fba->sattr.emu_type = sc->sc_fb.fb_type.fb_type; 420 1.11 martin fba->sattr.dev_specific[0] = -1; 421 1.11 martin fba->emu_types[0] = sc->sc_fb.fb_type.fb_type; 422 1.11 martin fba->emu_types[1] = -1; 423 1.11 martin #undef fba 424 1.57 msaitoh break; 425 1.11 martin 426 1.11 martin case FBIOGETCMAP: 427 1.11 martin case FBIOPUTCMAP: 428 1.11 martin return EIO; 429 1.11 martin 430 1.11 martin case FBIOGVIDEO: 431 1.11 martin case FBIOSVIDEO: 432 1.11 martin return ffb_blank(sc, cmd == FBIOGVIDEO? 433 1.11 martin WSDISPLAYIO_GVIDEO : WSDISPLAYIO_SVIDEO, 434 1.11 martin (u_int *)data); 435 1.11 martin break; 436 1.11 martin case FBIOGCURSOR: 437 1.11 martin case FBIOSCURSOR: 438 1.13 martin /* the console driver is not using the hardware cursor */ 439 1.13 martin break; 440 1.11 martin case FBIOGCURPOS: 441 1.43 christos printf("%s: FBIOGCURPOS not implemented\n", 442 1.43 christos device_xname(sc->sc_dev)); 443 1.11 martin return EIO; 444 1.11 martin case FBIOSCURPOS: 445 1.43 christos printf("%s: FBIOSCURPOS not implemented\n", 446 1.43 christos device_xname(sc->sc_dev)); 447 1.11 martin return EIO; 448 1.11 martin case FBIOGCURMAX: 449 1.43 christos printf("%s: FBIOGCURMAX not implemented\n", 450 1.43 christos device_xname(sc->sc_dev)); 451 1.11 martin return EIO; 452 1.11 martin 453 1.1 petrov case WSDISPLAYIO_GTYPE: 454 1.6 heas *(u_int *)data = WSDISPLAY_TYPE_SUNFFB; 455 1.1 petrov break; 456 1.1 petrov case WSDISPLAYIO_SMODE: 457 1.16 macallan { 458 1.16 macallan if (sc->sc_mode != *(u_int *)data) { 459 1.16 macallan sc->sc_mode = *(u_int *)data; 460 1.30 martin if ((sc->sc_mode == WSDISPLAYIO_MODE_EMUL) && 461 1.30 martin (sc->sc_locked == 0)) { 462 1.57 msaitoh ffb_ras_init(sc); 463 1.30 martin vcons_redraw_screen(ms); 464 1.58 macallan } else { 465 1.58 macallan ffb_ras_wait(sc); 466 1.16 macallan } 467 1.16 macallan } 468 1.16 macallan } 469 1.1 petrov break; 470 1.1 petrov case WSDISPLAYIO_GINFO: 471 1.1 petrov wdf = (void *)data; 472 1.1 petrov wdf->height = sc->sc_height; 473 1.1 petrov wdf->width = sc->sc_width; 474 1.1 petrov wdf->depth = 32; 475 1.1 petrov wdf->cmsize = 256; /* XXX */ 476 1.1 petrov break; 477 1.1 petrov #ifdef WSDISPLAYIO_LINEBYTES 478 1.1 petrov case WSDISPLAYIO_LINEBYTES: 479 1.1 petrov *(u_int *)data = sc->sc_linebytes; 480 1.1 petrov break; 481 1.1 petrov #endif 482 1.1 petrov case WSDISPLAYIO_GETCMAP: 483 1.1 petrov break;/* XXX */ 484 1.1 petrov 485 1.1 petrov case WSDISPLAYIO_PUTCMAP: 486 1.1 petrov break;/* XXX */ 487 1.1 petrov 488 1.1 petrov case WSDISPLAYIO_SVIDEO: 489 1.1 petrov case WSDISPLAYIO_GVIDEO: 490 1.7 heas return(ffb_blank(sc, cmd, (u_int *)data)); 491 1.7 heas break; 492 1.55 macallan 493 1.1 petrov case WSDISPLAYIO_GCURPOS: 494 1.1 petrov case WSDISPLAYIO_SCURPOS: 495 1.1 petrov case WSDISPLAYIO_GCURMAX: 496 1.1 petrov case WSDISPLAYIO_GCURSOR: 497 1.1 petrov case WSDISPLAYIO_SCURSOR: 498 1.9 martin return EIO; /* not supported yet */ 499 1.48 jdc break; 500 1.55 macallan 501 1.48 jdc case WSDISPLAYIO_GET_EDID: { 502 1.48 jdc struct wsdisplayio_edid_info *d = data; 503 1.48 jdc return wsdisplayio_get_edid(sc->sc_dev, d); 504 1.48 jdc } 505 1.55 macallan 506 1.55 macallan case WSDISPLAYIO_GET_FBINFO: { 507 1.55 macallan struct wsdisplayio_fbinfo *fbi = data; 508 1.55 macallan return wsdisplayio_get_fbinfo(&ms->scr_ri, fbi); 509 1.55 macallan } 510 1.55 macallan 511 1.1 petrov default: 512 1.9 martin return EPASSTHROUGH; 513 1.39 jdc } 514 1.1 petrov 515 1.1 petrov return (0); 516 1.1 petrov } 517 1.1 petrov 518 1.7 heas /* blank/unblank the screen */ 519 1.7 heas static int 520 1.7 heas ffb_blank(struct ffb_softc *sc, u_long cmd, u_int *data) 521 1.7 heas { 522 1.30 martin struct vcons_screen *ms = sc->vd.active; 523 1.7 heas u_int val; 524 1.30 martin 525 1.39 jdc DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_TGC); 526 1.7 heas val = DAC_READ(sc, FFB_DAC_VALUE); 527 1.7 heas 528 1.7 heas switch (cmd) { 529 1.7 heas case WSDISPLAYIO_GVIDEO: 530 1.7 heas *data = val & 1; 531 1.7 heas return(0); 532 1.7 heas break; 533 1.7 heas case WSDISPLAYIO_SVIDEO: 534 1.7 heas if (*data == WSDISPLAYIO_VIDEO_OFF) 535 1.7 heas val &= ~1; 536 1.7 heas else if (*data == WSDISPLAYIO_VIDEO_ON) 537 1.7 heas val |= 1; 538 1.7 heas else 539 1.7 heas return(EINVAL); 540 1.7 heas break; 541 1.7 heas default: 542 1.7 heas return(EINVAL); 543 1.7 heas } 544 1.7 heas 545 1.39 jdc DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_TGC); 546 1.7 heas DAC_WRITE(sc, FFB_DAC_VALUE, val); 547 1.30 martin 548 1.30 martin if ((val & 1) && sc->sc_needredraw) { 549 1.30 martin if (ms != NULL) { 550 1.30 martin if ((sc->sc_mode == WSDISPLAYIO_MODE_EMUL) && 551 1.30 martin (sc->sc_locked == 0)) { 552 1.57 msaitoh ffb_ras_init(sc); 553 1.30 martin vcons_redraw_screen(ms); 554 1.30 martin } 555 1.30 martin } 556 1.30 martin } 557 1.7 heas 558 1.7 heas return(0); 559 1.7 heas } 560 1.7 heas 561 1.1 petrov paddr_t 562 1.24 jmmv ffb_mmap(void *vsc, void *vs, off_t off, int prot) 563 1.1 petrov { 564 1.30 martin struct vcons_data *vd = vsc; 565 1.30 martin struct ffb_softc *sc = vd->cookie; 566 1.1 petrov int i; 567 1.1 petrov 568 1.1 petrov switch (sc->sc_mode) { 569 1.1 petrov case WSDISPLAYIO_MODE_MAPPED: 570 1.1 petrov for (i = 0; i < sc->sc_nreg; i++) { 571 1.1 petrov /* Before this set? */ 572 1.1 petrov if (off < sc->sc_addrs[i]) 573 1.1 petrov continue; 574 1.1 petrov /* After this set? */ 575 1.1 petrov if (off >= (sc->sc_addrs[i] + sc->sc_sizes[i])) 576 1.1 petrov continue; 577 1.1 petrov 578 1.1 petrov return (bus_space_mmap(sc->sc_bt, sc->sc_addrs[i], 579 1.1 petrov off - sc->sc_addrs[i], prot, BUS_SPACE_MAP_LINEAR)); 580 1.1 petrov } 581 1.1 petrov break; 582 1.1 petrov #ifdef WSDISPLAYIO_MODE_DUMBFB 583 1.1 petrov case WSDISPLAYIO_MODE_DUMBFB: 584 1.1 petrov if (sc->sc_nreg < FFB_REG_DFB24) 585 1.1 petrov break; 586 1.1 petrov if (off >= 0 && off < sc->sc_sizes[FFB_REG_DFB24]) 587 1.1 petrov return (bus_space_mmap(sc->sc_bt, 588 1.1 petrov sc->sc_addrs[FFB_REG_DFB24], off, prot, 589 1.58 macallan BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE)); 590 1.1 petrov break; 591 1.1 petrov #endif 592 1.1 petrov } 593 1.1 petrov return (-1); 594 1.1 petrov } 595 1.1 petrov 596 1.1 petrov void 597 1.10 martin ffb_ras_fifo_wait(struct ffb_softc *sc, int n) 598 1.1 petrov { 599 1.1 petrov int32_t cache = sc->sc_fifo_cache; 600 1.1 petrov 601 1.1 petrov if (cache < n) { 602 1.1 petrov do { 603 1.1 petrov cache = FBC_READ(sc, FFB_FBC_UCSR); 604 1.1 petrov cache = (cache & FBC_UCSR_FIFO_MASK) - 8; 605 1.1 petrov } while (cache < n); 606 1.1 petrov } 607 1.1 petrov sc->sc_fifo_cache = cache - n; 608 1.1 petrov } 609 1.1 petrov 610 1.1 petrov void 611 1.10 martin ffb_ras_wait(struct ffb_softc *sc) 612 1.1 petrov { 613 1.22 cdi uint32_t ucsr, r; 614 1.1 petrov 615 1.1 petrov while (1) { 616 1.1 petrov ucsr = FBC_READ(sc, FFB_FBC_UCSR); 617 1.1 petrov if ((ucsr & (FBC_UCSR_FB_BUSY|FBC_UCSR_RP_BUSY)) == 0) 618 1.1 petrov break; 619 1.1 petrov r = ucsr & (FBC_UCSR_READ_ERR | FBC_UCSR_FIFO_OVFL); 620 1.1 petrov if (r != 0) 621 1.1 petrov FBC_WRITE(sc, FFB_FBC_UCSR, r); 622 1.1 petrov } 623 1.1 petrov } 624 1.1 petrov 625 1.1 petrov void 626 1.10 martin ffb_ras_init(struct ffb_softc *sc) 627 1.1 petrov { 628 1.39 jdc uint32_t fbc; 629 1.39 jdc 630 1.39 jdc if (sc->sc_width > 1280) { 631 1.39 jdc DPRINTF(("ffb_ras_init: high resolution.\n")); 632 1.45 macallan fbc = FFB_FBC_WM_COMBINED | FFB_FBC_WE_FORCEON | 633 1.39 jdc FFB_FBC_ZE_OFF | FFB_FBC_YE_OFF | FFB_FBC_XE_ON; 634 1.39 jdc } else { 635 1.39 jdc DPRINTF(("ffb_ras_init: standard resolution.\n")); 636 1.39 jdc fbc = FFB_FBC_XE_OFF; 637 1.39 jdc } 638 1.56 macallan ffb_ras_fifo_wait(sc, 7); 639 1.45 macallan DPRINTF(("WID: %08x\n", FBC_READ(sc, FFB_FBC_WID))); 640 1.45 macallan FBC_WRITE(sc, FFB_FBC_WID, 0x0); 641 1.1 petrov FBC_WRITE(sc, FFB_FBC_PPC, 642 1.38 macallan FBC_PPC_VCE_DIS | FBC_PPC_TBE_OPAQUE | FBC_PPC_ACE_DIS | 643 1.45 macallan FBC_PPC_APE_DIS | FBC_PPC_DCE_DIS | FBC_PPC_CS_CONST | 644 1.49 macallan FBC_PPC_ABE_DIS | FBC_PPC_XS_WID); 645 1.45 macallan 646 1.45 macallan fbc |= FFB_FBC_WB_A | FFB_FBC_RB_A | FFB_FBC_SB_BOTH | 647 1.45 macallan FFB_FBC_RGBE_MASK; 648 1.45 macallan DPRINTF(("%s: fbc is %08x\n", __func__, fbc)); 649 1.45 macallan FBC_WRITE(sc, FFB_FBC_FBC, fbc); 650 1.1 petrov FBC_WRITE(sc, FFB_FBC_ROP, FBC_ROP_NEW); 651 1.1 petrov FBC_WRITE(sc, FFB_FBC_DRAWOP, FBC_DRAWOP_RECTANGLE); 652 1.1 petrov FBC_WRITE(sc, FFB_FBC_PMASK, 0xffffffff); 653 1.1 petrov FBC_WRITE(sc, FFB_FBC_FONTINC, 0x10000); 654 1.56 macallan ffb_ras_fifo_wait(sc, 5); 655 1.1 petrov sc->sc_fg_cache = 0; 656 1.1 petrov FBC_WRITE(sc, FFB_FBC_FG, sc->sc_fg_cache); 657 1.56 macallan sc->sc_bg_cache = 0; 658 1.56 macallan FBC_WRITE(sc, FFB_FBC_BG, sc->sc_bg_cache); 659 1.49 macallan FBC_WRITE(sc, FFB_FBC_BLENDC, FFB_BLENDC_FORCE_ONE | 660 1.49 macallan FFB_BLENDC_DF_ONE_M_A | 661 1.49 macallan FFB_BLENDC_SF_A); 662 1.49 macallan FBC_WRITE(sc, FFB_FBC_BLENDC1, 0); 663 1.49 macallan FBC_WRITE(sc, FFB_FBC_BLENDC2, 0); 664 1.1 petrov ffb_ras_wait(sc); 665 1.1 petrov } 666 1.1 petrov 667 1.1 petrov void 668 1.10 martin ffb_ras_eraserows(void *cookie, int row, int n, long attr) 669 1.1 petrov { 670 1.1 petrov struct rasops_info *ri = cookie; 671 1.30 martin struct vcons_screen *scr = ri->ri_hw; 672 1.30 martin struct ffb_softc *sc = scr->scr_cookie; 673 1.1 petrov 674 1.30 martin if (row < 0) { 675 1.30 martin n += row; 676 1.30 martin row = 0; 677 1.30 martin } 678 1.30 martin if (row + n > ri->ri_rows) 679 1.30 martin n = ri->ri_rows - row; 680 1.30 martin if (n <= 0) 681 1.30 martin return; 682 1.16 macallan 683 1.30 martin ffb_ras_fill(sc); 684 1.30 martin ffb_ras_setfg(sc, ri->ri_devcmap[(attr >> 16) & 0xf]); 685 1.30 martin ffb_ras_fifo_wait(sc, 4); 686 1.30 martin if ((n == ri->ri_rows) && (ri->ri_flg & RI_FULLCLEAR)) { 687 1.30 martin FBC_WRITE(sc, FFB_FBC_BY, 0); 688 1.30 martin FBC_WRITE(sc, FFB_FBC_BX, 0); 689 1.30 martin FBC_WRITE(sc, FFB_FBC_BH, ri->ri_height); 690 1.30 martin FBC_WRITE(sc, FFB_FBC_BW, ri->ri_width); 691 1.59 macallan ri->ri_flg &= ~RI_CURSOR; 692 1.30 martin } else { 693 1.30 martin row *= ri->ri_font->fontheight; 694 1.30 martin FBC_WRITE(sc, FFB_FBC_BY, ri->ri_yorigin + row); 695 1.30 martin FBC_WRITE(sc, FFB_FBC_BX, ri->ri_xorigin); 696 1.30 martin FBC_WRITE(sc, FFB_FBC_BH, n * ri->ri_font->fontheight); 697 1.30 martin FBC_WRITE(sc, FFB_FBC_BW, ri->ri_emuwidth); 698 1.1 petrov } 699 1.38 macallan SYNC; 700 1.1 petrov } 701 1.1 petrov 702 1.1 petrov void 703 1.10 martin ffb_ras_erasecols(void *cookie, int row, int col, int n, long attr) 704 1.1 petrov { 705 1.1 petrov struct rasops_info *ri = cookie; 706 1.30 martin struct vcons_screen *scr = ri->ri_hw; 707 1.30 martin struct ffb_softc *sc = scr->scr_cookie; 708 1.30 martin 709 1.30 martin if ((row < 0) || (row >= ri->ri_rows)) 710 1.30 martin return; 711 1.30 martin if (col < 0) { 712 1.30 martin n += col; 713 1.30 martin col = 0; 714 1.30 martin } 715 1.30 martin if (col + n > ri->ri_cols) 716 1.30 martin n = ri->ri_cols - col; 717 1.30 martin if (n <= 0) 718 1.30 martin return; 719 1.59 macallan 720 1.30 martin n *= ri->ri_font->fontwidth; 721 1.30 martin col *= ri->ri_font->fontwidth; 722 1.30 martin row *= ri->ri_font->fontheight; 723 1.1 petrov 724 1.30 martin ffb_ras_fill(sc); 725 1.30 martin ffb_ras_setfg(sc, ri->ri_devcmap[(attr >> 16) & 0xf]); 726 1.30 martin ffb_ras_fifo_wait(sc, 4); 727 1.30 martin FBC_WRITE(sc, FFB_FBC_BY, ri->ri_yorigin + row); 728 1.30 martin FBC_WRITE(sc, FFB_FBC_BX, ri->ri_xorigin + col); 729 1.30 martin FBC_WRITE(sc, FFB_FBC_BH, ri->ri_font->fontheight); 730 1.56 macallan FBC_WRITE(sc, FFB_FBC_BW, n); 731 1.38 macallan SYNC; 732 1.1 petrov } 733 1.1 petrov 734 1.1 petrov void 735 1.10 martin ffb_ras_fill(struct ffb_softc *sc) 736 1.1 petrov { 737 1.49 macallan ffb_ras_fifo_wait(sc, 3); 738 1.49 macallan FBC_WRITE(sc, FFB_FBC_PPC, 739 1.49 macallan FBC_PPC_VCE_DIS | FBC_PPC_TBE_OPAQUE | FBC_PPC_ACE_DIS | 740 1.49 macallan FBC_PPC_APE_DIS | FBC_PPC_DCE_DIS | FBC_PPC_CS_CONST | 741 1.49 macallan FBC_PPC_ABE_DIS | FBC_PPC_XS_WID); 742 1.1 petrov FBC_WRITE(sc, FFB_FBC_ROP, FBC_ROP_NEW); 743 1.1 petrov FBC_WRITE(sc, FFB_FBC_DRAWOP, FBC_DRAWOP_RECTANGLE); 744 1.38 macallan SYNC; 745 1.1 petrov } 746 1.1 petrov 747 1.1 petrov void 748 1.52 macallan ffb_ras_invert(struct ffb_softc *sc) 749 1.52 macallan { 750 1.52 macallan ffb_ras_fifo_wait(sc, 3); 751 1.52 macallan FBC_WRITE(sc, FFB_FBC_PPC, 752 1.52 macallan FBC_PPC_VCE_DIS | FBC_PPC_TBE_OPAQUE | FBC_PPC_ACE_DIS | 753 1.52 macallan FBC_PPC_APE_DIS | FBC_PPC_DCE_DIS | FBC_PPC_CS_CONST | 754 1.52 macallan FBC_PPC_ABE_DIS | FBC_PPC_XS_WID); 755 1.52 macallan FBC_WRITE(sc, FFB_FBC_ROP, FBC_ROP_INVERT); 756 1.52 macallan FBC_WRITE(sc, FFB_FBC_DRAWOP, FBC_DRAWOP_RECTANGLE); 757 1.52 macallan SYNC; 758 1.52 macallan } 759 1.52 macallan 760 1.52 macallan void 761 1.10 martin ffb_ras_copyrows(void *cookie, int src, int dst, int n) 762 1.1 petrov { 763 1.1 petrov struct rasops_info *ri = cookie; 764 1.30 martin struct vcons_screen *scr = ri->ri_hw; 765 1.30 martin struct ffb_softc *sc = scr->scr_cookie; 766 1.1 petrov 767 1.30 martin if (dst == src) 768 1.30 martin return; 769 1.30 martin if (src < 0) { 770 1.30 martin n += src; 771 1.30 martin src = 0; 772 1.30 martin } 773 1.30 martin if ((src + n) > ri->ri_rows) 774 1.30 martin n = ri->ri_rows - src; 775 1.30 martin if (dst < 0) { 776 1.30 martin n += dst; 777 1.30 martin dst = 0; 778 1.30 martin } 779 1.30 martin if ((dst + n) > ri->ri_rows) 780 1.30 martin n = ri->ri_rows - dst; 781 1.30 martin if (n <= 0) 782 1.30 martin return; 783 1.30 martin n *= ri->ri_font->fontheight; 784 1.30 martin src *= ri->ri_font->fontheight; 785 1.30 martin dst *= ri->ri_font->fontheight; 786 1.30 martin 787 1.49 macallan ffb_ras_fifo_wait(sc, 9); 788 1.49 macallan FBC_WRITE(sc, FFB_FBC_PPC, 789 1.49 macallan FBC_PPC_VCE_DIS | FBC_PPC_TBE_OPAQUE | FBC_PPC_ACE_DIS | 790 1.49 macallan FBC_PPC_APE_DIS | FBC_PPC_DCE_DIS | FBC_PPC_CS_CONST | 791 1.49 macallan FBC_PPC_ABE_DIS | FBC_PPC_XS_WID); 792 1.30 martin FBC_WRITE(sc, FFB_FBC_ROP, FBC_ROP_OLD | (FBC_ROP_OLD << 8)); 793 1.30 martin FBC_WRITE(sc, FFB_FBC_DRAWOP, FBC_DRAWOP_VSCROLL); 794 1.30 martin FBC_WRITE(sc, FFB_FBC_BY, ri->ri_yorigin + src); 795 1.30 martin FBC_WRITE(sc, FFB_FBC_BX, ri->ri_xorigin); 796 1.30 martin FBC_WRITE(sc, FFB_FBC_DY, ri->ri_yorigin + dst); 797 1.30 martin FBC_WRITE(sc, FFB_FBC_DX, ri->ri_xorigin); 798 1.30 martin FBC_WRITE(sc, FFB_FBC_BH, n); 799 1.30 martin FBC_WRITE(sc, FFB_FBC_BW, ri->ri_emuwidth); 800 1.38 macallan SYNC; 801 1.1 petrov } 802 1.1 petrov 803 1.38 macallan static void 804 1.10 martin ffb_ras_setfg(struct ffb_softc *sc, int32_t fg) 805 1.1 petrov { 806 1.1 petrov ffb_ras_fifo_wait(sc, 1); 807 1.1 petrov if (fg == sc->sc_fg_cache) 808 1.1 petrov return; 809 1.1 petrov sc->sc_fg_cache = fg; 810 1.1 petrov FBC_WRITE(sc, FFB_FBC_FG, fg); 811 1.38 macallan SYNC; 812 1.38 macallan } 813 1.38 macallan 814 1.38 macallan static void 815 1.38 macallan ffb_ras_setbg(struct ffb_softc *sc, int32_t bg) 816 1.38 macallan { 817 1.38 macallan ffb_ras_fifo_wait(sc, 1); 818 1.38 macallan if (bg == sc->sc_bg_cache) 819 1.38 macallan return; 820 1.38 macallan sc->sc_bg_cache = bg; 821 1.38 macallan FBC_WRITE(sc, FFB_FBC_BG, bg); 822 1.38 macallan SYNC; 823 1.1 petrov } 824 1.11 martin 825 1.11 martin /* frame buffer generic driver support functions */ 826 1.11 martin static void 827 1.43 christos ffbfb_unblank(device_t dev) 828 1.11 martin { 829 1.35 martin struct ffb_softc *sc = device_private(dev); 830 1.30 martin struct vcons_screen *ms = sc->vd.active; 831 1.29 martin u_int on = 1; 832 1.30 martin int redraw = 0; 833 1.30 martin 834 1.30 martin ffb_ras_init(sc); 835 1.30 martin if (sc->sc_locked) { 836 1.30 martin sc->sc_locked = 0; 837 1.30 martin redraw = 1; 838 1.30 martin } 839 1.30 martin 840 1.36 macallan ffb_blank(sc, WSDISPLAYIO_SVIDEO, &on); 841 1.36 macallan #if 0 842 1.30 martin if ((sc->vd.active != &ffb_console_screen) && 843 1.30 martin (ffb_console_screen.scr_flags & VCONS_SCREEN_IS_STATIC)) { 844 1.30 martin /* 845 1.30 martin * force-switch to the console screen. 846 1.30 martin * Caveat: the higher layer will think we're still on the 847 1.30 martin * other screen 848 1.30 martin */ 849 1.30 martin 850 1.30 martin SCREEN_INVISIBLE(sc->vd.active); 851 1.30 martin sc->vd.active = &ffb_console_screen; 852 1.30 martin SCREEN_VISIBLE(sc->vd.active); 853 1.30 martin ms = sc->vd.active; 854 1.30 martin redraw = 1; 855 1.30 martin } 856 1.36 macallan #endif 857 1.30 martin if (redraw) { 858 1.30 martin vcons_redraw_screen(ms); 859 1.30 martin } 860 1.11 martin } 861 1.11 martin 862 1.11 martin int 863 1.21 christos ffbfb_open(dev_t dev, int flags, int mode, struct lwp *l) 864 1.11 martin { 865 1.30 martin struct ffb_softc *sc; 866 1.11 martin 867 1.34 cegger sc = device_lookup_private(&ffb_cd, minor(dev)); 868 1.34 cegger if (sc == NULL) 869 1.11 martin return ENXIO; 870 1.30 martin 871 1.30 martin sc->sc_locked = 1; 872 1.11 martin return 0; 873 1.11 martin } 874 1.11 martin 875 1.11 martin int 876 1.21 christos ffbfb_close(dev_t dev, int flags, int mode, struct lwp *l) 877 1.11 martin { 878 1.34 cegger struct ffb_softc *sc = device_lookup_private(&ffb_cd, minor(dev)); 879 1.30 martin struct vcons_screen *ms = sc->vd.active; 880 1.30 martin 881 1.30 martin sc->sc_locked = 0; 882 1.30 martin if (ms != NULL) { 883 1.30 martin if ((sc->sc_mode == WSDISPLAYIO_MODE_EMUL) && 884 1.30 martin (sc->sc_locked == 0)) { 885 1.57 msaitoh ffb_ras_init(sc); 886 1.30 martin vcons_redraw_screen(ms); 887 1.30 martin } 888 1.30 martin } 889 1.11 martin return 0; 890 1.11 martin } 891 1.11 martin 892 1.11 martin int 893 1.32 christos ffbfb_ioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l) 894 1.11 martin { 895 1.34 cegger struct ffb_softc *sc = device_lookup_private(&ffb_cd, minor(dev)); 896 1.11 martin 897 1.30 martin return ffb_ioctl(&sc->vd, NULL, cmd, data, flags, l); 898 1.11 martin } 899 1.11 martin 900 1.11 martin paddr_t 901 1.11 martin ffbfb_mmap(dev_t dev, off_t off, int prot) 902 1.11 martin { 903 1.34 cegger struct ffb_softc *sc = device_lookup_private(&ffb_cd, minor(dev)); 904 1.14 macallan uint64_t size; 905 1.11 martin int i, reg; 906 1.11 martin off_t o; 907 1.11 martin 908 1.11 martin /* 909 1.11 martin * off is a magic cookie (see xfree86/drivers/sunffb/ffb.h), 910 1.11 martin * which we map to an index into the "reg" property, and use 911 1.11 martin * our copy of the firmware data as arguments for the real 912 1.11 martin * mapping. 913 1.11 martin */ 914 1.58 macallan static struct { unsigned long voff; int reg; long flags; } map[] = { 915 1.58 macallan { 0x00000000, FFB_REG_SFB8R, BUS_SPACE_MAP_PREFETCHABLE }, 916 1.58 macallan { 0x00400000, FFB_REG_SFB8G, BUS_SPACE_MAP_PREFETCHABLE }, 917 1.58 macallan { 0x00800000, FFB_REG_SFB8B, BUS_SPACE_MAP_PREFETCHABLE }, 918 1.58 macallan { 0x00c00000, FFB_REG_SFB8X, BUS_SPACE_MAP_PREFETCHABLE }, 919 1.58 macallan { 0x01000000, FFB_REG_SFB32, BUS_SPACE_MAP_PREFETCHABLE }, 920 1.58 macallan { 0x02000000, FFB_REG_SFB64, BUS_SPACE_MAP_PREFETCHABLE }, 921 1.58 macallan { 0x04000000, FFB_REG_FBC, 0 }, 922 1.58 macallan { 0x04004000, FFB_REG_DFB8R, BUS_SPACE_MAP_PREFETCHABLE }, 923 1.58 macallan { 0x04404000, FFB_REG_DFB8G, BUS_SPACE_MAP_PREFETCHABLE }, 924 1.58 macallan { 0x04804000, FFB_REG_DFB8B, BUS_SPACE_MAP_PREFETCHABLE }, 925 1.58 macallan { 0x04c04000, FFB_REG_DFB8X, BUS_SPACE_MAP_PREFETCHABLE }, 926 1.58 macallan { 0x05004000, FFB_REG_DFB24, BUS_SPACE_MAP_PREFETCHABLE }, 927 1.58 macallan { 0x06004000, FFB_REG_DFB32, BUS_SPACE_MAP_PREFETCHABLE }, 928 1.58 macallan { 0x07004000, FFB_REG_DFB422A, BUS_SPACE_MAP_PREFETCHABLE }, 929 1.58 macallan { 0x0bc06000, FFB_REG_DAC, 0 }, 930 1.58 macallan { 0x0bc08000, FFB_REG_PROM, 0 }, 931 1.58 macallan { 0x0bc18000, 0, 0 } 932 1.11 martin }; 933 1.11 martin 934 1.11 martin /* special value "FFB_EXP_VOFF" - not backed by any "reg" entry */ 935 1.11 martin if (off == 0x0bc18000) 936 1.11 martin return bus_space_mmap(sc->sc_bt, sc->sc_addrs[FFB_REG_PROM], 937 1.11 martin 0x00200000, prot, BUS_SPACE_MAP_LINEAR); 938 1.14 macallan 939 1.14 macallan /* 940 1.14 macallan * FFB_VOFF_FBC_KREGS - used by afbinit to upload firmware. We should 941 1.14 macallan * probably mmap them only on afb boards 942 1.14 macallan */ 943 1.14 macallan if ((off >= 0x0bc04000) && (off < 0x0bc06000)) 944 1.14 macallan return bus_space_mmap(sc->sc_bt, sc->sc_addrs[FFB_REG_PROM], 945 1.14 macallan 0x00610000 + (off - 0x0bc04000), prot, 946 1.14 macallan BUS_SPACE_MAP_LINEAR); 947 1.14 macallan 948 1.11 martin #define NELEMS(arr) (sizeof(arr)/sizeof((arr)[0])) 949 1.11 martin 950 1.11 martin /* the map is ordered by voff */ 951 1.14 macallan for (i = 0; i < NELEMS(map)-1; i++) { 952 1.11 martin reg = map[i].reg; 953 1.16 macallan /* the number of entries in reg seems to vary */ 954 1.14 macallan if (reg < sc->sc_nreg) { 955 1.63 riastrad size = uimin((map[i + 1].voff - map[i].voff), 956 1.14 macallan sc->sc_sizes[reg]); 957 1.14 macallan if ((off >= map[i].voff) && 958 1.14 macallan (off < (map[i].voff + size))) { 959 1.14 macallan o = off - map[i].voff; 960 1.14 macallan return bus_space_mmap(sc->sc_bt, 961 1.14 macallan sc->sc_addrs[reg], o, prot, 962 1.58 macallan BUS_SPACE_MAP_LINEAR | map[i].flags); 963 1.14 macallan } 964 1.14 macallan } 965 1.11 martin } 966 1.11 martin 967 1.11 martin return -1; 968 1.11 martin } 969 1.16 macallan 970 1.16 macallan void 971 1.16 macallan ffb_clearscreen(struct ffb_softc *sc) 972 1.16 macallan { 973 1.30 martin struct rasops_info *ri = &ffb_console_screen.scr_ri; 974 1.16 macallan ffb_ras_fill(sc); 975 1.16 macallan ffb_ras_setfg(sc, ri->ri_devcmap[WS_DEFAULT_BG]); 976 1.16 macallan ffb_ras_fifo_wait(sc, 4); 977 1.16 macallan FBC_WRITE(sc, FFB_FBC_BY, 0); 978 1.16 macallan FBC_WRITE(sc, FFB_FBC_BX, 0); 979 1.30 martin FBC_WRITE(sc, FFB_FBC_BH, sc->sc_height); 980 1.30 martin FBC_WRITE(sc, FFB_FBC_BW, sc->sc_width); 981 1.16 macallan } 982 1.16 macallan 983 1.16 macallan void 984 1.16 macallan ffb_cursor(void *cookie, int on, int row, int col) 985 1.16 macallan { 986 1.16 macallan struct rasops_info *ri = cookie; 987 1.30 martin struct vcons_screen *scr; 988 1.30 martin struct ffb_softc *sc; 989 1.52 macallan int x, y, wi, he; 990 1.16 macallan 991 1.30 martin if (cookie != NULL) { 992 1.30 martin scr = ri->ri_hw; 993 1.30 martin sc = scr->scr_cookie; 994 1.30 martin 995 1.30 martin wi = ri->ri_font->fontwidth; 996 1.30 martin he = ri->ri_font->fontheight; 997 1.30 martin 998 1.30 martin if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) { 999 1.30 martin 1000 1.30 martin if (ri->ri_flg & RI_CURSOR) { 1001 1.52 macallan 1002 1.30 martin /* remove cursor */ 1003 1.52 macallan x = ri->ri_ccol * wi + ri->ri_xorigin; 1004 1.52 macallan y = ri->ri_crow * he + ri->ri_yorigin; 1005 1.52 macallan 1006 1.52 macallan ffb_ras_invert(sc); 1007 1.52 macallan ffb_ras_fifo_wait(sc, 4); 1008 1.52 macallan FBC_WRITE(sc, FFB_FBC_BY, y); 1009 1.52 macallan FBC_WRITE(sc, FFB_FBC_BX, x); 1010 1.52 macallan FBC_WRITE(sc, FFB_FBC_BH, he); 1011 1.52 macallan FBC_WRITE(sc, FFB_FBC_BW, wi); 1012 1.52 macallan 1013 1.30 martin ri->ri_flg &= ~RI_CURSOR; 1014 1.30 martin } 1015 1.30 martin ri->ri_crow = row; 1016 1.30 martin ri->ri_ccol = col; 1017 1.30 martin if (on) 1018 1.30 martin { 1019 1.30 martin x = ri->ri_ccol * wi + ri->ri_xorigin; 1020 1.30 martin y = ri->ri_crow * he + ri->ri_yorigin; 1021 1.52 macallan 1022 1.52 macallan ffb_ras_invert(sc); 1023 1.52 macallan ffb_ras_fifo_wait(sc, 4); 1024 1.52 macallan FBC_WRITE(sc, FFB_FBC_BY, y); 1025 1.52 macallan FBC_WRITE(sc, FFB_FBC_BX, x); 1026 1.52 macallan FBC_WRITE(sc, FFB_FBC_BH, he); 1027 1.52 macallan FBC_WRITE(sc, FFB_FBC_BW, wi); 1028 1.52 macallan 1029 1.30 martin ri->ri_flg |= RI_CURSOR; 1030 1.30 martin } 1031 1.30 martin } else { 1032 1.30 martin ri->ri_crow = row; 1033 1.30 martin ri->ri_ccol = col; 1034 1.30 martin ri->ri_flg &= ~RI_CURSOR; 1035 1.16 macallan } 1036 1.16 macallan } 1037 1.16 macallan } 1038 1.16 macallan 1039 1.52 macallan /* mono bitmap font */ 1040 1.16 macallan void 1041 1.52 macallan ffb_putchar_mono(void *cookie, int row, int col, u_int c, long attr) 1042 1.16 macallan { 1043 1.16 macallan struct rasops_info *ri = cookie; 1044 1.30 martin struct vcons_screen *scr = ri->ri_hw; 1045 1.38 macallan struct wsdisplay_font *font = PICK_FONT(ri, c); 1046 1.30 martin struct ffb_softc *sc = scr->scr_cookie; 1047 1.49 macallan void *data; 1048 1.49 macallan uint32_t fg, bg; 1049 1.52 macallan int i; 1050 1.49 macallan int x, y, wi, he; 1051 1.16 macallan 1052 1.49 macallan if (sc->sc_mode != WSDISPLAYIO_MODE_EMUL) 1053 1.49 macallan return; 1054 1.49 macallan 1055 1.49 macallan wi = font->fontwidth; 1056 1.49 macallan he = font->fontheight; 1057 1.49 macallan 1058 1.49 macallan if (!CHAR_IN_FONT(c, font)) 1059 1.49 macallan return; 1060 1.49 macallan 1061 1.49 macallan bg = ri->ri_devcmap[(attr >> 16) & 0xf]; 1062 1.49 macallan fg = ri->ri_devcmap[(attr >> 24) & 0xf]; 1063 1.49 macallan x = ri->ri_xorigin + col * wi; 1064 1.49 macallan y = ri->ri_yorigin + row * he; 1065 1.38 macallan 1066 1.52 macallan data = WSFONT_GLYPH(c, font); 1067 1.52 macallan 1068 1.52 macallan ffb_ras_setbg(sc, bg); 1069 1.52 macallan ffb_ras_setfg(sc, fg); 1070 1.52 macallan ffb_ras_fifo_wait(sc, 4); 1071 1.52 macallan FBC_WRITE(sc, FFB_FBC_ROP, FBC_ROP_NEW); 1072 1.52 macallan FBC_WRITE(sc, FFB_FBC_FONTXY, (y << 16) | x); 1073 1.52 macallan FBC_WRITE(sc, FFB_FBC_FONTW, wi); 1074 1.52 macallan FBC_WRITE(sc, FFB_FBC_PPC, 1075 1.52 macallan FBC_PPC_VCE_DIS | FBC_PPC_TBE_OPAQUE | FBC_PPC_ACE_DIS | 1076 1.52 macallan FBC_PPC_APE_DIS | FBC_PPC_DCE_DIS | FBC_PPC_CS_CONST | 1077 1.52 macallan FBC_PPC_ABE_DIS | FBC_PPC_XS_WID); 1078 1.38 macallan 1079 1.52 macallan switch (font->stride) { 1080 1.52 macallan case 1: { 1081 1.52 macallan uint8_t *data8 = data; 1082 1.52 macallan uint32_t reg; 1083 1.60 macallan if (attr & WSATTR_UNDERLINE) { 1084 1.60 macallan for (i = 0; i < he - 2; i++) { 1085 1.60 macallan reg = *data8; 1086 1.60 macallan FBC_WRITE(sc, FFB_FBC_FONT, reg << 24); 1087 1.60 macallan data8++; 1088 1.60 macallan } 1089 1.60 macallan FBC_WRITE(sc, FFB_FBC_FONT, 0xff000000); 1090 1.60 macallan data8++; 1091 1.52 macallan reg = *data8; 1092 1.52 macallan FBC_WRITE(sc, FFB_FBC_FONT, reg << 24); 1093 1.60 macallan } else { 1094 1.60 macallan for (i = 0; i < he; i++) { 1095 1.60 macallan reg = *data8; 1096 1.60 macallan FBC_WRITE(sc, FFB_FBC_FONT, reg << 24); 1097 1.60 macallan data8++; 1098 1.60 macallan } 1099 1.38 macallan } 1100 1.52 macallan break; 1101 1.52 macallan } 1102 1.52 macallan case 2: { 1103 1.52 macallan uint16_t *data16 = data; 1104 1.52 macallan uint32_t reg; 1105 1.60 macallan if (attr & WSATTR_UNDERLINE) { 1106 1.60 macallan for (i = 0; i < he - 2; i++) { 1107 1.60 macallan reg = *data16; 1108 1.60 macallan FBC_WRITE(sc, FFB_FBC_FONT, reg << 16); 1109 1.60 macallan data16++; 1110 1.60 macallan } 1111 1.60 macallan FBC_WRITE(sc, FFB_FBC_FONT, 0xffff0000); 1112 1.60 macallan data16++; 1113 1.52 macallan reg = *data16; 1114 1.52 macallan FBC_WRITE(sc, FFB_FBC_FONT, reg << 16); 1115 1.60 macallan } else { 1116 1.60 macallan for (i = 0; i < he; i++) { 1117 1.60 macallan reg = *data16; 1118 1.60 macallan FBC_WRITE(sc, FFB_FBC_FONT, reg << 16); 1119 1.60 macallan data16++; 1120 1.60 macallan } 1121 1.38 macallan } 1122 1.52 macallan break; 1123 1.38 macallan } 1124 1.52 macallan } 1125 1.52 macallan } 1126 1.52 macallan 1127 1.52 macallan /* alpha font */ 1128 1.52 macallan void 1129 1.52 macallan ffb_putchar_aa(void *cookie, int row, int col, u_int c, long attr) 1130 1.52 macallan { 1131 1.52 macallan struct rasops_info *ri = cookie; 1132 1.52 macallan struct vcons_screen *scr = ri->ri_hw; 1133 1.52 macallan struct wsdisplay_font *font = PICK_FONT(ri, c); 1134 1.52 macallan struct ffb_softc *sc = scr->scr_cookie; 1135 1.52 macallan volatile uint32_t *dest, *ddest; 1136 1.52 macallan uint8_t *data8; 1137 1.52 macallan uint32_t fg, bg; 1138 1.52 macallan int i; 1139 1.52 macallan int x, y, wi, he; 1140 1.52 macallan uint32_t alpha = 0x80; 1141 1.52 macallan int j; 1142 1.52 macallan 1143 1.52 macallan if (sc->sc_mode != WSDISPLAYIO_MODE_EMUL) 1144 1.52 macallan return; 1145 1.52 macallan 1146 1.52 macallan wi = font->fontwidth; 1147 1.52 macallan he = font->fontheight; 1148 1.52 macallan 1149 1.52 macallan if (!CHAR_IN_FONT(c, font)) 1150 1.52 macallan return; 1151 1.52 macallan 1152 1.52 macallan bg = ri->ri_devcmap[(attr >> 16) & 0xf]; 1153 1.52 macallan fg = ri->ri_devcmap[(attr >> 24) & 0xf]; 1154 1.52 macallan x = ri->ri_xorigin + col * wi; 1155 1.52 macallan y = ri->ri_yorigin + row * he; 1156 1.52 macallan 1157 1.52 macallan data8 = WSFONT_GLYPH(c, font); 1158 1.52 macallan 1159 1.52 macallan /* first we erase the background */ 1160 1.52 macallan ffb_ras_fill(sc); 1161 1.52 macallan ffb_ras_setfg(sc, bg); 1162 1.52 macallan ffb_ras_fifo_wait(sc, 4); 1163 1.52 macallan FBC_WRITE(sc, FFB_FBC_BY, y); 1164 1.52 macallan FBC_WRITE(sc, FFB_FBC_BX, x); 1165 1.52 macallan FBC_WRITE(sc, FFB_FBC_BH, he); 1166 1.52 macallan FBC_WRITE(sc, FFB_FBC_BW, wi); 1167 1.52 macallan 1168 1.52 macallan /* if we draw a space we're done */ 1169 1.60 macallan if (c == ' ') goto out; 1170 1.52 macallan 1171 1.52 macallan /* now enable alpha blending */ 1172 1.52 macallan ffb_ras_setfg(sc, fg); 1173 1.52 macallan ffb_ras_fifo_wait(sc, 2); 1174 1.52 macallan FBC_WRITE(sc, FFB_FBC_ROP, FBC_ROP_NEW); 1175 1.52 macallan 1176 1.52 macallan FBC_WRITE(sc, FFB_FBC_PPC, 1177 1.52 macallan FBC_PPC_VCE_DIS | FBC_PPC_TBE_OPAQUE | FBC_PPC_ACE_DIS | 1178 1.52 macallan FBC_PPC_APE_DIS | FBC_PPC_DCE_DIS | FBC_PPC_CS_CONST | 1179 1.52 macallan FBC_PPC_ABE_ENA | FBC_PPC_XS_VAR); 1180 1.52 macallan /* 1181 1.52 macallan * we have to wait for both the rectangle drawing op above and the 1182 1.52 macallan * FFB_FBC_PPC write to finish before mucking around in the SFB aperture 1183 1.52 macallan */ 1184 1.52 macallan ffb_ras_wait(sc); 1185 1.49 macallan 1186 1.52 macallan /* ... and draw the character */ 1187 1.52 macallan dest = sc->sc_sfb32 + (y << 11) + x; 1188 1.52 macallan for (i = 0; i < he; i++) { 1189 1.52 macallan ddest = dest; 1190 1.52 macallan for (j = 0; j < wi; j++) { 1191 1.52 macallan alpha = *data8; 1192 1.52 macallan /* 1193 1.52 macallan * We set the colour source to constant above so we only 1194 1.52 macallan * have to write the alpha channel here and the colour 1195 1.52 macallan * comes from the FG register. It would be nice if we 1196 1.52 macallan * could just use the SFB8X aperture and memcpy() the 1197 1.52 macallan * alpha map line by line but for some strange reason 1198 1.52 macallan * that will take colour info from the framebuffer even 1199 1.52 macallan * if we set the FBC_PPC_CS_CONST bit above. 1200 1.52 macallan */ 1201 1.52 macallan *ddest = alpha << 24; 1202 1.52 macallan data8++; 1203 1.52 macallan ddest++; 1204 1.49 macallan } 1205 1.52 macallan dest += 2048; 1206 1.60 macallan } 1207 1.60 macallan out: 1208 1.60 macallan /* check if we need to draw an underline */ 1209 1.60 macallan if (attr & WSATTR_UNDERLINE) { 1210 1.60 macallan dest = sc->sc_sfb32 + ((y + he - 2) << 11) + x; 1211 1.60 macallan for (i = 0; i < wi; i++) { 1212 1.60 macallan *dest = 0xa0000000; 1213 1.60 macallan dest++; 1214 1.60 macallan } 1215 1.60 macallan } 1216 1.16 macallan } 1217 1.16 macallan 1218 1.16 macallan int 1219 1.16 macallan ffb_allocattr(void *cookie, int fg, int bg, int flags, long *attrp) 1220 1.16 macallan { 1221 1.16 macallan if ((fg == 0) && (bg == 0)) 1222 1.16 macallan { 1223 1.16 macallan fg = WS_DEFAULT_FG; 1224 1.16 macallan bg = WS_DEFAULT_BG; 1225 1.16 macallan } 1226 1.16 macallan if (flags & WSATTR_REVERSE) { 1227 1.60 macallan *attrp = (bg & 0xff) << 24 | (fg & 0xff) << 16; 1228 1.16 macallan } else 1229 1.60 macallan *attrp = (fg & 0xff) << 24 | (bg & 0xff) << 16; 1230 1.60 macallan if (flags & WSATTR_UNDERLINE) 1231 1.60 macallan *attrp |= WSATTR_UNDERLINE; 1232 1.16 macallan return 0; 1233 1.16 macallan } 1234 1.16 macallan 1235 1.16 macallan void 1236 1.30 martin ffb_init_screen(void *cookie, struct vcons_screen *scr, 1237 1.16 macallan int existing, long *defattr) 1238 1.16 macallan { 1239 1.30 martin struct ffb_softc *sc = cookie; 1240 1.30 martin struct rasops_info *ri = &scr->scr_ri; 1241 1.16 macallan 1242 1.16 macallan ri->ri_depth = 32; 1243 1.16 macallan ri->ri_width = sc->sc_width; 1244 1.16 macallan ri->ri_height = sc->sc_height; 1245 1.16 macallan ri->ri_stride = sc->sc_linebytes; 1246 1.60 macallan ri->ri_flg = RI_CENTER | RI_ENABLE_ALPHA | RI_PREFER_ALPHA; 1247 1.16 macallan 1248 1.38 macallan /* 1249 1.38 macallan * we can't accelerate copycols() so instead of falling back to 1250 1.38 macallan * software use vcons' putchar() based implementation 1251 1.38 macallan */ 1252 1.61 macallan scr->scr_flags |= VCONS_NO_COPYCOLS | VCONS_LOADFONT; 1253 1.61 macallan 1254 1.45 macallan #ifdef VCONS_DRAW_INTR 1255 1.45 macallan scr->scr_flags |= VCONS_DONT_READ; 1256 1.45 macallan #endif 1257 1.39 jdc DPRINTF(("ffb_init_screen: addr: %08lx\n",(ulong)ri->ri_bits)); 1258 1.39 jdc 1259 1.51 macallan /* explicitly request BGR in case the default changes */ 1260 1.51 macallan ri->ri_rnum = 8; 1261 1.51 macallan ri->ri_gnum = 8; 1262 1.51 macallan ri->ri_bnum = 8; 1263 1.51 macallan ri->ri_rpos = 0; 1264 1.51 macallan ri->ri_gpos = 8; 1265 1.51 macallan ri->ri_bpos = 16; 1266 1.51 macallan 1267 1.50 macallan rasops_init(ri, 0, 0); 1268 1.16 macallan rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight, 1269 1.16 macallan sc->sc_width / ri->ri_font->fontwidth); 1270 1.61 macallan ri->ri_caps = WSSCREEN_WSCOLORS | WSSCREEN_UNDERLINE | 1271 1.61 macallan WSSCREEN_REVERSE | WSSCREEN_RESIZE; 1272 1.16 macallan 1273 1.16 macallan /* enable acceleration */ 1274 1.16 macallan ri->ri_ops.copyrows = ffb_ras_copyrows; 1275 1.16 macallan ri->ri_ops.eraserows = ffb_ras_eraserows; 1276 1.16 macallan ri->ri_ops.erasecols = ffb_ras_erasecols; 1277 1.16 macallan ri->ri_ops.cursor = ffb_cursor; 1278 1.16 macallan ri->ri_ops.allocattr = ffb_allocattr; 1279 1.52 macallan if (FONT_IS_ALPHA(ri->ri_font)) { 1280 1.52 macallan ri->ri_ops.putchar = ffb_putchar_aa; 1281 1.52 macallan } else 1282 1.52 macallan ri->ri_ops.putchar = ffb_putchar_mono; 1283 1.16 macallan } 1284 1.39 jdc 1285 1.39 jdc /* I2C bitbanging */ 1286 1.39 jdc static void ffb_i2cbb_set_bits(void *cookie, uint32_t bits) 1287 1.39 jdc { 1288 1.39 jdc struct ffb_softc *sc = cookie; 1289 1.39 jdc 1290 1.39 jdc DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_CFG_MPDATA); 1291 1.39 jdc DAC_WRITE(sc, FFB_DAC_VALUE, bits); 1292 1.39 jdc } 1293 1.39 jdc 1294 1.39 jdc static void ffb_i2cbb_set_dir(void *cookie, uint32_t dir) 1295 1.39 jdc { 1296 1.39 jdc /* Nothing to do */ 1297 1.39 jdc } 1298 1.39 jdc 1299 1.39 jdc static uint32_t ffb_i2cbb_read(void *cookie) 1300 1.39 jdc { 1301 1.39 jdc struct ffb_softc *sc = cookie; 1302 1.39 jdc uint32_t bits; 1303 1.39 jdc 1304 1.39 jdc DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_CFG_MPSENSE); 1305 1.39 jdc bits = DAC_READ(sc, FFB_DAC_VALUE); 1306 1.39 jdc 1307 1.39 jdc return bits; 1308 1.39 jdc } 1309 1.39 jdc 1310 1.39 jdc /* higher level I2C stuff */ 1311 1.39 jdc static int 1312 1.39 jdc ffb_i2c_send_start(void *cookie, int flags) 1313 1.39 jdc { 1314 1.39 jdc return (i2c_bitbang_send_start(cookie, flags, &ffb_i2cbb_ops)); 1315 1.39 jdc } 1316 1.39 jdc 1317 1.39 jdc static int 1318 1.39 jdc ffb_i2c_send_stop(void *cookie, int flags) 1319 1.39 jdc { 1320 1.39 jdc 1321 1.39 jdc return (i2c_bitbang_send_stop(cookie, flags, &ffb_i2cbb_ops)); 1322 1.39 jdc } 1323 1.39 jdc 1324 1.39 jdc static int 1325 1.39 jdc ffb_i2c_initiate_xfer(void *cookie, i2c_addr_t addr, int flags) 1326 1.39 jdc { 1327 1.39 jdc /* 1328 1.39 jdc * for some reason i2c_bitbang_initiate_xfer left-shifts 1329 1.39 jdc * the I2C-address and then sets the direction bit 1330 1.39 jdc */ 1331 1.39 jdc return (i2c_bitbang_initiate_xfer(cookie, addr, flags, 1332 1.39 jdc &ffb_i2cbb_ops)); 1333 1.39 jdc } 1334 1.39 jdc 1335 1.39 jdc static int 1336 1.39 jdc ffb_i2c_read_byte(void *cookie, uint8_t *valp, int flags) 1337 1.39 jdc { 1338 1.39 jdc return (i2c_bitbang_read_byte(cookie, valp, flags, &ffb_i2cbb_ops)); 1339 1.39 jdc } 1340 1.39 jdc 1341 1.39 jdc static int 1342 1.39 jdc ffb_i2c_write_byte(void *cookie, uint8_t val, int flags) 1343 1.39 jdc { 1344 1.39 jdc return (i2c_bitbang_write_byte(cookie, val, flags, &ffb_i2cbb_ops)); 1345 1.39 jdc } 1346 1.39 jdc 1347 1.39 jdc 1348 1.39 jdc #define TVC_READ_LIMIT 100000 1349 1.39 jdc int 1350 1.39 jdc ffb_tgc_disable(struct ffb_softc *sc) 1351 1.39 jdc { 1352 1.39 jdc int i; 1353 1.39 jdc 1354 1.39 jdc /* Is the timing generator disabled? */ 1355 1.39 jdc DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_TGC); 1356 1.39 jdc if (!(DAC_READ(sc, FFB_DAC_VALUE) & FFB_DAC_TGC_TIMING_ENABLE)) 1357 1.39 jdc return 1; 1358 1.39 jdc 1359 1.39 jdc /* If not, disable it when the vertical counter reaches 0 */ 1360 1.39 jdc for (i = 0; i < TVC_READ_LIMIT; i++) { 1361 1.39 jdc DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_TVC); 1362 1.39 jdc if (!DAC_READ(sc, FFB_DAC_VALUE)) { 1363 1.39 jdc DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_TGC); 1364 1.39 jdc DAC_WRITE(sc, FFB_DAC_VALUE, 0); 1365 1.39 jdc return 1; 1366 1.39 jdc } 1367 1.39 jdc } 1368 1.39 jdc return 0; 1369 1.39 jdc } 1370 1.39 jdc 1371 1.39 jdc /* 1372 1.39 jdc * PLL Control Register values: 1373 1.39 jdc * M)ultiplier = bits 0:6 + 1 1374 1.39 jdc * D)ivisor = bits 7:10 + 1 1375 1.39 jdc * P)ost divisor = bits 11:13 (000 = 1, 001 = 2, 010 = 4, 011 = 8) 1376 1.39 jdc * Frequency = 13.5 * M / D / P 1377 1.39 jdc */ 1378 1.39 jdc #define FFB_PLL_FREQ 13500000 1379 1.39 jdc void 1380 1.39 jdc ffb_get_pclk(int request, uint32_t *pll, int *diff) 1381 1.39 jdc { 1382 1.39 jdc int m, d, p, f, hex = 0, curdiff; 1383 1.39 jdc 1384 1.39 jdc *diff = 100000000; 1385 1.39 jdc 1386 1.39 jdc for (m = 32; m <= 80; m++) { 1387 1.39 jdc for (d = 4; d <= 11; d++) { 1388 1.39 jdc for (p = 1; p <= 8; p = p << 1) { 1389 1.39 jdc switch (p) { 1390 1.39 jdc case 1: 1391 1.39 jdc hex = 0x4000 + (d << 7) + m; 1392 1.39 jdc break; 1393 1.39 jdc case 2: 1394 1.39 jdc hex = 0x4800 + (d << 7) + m; 1395 1.39 jdc break; 1396 1.39 jdc case 4: 1397 1.39 jdc hex = 0x5000 + (d << 7) + m; 1398 1.39 jdc break; 1399 1.39 jdc case 8: 1400 1.39 jdc hex = 0x6000 + (d << 7) + m; 1401 1.39 jdc break; 1402 1.39 jdc } 1403 1.39 jdc f = 13500000 * m / d / p; 1404 1.39 jdc if (f == request) { 1405 1.39 jdc *diff = 0; 1406 1.39 jdc *pll = hex; 1407 1.39 jdc return; 1408 1.39 jdc } else { 1409 1.39 jdc curdiff = abs(request - f); 1410 1.39 jdc if (curdiff < *diff) { 1411 1.39 jdc *diff = curdiff; 1412 1.39 jdc *pll = hex; 1413 1.39 jdc } 1414 1.39 jdc } 1415 1.39 jdc } 1416 1.39 jdc } 1417 1.39 jdc } 1418 1.39 jdc } 1419 1.39 jdc 1420 1.39 jdc /* 1421 1.39 jdc * Details of the FFB RAMDAC are contained in the Brooktree BT497/498 1422 1.39 jdc * and in the Connexant BT497A/498A documentation. 1423 1.39 jdc * 1424 1.39 jdc * VESA timings to FFB register conversion: 1425 1.39 jdc * If interleave = 4/2:1 then x = 2, if interleave = 8/2:1 then x = 4 1426 1.39 jdc * VBE = VBS - vres = (sync pulse - 1) + back porch 1427 1.39 jdc * VBS = VSS - front porch = (sync pulse - 1) + back porch + vres 1428 1.39 jdc * VSE = sync pulse - 1 1429 1.39 jdc * VSS = (sync pulse - 1) + back porch + vres + front porch 1430 1.39 jdc * HRE = HSS - HSE - 1 1431 1.39 jdc * HBE = (sync pulse + back porch) / x - 1 1432 1.39 jdc * HBS = (sync pulse + back porch + hres) / x - 1 1433 1.39 jdc * HSE = sync pulse / x - 1 1434 1.39 jdc * HSS = (sync pulse + back porch + hres + front porch) / x - 1 1435 1.39 jdc * HCE = HBS - 4 1436 1.39 jdc * HCS = HBE - 4 1437 1.39 jdc * EPE = EIE = EIS = 0 (for all non-interlaced modes) 1438 1.39 jdc * 1439 1.39 jdc * Note, that 8/2:1 Single Buffered Interleaving is only supported by the 1440 1.39 jdc * double-buffered FFB (Creator3D), and at higher resolutions than 1280x1024 1441 1.39 jdc * 1442 1.39 jdc * Note, that the timing generator should be disabled and re-enabled when the 1443 1.39 jdc * the timing parameter registers are being programmed. Stopping the timing 1444 1.39 jdc * generator should only be done when the vertical counter is zero. 1445 1.39 jdc */ 1446 1.39 jdc #define DIVIDE(x,y) (((x) + ((y) / 2)) / (y)) 1447 1.39 jdc int 1448 1.39 jdc ffb_set_vmode(struct ffb_softc *sc, struct videomode *mode, int btype, 1449 1.39 jdc int *hres, int *vres) 1450 1.39 jdc { 1451 1.39 jdc int diff; 1452 1.39 jdc uint32_t fp, sp, bp, x; 1453 1.39 jdc uint32_t pll, pfc, ucl, dcl, tgc; 1454 1.39 jdc uint32_t vbe, vbs, vse, vss, hre, hbe, hbs, hse, hss, hce, hcs; 1455 1.39 jdc uint32_t epe, eie, eis; 1456 1.39 jdc uint32_t fbcfg0; 1457 1.39 jdc 1458 1.39 jdc DPRINTF(("ffb_set_vmode: %dx%d@%d", mode->hdisplay, mode->vdisplay, 1459 1.39 jdc DIVIDE(DIVIDE(mode->dot_clock * 1000, 1460 1.39 jdc mode->htotal), mode->vtotal))); 1461 1.39 jdc DPRINTF((" (%d %d %d %d %d %d %d", 1462 1.39 jdc mode->dot_clock, mode->hsync_start, mode->hsync_end, mode->htotal, 1463 1.39 jdc mode->vsync_start, mode->vsync_end, mode->vtotal)); 1464 1.39 jdc DPRINTF((" %s%sH %s%sV)\n", 1465 1.39 jdc mode->flags & VID_PHSYNC ? "+" : "", 1466 1.39 jdc mode->flags & VID_NHSYNC ? "-" : "", 1467 1.39 jdc mode->flags & VID_PVSYNC ? "+" : "", 1468 1.39 jdc mode->flags & VID_NVSYNC ? "-" : "")); 1469 1.39 jdc 1470 1.39 jdc /* We don't handle interlaced or doublescan (yet) */ 1471 1.39 jdc if ((mode->flags & VID_INTERLACE) || (mode->flags & VID_DBLSCAN)) 1472 1.39 jdc return 0; 1473 1.39 jdc 1474 1.39 jdc /* Only Creator3D can be set to > 1280x1024 */ 1475 1.39 jdc if(((sc->sc_type == FFB_CREATOR && !((btype & 7) == 3)) || 1476 1.39 jdc sc->sc_type == FFB_AFB) 1477 1.39 jdc && (mode->hdisplay > 1280 || mode->vdisplay > 1024)) 1478 1.39 jdc return 0; 1479 1.39 jdc /* Creator3D can be set to <= 1920x1360 */ 1480 1.39 jdc if (mode->hdisplay > 1920 || mode->vdisplay > 1360) 1481 1.39 jdc return 0; 1482 1.39 jdc 1483 1.39 jdc /* 1484 1.39 jdc * Look for a matching pixel clock and set PLL Control. 1485 1.39 jdc * XXX: 640x480@60 is 25175000 in modelines but 25125000 in the 1486 1.39 jdc * FFB PROM, and the closest match to 25175000 (0x4da9/25159090) 1487 1.39 jdc * does not work. So, use the PROM value instead. 1488 1.39 jdc */ 1489 1.39 jdc if (mode->hdisplay == 640 && mode->vdisplay == 480 && 1490 1.39 jdc mode->dot_clock == 25175) { 1491 1.39 jdc DPRINTF(("ffb_set_vmode: 640x480@60: adjusted dot clock\n")); 1492 1.39 jdc mode->dot_clock = 25125; 1493 1.39 jdc } 1494 1.39 jdc ffb_get_pclk(mode->dot_clock * 1000, &pll, &diff); 1495 1.39 jdc if (diff > 250000) 1496 1.39 jdc return 0; 1497 1.39 jdc 1498 1.39 jdc /* Pixel Format Control, User Control and FBC Configuration. */ 1499 1.39 jdc if (mode->hdisplay > 1280) { 1500 1.39 jdc pfc = FFB_DAC_PIX_FMT_821; 1501 1.39 jdc ucl = FFB_DAC_USR_CTRL_OVERLAY | FFB_DAC_USR_CTRL_WMODE_C; 1502 1.39 jdc x = 4; 1503 1.39 jdc fbcfg0 = FBC_READ(sc, FFB_FBC_FBCFG0) | FBC_CFG0_DOUBLE_BUF; 1504 1.39 jdc } else { 1505 1.39 jdc pfc = FFB_DAC_PIX_FMT_421; 1506 1.39 jdc /* Only Creator3D and Elite3D can have double-buffer */ 1507 1.39 jdc if ((sc->sc_type == FFB_CREATOR && !((btype & 7) == 3))) 1508 1.39 jdc ucl = 0; 1509 1.39 jdc else 1510 1.39 jdc ucl = FFB_DAC_USR_CTRL_DOUBLE; 1511 1.39 jdc ucl |= (FFB_DAC_USR_CTRL_OVERLAY | FFB_DAC_USR_CTRL_WMODE_S8); 1512 1.39 jdc x = 2; 1513 1.39 jdc fbcfg0 = FBC_READ(sc, FFB_FBC_FBCFG0) | FBC_CFG0_SINGLE_BUF; 1514 1.39 jdc } 1515 1.39 jdc 1516 1.39 jdc /* DAC Control and Timing Generator Control */ 1517 1.47 jdc if (mode->flags & VID_PVSYNC) 1518 1.47 jdc dcl = FFB_DAC_DAC_CTRL_POS_VSYNC; 1519 1.47 jdc else 1520 1.39 jdc dcl = 0; 1521 1.47 jdc tgc = 0; 1522 1.39 jdc #define EDID_VID_INP sc->sc_edid_info.edid_video_input 1523 1.47 jdc if ((EDID_VID_INP & EDID_VIDEO_INPUT_COMPOSITE_SYNC)) { 1524 1.47 jdc dcl |= FFB_DAC_DAC_CTRL_VSYNC_DIS; 1525 1.47 jdc tgc = FFB_DAC_TGC_EQUAL_DISABLE; 1526 1.47 jdc } else { 1527 1.39 jdc dcl |= FFB_DAC_DAC_CTRL_SYNC_G; 1528 1.41 jdc if (EDID_VID_INP & EDID_VIDEO_INPUT_SEPARATE_SYNCS) 1529 1.41 jdc tgc |= FFB_DAC_TGC_VSYNC_DISABLE; 1530 1.47 jdc else 1531 1.47 jdc tgc = FFB_DAC_TGC_EQUAL_DISABLE; 1532 1.39 jdc } 1533 1.39 jdc if (EDID_VID_INP & EDID_VIDEO_INPUT_BLANK_TO_BLACK) 1534 1.39 jdc dcl |= FFB_DAC_DAC_CTRL_PED_ENABLE; 1535 1.39 jdc tgc |= (FFB_DAC_TGC_VIDEO_ENABLE | FFB_DAC_TGC_TIMING_ENABLE | 1536 1.39 jdc FFB_DAC_TGC_MASTER_ENABLE); 1537 1.39 jdc 1538 1.39 jdc /* Vertical timing */ 1539 1.39 jdc fp = mode->vsync_start - mode->vdisplay; 1540 1.39 jdc sp = mode->vsync_end - mode->vsync_start; 1541 1.39 jdc bp = mode->vtotal - mode->vsync_end; 1542 1.39 jdc 1543 1.39 jdc vbe = sp - 1 + bp; 1544 1.39 jdc vbs = sp - 1 + bp + mode->vdisplay; 1545 1.39 jdc vse = sp - 1; 1546 1.39 jdc vss = sp - 1 + bp + mode->vdisplay + fp; 1547 1.39 jdc 1548 1.39 jdc /* Horizontal timing */ 1549 1.39 jdc fp = mode->hsync_start - mode->hdisplay; 1550 1.39 jdc sp = mode->hsync_end - mode->hsync_start; 1551 1.39 jdc bp = mode->htotal - mode->hsync_end; 1552 1.39 jdc 1553 1.39 jdc hbe = (sp + bp) / x - 1; 1554 1.39 jdc hbs = (sp + bp + mode->hdisplay) / x - 1; 1555 1.39 jdc hse = sp / x - 1; 1556 1.39 jdc hss = (sp + bp + mode->hdisplay + fp) / x -1; 1557 1.39 jdc hre = hss - hse - 1; 1558 1.39 jdc hce = hbs - 4; 1559 1.39 jdc hcs = hbe - 4; 1560 1.39 jdc 1561 1.39 jdc /* Equalisation (interlaced modes) */ 1562 1.39 jdc epe = 0; 1563 1.39 jdc eie = 0; 1564 1.39 jdc eis = 0; 1565 1.39 jdc 1566 1.39 jdc DPRINTF(("ffb_set_vmode: 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x\n", 1567 1.39 jdc pll, pfc, ucl, dcl, tgc)); 1568 1.39 jdc DPRINTF(("\t0x%04x 0x%04x 0x%04x 0x%04x\n", vbe, vbs, vse, vss)); 1569 1.39 jdc DPRINTF(("\t0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x\n", 1570 1.39 jdc hre, hbe, hbs, hse, hss, hce, hcs)); 1571 1.39 jdc DPRINTF(("\t0x%04x 0x%04x 0x%04x\n", epe, eie, eis)); 1572 1.39 jdc 1573 1.39 jdc if (!ffb_tgc_disable(sc)) { 1574 1.39 jdc DPRINTF(("ffb_set_vmode: failed to disable TGC register\n")); 1575 1.39 jdc return 0; 1576 1.39 jdc } 1577 1.39 jdc 1578 1.39 jdc /* 1579 1.39 jdc * Program the mode registers. 1580 1.39 jdc * Program the timing generator last, as that re-enables output. 1581 1.39 jdc * Note, that a read to/write from a register increments the 1582 1.39 jdc * register address to the next register automatically. 1583 1.39 jdc */ 1584 1.39 jdc DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_PLL_CTRL); 1585 1.39 jdc DAC_WRITE(sc, FFB_DAC_VALUE, pll); 1586 1.39 jdc DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_PIX_FMT); 1587 1.39 jdc DAC_WRITE(sc, FFB_DAC_VALUE, pfc); 1588 1.39 jdc DAC_WRITE(sc, FFB_DAC_VALUE, ucl); 1589 1.39 jdc DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_DAC_CTRL); 1590 1.39 jdc DAC_WRITE(sc, FFB_DAC_VALUE, dcl); 1591 1.39 jdc 1592 1.39 jdc DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_VBE); 1593 1.39 jdc DAC_WRITE(sc, FFB_DAC_VALUE, vbe); 1594 1.39 jdc DAC_WRITE(sc, FFB_DAC_VALUE, vbs); 1595 1.39 jdc DAC_WRITE(sc, FFB_DAC_VALUE, vse); 1596 1.39 jdc DAC_WRITE(sc, FFB_DAC_VALUE, vss); 1597 1.39 jdc 1598 1.39 jdc DAC_WRITE(sc, FFB_DAC_VALUE, hre); 1599 1.39 jdc DAC_WRITE(sc, FFB_DAC_VALUE, hbe); 1600 1.39 jdc DAC_WRITE(sc, FFB_DAC_VALUE, hbs); 1601 1.39 jdc DAC_WRITE(sc, FFB_DAC_VALUE, hse); 1602 1.39 jdc DAC_WRITE(sc, FFB_DAC_VALUE, hss); 1603 1.39 jdc DAC_WRITE(sc, FFB_DAC_VALUE, hce); 1604 1.39 jdc DAC_WRITE(sc, FFB_DAC_VALUE, hcs); 1605 1.39 jdc 1606 1.39 jdc DAC_WRITE(sc, FFB_DAC_VALUE, epe); 1607 1.39 jdc DAC_WRITE(sc, FFB_DAC_VALUE, eie); 1608 1.39 jdc DAC_WRITE(sc, FFB_DAC_VALUE, eis); 1609 1.39 jdc 1610 1.39 jdc FBC_WRITE(sc, FFB_FBC_FBCFG0, fbcfg0); 1611 1.39 jdc 1612 1.39 jdc DAC_WRITE(sc, FFB_DAC_TYPE, FFB_DAC_TGC); 1613 1.39 jdc DAC_WRITE(sc, FFB_DAC_VALUE, tgc); 1614 1.45 macallan DPRINTF(("new tgc: %08x\n", tgc)); 1615 1.45 macallan 1616 1.39 jdc *hres = mode->hdisplay; 1617 1.39 jdc *vres = mode->vdisplay; 1618 1.39 jdc 1619 1.39 jdc printf("%s: video mode set to %d x %d @ %dHz\n", 1620 1.43 christos device_xname(sc->sc_dev), 1621 1.39 jdc mode->hdisplay, mode->vdisplay, 1622 1.39 jdc DIVIDE(DIVIDE(mode->dot_clock * 1000, 1623 1.39 jdc mode->htotal), mode->vtotal)); 1624 1.39 jdc 1625 1.39 jdc return 1; 1626 1.39 jdc } 1627