1 /* $NetBSD: fb_elb.c,v 1.5 2004/09/13 15:14:12 drochner Exp $ */ 2 3 /*- 4 * Copyright (c) 2003 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Juergen Hannken-Illjes. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 #include <sys/cdefs.h> 40 __KERNEL_RCSID(0, "$NetBSD: fb_elb.c,v 1.5 2004/09/13 15:14:12 drochner Exp $"); 41 42 #include <sys/param.h> 43 #include <sys/conf.h> 44 #include <sys/device.h> 45 #include <sys/ioctl.h> 46 #include <sys/malloc.h> 47 #include <sys/systm.h> 48 49 #include <dev/wscons/wsconsio.h> 50 #include <dev/wscons/wsdisplayvar.h> 51 #include <dev/rasops/rasops.h> 52 53 #include <machine/explora.h> 54 #include <machine/bus.h> 55 56 #include <evbppc/explora/dev/elbvar.h> 57 58 #define FB_NPORTS 65536 59 60 struct fb_dev { 61 void *fb_vram; 62 bus_space_tag_t fb_iot; 63 bus_space_handle_t fb_ioh; 64 struct rasops_info fb_ri; 65 }; 66 67 struct fb_elb_softc { 68 struct device sc_dev; 69 struct fb_dev *sc_fb; 70 int sc_nscreens; 71 }; 72 73 static int fb_elb_probe(struct device *, struct cfdata *, void *); 74 static void fb_elb_attach(struct device *, struct device *, void *); 75 void fb_cnattach(bus_space_tag_t, bus_addr_t, void *); 76 static void fb_init(struct fb_dev *, int); 77 static int fb_ioctl(void *, u_long, caddr_t, int, struct proc *); 78 static paddr_t fb_mmap(void *, off_t, int); 79 static int fb_alloc_screen(void *, const struct wsscreen_descr *, void **, 80 int *, int *, long *); 81 static void fb_free_screen(void *, void *); 82 static int fb_show_screen(void *, void *, int, void (*)(void *, int, int), 83 void *); 84 85 static void fb_eraserows(void *, int, int, long); 86 static void fb_erasecols(void *, int, int, int, long); 87 static void fb_copyrows(void *, int, int, int); 88 static void fb_copycols(void *, int, int, int, int); 89 90 static void s3_init(struct fb_dev *, int *, int *); 91 static void s3_copy(struct fb_dev *, int, int, int, int, int, int, int); 92 static void s3_fill(struct fb_dev *, int, int, int, int, int, int); 93 94 static struct fb_dev console_dev; 95 96 static struct wsdisplay_accessops accessops = { 97 fb_ioctl, 98 fb_mmap, 99 fb_alloc_screen, 100 fb_free_screen, 101 fb_show_screen, 102 NULL 103 }; 104 105 static struct wsscreen_descr stdscreen = { 106 "std", 107 0, 0, 108 0, 109 0, 0, 110 0 111 }; 112 113 static const struct wsscreen_descr *scrlist[] = { 114 &stdscreen 115 }; 116 117 static struct wsscreen_list screenlist = { 118 sizeof(scrlist)/sizeof(scrlist[0]), scrlist 119 }; 120 121 CFATTACH_DECL(fb_elb, sizeof(struct fb_elb_softc), 122 fb_elb_probe, fb_elb_attach, NULL, NULL); 123 124 static int 125 fb_elb_probe(struct device *parent, struct cfdata *cf, void *aux) 126 { 127 struct elb_attach_args *oaa = aux; 128 129 if (strcmp(oaa->elb_name, cf->cf_name) != 0) 130 return 0; 131 132 return (1); 133 } 134 135 static void 136 fb_elb_attach(struct device *parent, struct device *self, void *aux) 137 { 138 struct fb_elb_softc *sc = (void *)self; 139 struct elb_attach_args *eaa = aux; 140 struct wsemuldisplaydev_attach_args waa; 141 struct rasops_info *ri; 142 bus_space_handle_t ioh; 143 int is_console; 144 145 is_console = ((void *)eaa->elb_base == console_dev.fb_vram); 146 147 if (is_console) { 148 sc->sc_fb = &console_dev; 149 } else { 150 sc->sc_fb = malloc(sizeof(struct fb_dev), M_DEVBUF, M_WAITOK); 151 memset(sc->sc_fb, 0, sizeof(struct fb_dev)); 152 } 153 154 sc->sc_fb->fb_iot = eaa->elb_bt; 155 bus_space_map(sc->sc_fb->fb_iot, eaa->elb_base, SIZE_FB, 156 BUS_SPACE_MAP_LINEAR, &ioh); 157 sc->sc_fb->fb_vram = bus_space_vaddr(sc->sc_fb->fb_iot, ioh); 158 bus_space_map(sc->sc_fb->fb_iot, eaa->elb_base2, FB_NPORTS, 159 0, &sc->sc_fb->fb_ioh); 160 161 fb_init(sc->sc_fb, !is_console); 162 163 ri = &sc->sc_fb->fb_ri; 164 165 printf(": %d x %d\n", ri->ri_rows, ri->ri_cols); 166 167 waa.console = is_console; 168 waa.scrdata = &screenlist; 169 waa.accessops = &accessops; 170 waa.accesscookie = sc; 171 172 config_found(self, &waa, wsemuldisplaydevprint); 173 } 174 175 static void 176 fb_init(struct fb_dev *fb, int full) 177 { 178 struct rasops_info *ri = &fb->fb_ri; 179 180 if (full) { 181 s3_init(fb, &ri->ri_width, &ri->ri_height); 182 ri->ri_depth = 8; 183 ri->ri_stride = ri->ri_width; 184 ri->ri_bits = fb->fb_vram; 185 ri->ri_flg = RI_CENTER; 186 187 rasops_init(ri, 500, 500); 188 } else { 189 ri->ri_origbits = fb->fb_vram; /*XXX*/ 190 rasops_reconfig(ri, 500, 500); 191 } 192 193 /* Replace the copy/erase ops. */ 194 ri->ri_hw = fb; 195 ri->ri_ops.eraserows = fb_eraserows; 196 ri->ri_ops.erasecols = fb_erasecols; 197 ri->ri_ops.copyrows = fb_copyrows; 198 ri->ri_ops.copycols = fb_copycols; 199 200 stdscreen.nrows = ri->ri_rows; 201 stdscreen.ncols = ri->ri_cols; 202 stdscreen.textops = &ri->ri_ops; 203 stdscreen.capabilities = ri->ri_caps; 204 } 205 206 static int 207 fb_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 208 { 209 struct fb_elb_softc *sc = v; 210 struct rasops_info *ri = &sc->sc_fb->fb_ri; 211 struct wsdisplay_fbinfo *wdf; 212 213 switch (cmd) { 214 case WSDISPLAYIO_GTYPE: 215 *(int *)data = WSDISPLAY_TYPE_UNKNOWN; /* XXX */ 216 return(0); 217 218 case WSDISPLAYIO_GINFO: 219 wdf = (void *)data; 220 wdf->height = ri->ri_height; 221 wdf->width = ri->ri_width; 222 wdf->depth = ri->ri_depth; 223 wdf->cmsize = 16; /*XXX*/ 224 return(0); 225 226 case WSDISPLAYIO_SVIDEO: 227 case WSDISPLAYIO_GETCMAP: 228 case WSDISPLAYIO_PUTCMAP: 229 break; 230 } 231 232 return(EPASSTHROUGH); 233 } 234 235 static paddr_t 236 fb_mmap(void *v, off_t offset, int prot) 237 { 238 struct fb_elb_softc *sc = v; 239 240 if (offset < 0 || offset >= SIZE_FB) 241 return -1; 242 243 return bus_space_mmap(sc->sc_fb->fb_iot, BASE_FB, offset, prot, 244 BUS_SPACE_MAP_LINEAR); 245 } 246 247 static int 248 fb_alloc_screen(void *v, const struct wsscreen_descr *scrdesc, void **cookiep, 249 int *ccolp, int *crowp, long *attrp) 250 { 251 struct fb_elb_softc *sc = v; 252 struct rasops_info *ri = &sc->sc_fb->fb_ri; 253 254 if (sc->sc_nscreens > 0) 255 return ENOMEM; 256 257 *cookiep = ri; 258 *ccolp = *crowp = 0; 259 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, attrp); 260 sc->sc_nscreens++; 261 262 return(0); 263 } 264 265 static void 266 fb_free_screen(void *v, void *cookie) 267 { 268 struct fb_elb_softc *sc = v; 269 270 if (sc->sc_fb == &console_dev) 271 panic("fb_free_screen: freeing console"); 272 273 sc->sc_nscreens--; 274 } 275 276 static int 277 fb_show_screen(void *v, void *cookie, int waitok, void (*cb)(void *, int, int), 278 void *cbarg) 279 { 280 return(0); 281 } 282 283 void 284 fb_cnattach(bus_space_tag_t iot, bus_addr_t iobase, void *vram) 285 { 286 struct rasops_info *ri = &console_dev.fb_ri; 287 long defattr; 288 289 console_dev.fb_iot = iot; 290 console_dev.fb_ioh = iobase; 291 console_dev.fb_vram = vram; 292 293 fb_init(&console_dev, 1); 294 295 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr); 296 297 wsdisplay_cnattach(&stdscreen, ri, 0, 0, defattr); 298 } 299 300 static void 301 fb_eraserows(void *v, int row, int nrows, long attr) 302 { 303 struct rasops_info *ri = v; 304 struct fb_dev *fb = ri->ri_hw; 305 306 row *= ri->ri_font->fontheight; 307 nrows *= ri->ri_font->fontheight; 308 309 s3_fill(fb, 0, row, ri->ri_stride, nrows, (attr >> 16)&0x0f, 0x0f); 310 } 311 312 static void 313 fb_erasecols(void *v, int row, int startcol, int ncols, long attr) 314 { 315 struct rasops_info *ri = v; 316 struct fb_dev *fb = ri->ri_hw; 317 318 row *= ri->ri_font->fontheight; 319 startcol *= ri->ri_font->fontwidth; 320 ncols *= ri->ri_font->fontwidth; 321 322 s3_fill(fb, startcol, row, ncols, ri->ri_font->fontheight, 323 (attr >> 16)&0x0f, 0x0f); 324 } 325 326 static void 327 fb_copyrows(void *v, int srcrow, int dstrow, int nrows) 328 { 329 struct rasops_info *ri = v; 330 struct fb_dev *fb = ri->ri_hw; 331 332 srcrow *= ri->ri_font->fontheight; 333 dstrow *= ri->ri_font->fontheight; 334 nrows *= ri->ri_font->fontheight; 335 336 s3_copy(fb, 0, srcrow, 0, dstrow, ri->ri_stride, nrows, 0x0f); 337 } 338 339 static void 340 fb_copycols(void *v, int row, int srccol, int dstcol, int ncols) 341 { 342 struct rasops_info *ri = v; 343 struct fb_dev *fb = ri->ri_hw; 344 345 row *= ri->ri_font->fontheight; 346 srccol *= ri->ri_font->fontwidth; 347 dstcol *= ri->ri_font->fontwidth; 348 ncols *= ri->ri_font->fontwidth; 349 350 s3_copy(fb, srccol, row, dstcol, row, 351 ncols, ri->ri_font->fontheight, 0x0f); 352 } 353 354 /* 355 * S3 support routines 356 */ 357 358 #define S3_CRTC_INDEX 0x83d4 359 #define S3_CRTC_DATA 0x83d5 360 361 #define S3_DAC_RD_INDEX 0x83c7 362 #define S3_DAC_WR_INDEX 0x83c8 363 #define S3_DAC_DATA 0x83c9 364 365 #define S3_CUR_Y 0x82e8 366 #define S3_CUR_X 0x86e8 367 #define S3_DESTY_AXSTP 0x8ae8 368 #define S3_DESTX_DIASTP 0x8ee8 369 #define S3_MAJ_AXIS_PCNT 0x96e8 370 #define S3_GP_STAT 0x9ae8 371 #define S3_CMD 0x9ae8 372 #define S3_BKGD_COLOR 0xa2e8 373 #define S3_FRGD_COLOR 0xa6e8 374 #define S3_WRT_MASK 0xaae8 375 #define S3_RD_MASK 0xaee8 376 #define S3_BKGD_MIX 0xb6e8 377 #define S3_FRGD_MIX 0xbae8 378 #define S3_MULTIFUNC_CNTL 0xbee8 379 380 #define S3_GP_STAT_FIFO_1 0x0080 381 #define S3_GP_STAT_BSY 0x0200 382 383 #define S3_CMD_BITBLT 0xc001 384 #define S3_CMD_RECT 0x4001 385 #define S3_INC_Y 0x0080 386 #define S3_INC_X 0x0020 387 #define S3_DRAW 0x0010 388 #define S3_MULTI 0x0002 389 390 #define S3_CSRC_BKGDCOL 0x0000 391 #define S3_CSRC_FRGDCOL 0x0020 392 #define S3_CSRC_DISPMEM 0x0060 393 #define S3_MIX_NEW 0x0007 394 395 #define CMAP_SIZE 256 396 397 static u_int8_t default_cmap[] = { 398 /* black */ 0, 0, 0, 399 /* blue */ 0, 0, 192, 400 /* green */ 0, 192, 0, 401 /* cyan */ 0, 192, 192, 402 /* red */ 192, 0, 0, 403 /* magenta */ 192, 0, 192, 404 /* brown */ 192, 192, 0, 405 /* lightgrey */ 212, 208, 200, 406 /* darkgrey */ 200, 192, 188, 407 /* lightblue */ 0, 0, 255, 408 /* lightgreen */ 0, 255, 0, 409 /* lightcyan */ 0, 255, 255, 410 /* lightred */ 255, 0, 0, 411 /* lightmagenta */ 255, 0, 255, 412 /* yellow */ 255, 255, 0, 413 /* white */ 255, 255, 255, 414 }; 415 416 static void 417 s3_init(struct fb_dev *fb, int *width, int *height) 418 { 419 int i, j, w, h; 420 bus_space_tag_t iot = fb->fb_iot; 421 bus_space_handle_t ioh = fb->fb_ioh; 422 423 /* Initialize colormap */ 424 425 bus_space_write_1(iot, ioh, S3_DAC_WR_INDEX, 0); 426 427 for (i = j = 0; i < CMAP_SIZE*3; i++) { 428 bus_space_write_1(iot, ioh, S3_DAC_DATA, default_cmap[j] >> 2); 429 j = (j+1) % sizeof(default_cmap)/sizeof(default_cmap[0]); 430 } 431 432 /* Retrieve frame buffer geometry */ 433 434 bus_space_write_1(iot, ioh, S3_CRTC_INDEX, 1); 435 w = bus_space_read_1(iot, ioh, S3_CRTC_DATA); 436 437 bus_space_write_1(iot, ioh, S3_CRTC_INDEX, 18); 438 h = bus_space_read_1(iot, ioh, S3_CRTC_DATA); 439 440 bus_space_write_1(iot, ioh, S3_CRTC_INDEX, 7); 441 i = bus_space_read_1(iot, ioh, S3_CRTC_DATA); 442 443 h += (i << 7) & 0x100; 444 h += (i << 3) & 0x200; 445 446 *width = (w+1) << 3; 447 *height = h+1; 448 } 449 450 static void 451 s3_copy(struct fb_dev *fb, int src_x, int src_y, int dest_x, int dest_y, 452 int width, int height, int mask) 453 { 454 bus_space_tag_t iot = fb->fb_iot; 455 bus_space_handle_t ioh = fb->fb_ioh; 456 u_int16_t cmd = S3_CMD_BITBLT | S3_DRAW; 457 458 if (src_x > dest_x) 459 cmd |= S3_INC_X; 460 else { 461 src_x += width-1; 462 dest_x += width-1; 463 } 464 465 if (src_y > dest_y) 466 cmd |= S3_INC_Y; 467 else { 468 src_y += height-1; 469 dest_y += height-1; 470 } 471 472 while (bus_space_read_2(iot, ioh, S3_GP_STAT) & S3_GP_STAT_FIFO_1) 473 ; 474 475 bus_space_write_2(iot, ioh, S3_FRGD_MIX, S3_CSRC_DISPMEM | S3_MIX_NEW); 476 bus_space_write_2(iot, ioh, S3_WRT_MASK, mask); 477 bus_space_write_2(iot, ioh, S3_CUR_X, src_x); 478 bus_space_write_2(iot, ioh, S3_CUR_Y, src_y); 479 bus_space_write_2(iot, ioh, S3_DESTX_DIASTP, dest_x); 480 bus_space_write_2(iot, ioh, S3_DESTY_AXSTP, dest_y); 481 bus_space_write_2(iot, ioh, S3_MULTIFUNC_CNTL, height-1); 482 bus_space_write_2(iot, ioh, S3_MAJ_AXIS_PCNT, width-1); 483 bus_space_write_2(iot, ioh, S3_CMD, cmd); 484 485 while (bus_space_read_2(iot, ioh, S3_GP_STAT) & S3_GP_STAT_BSY) 486 ; 487 } 488 489 static void 490 s3_fill(struct fb_dev *fb, int x, int y, int width, int height, 491 int color, int mask) 492 { 493 bus_space_tag_t iot = fb->fb_iot; 494 bus_space_handle_t ioh = fb->fb_ioh; 495 u_int16_t cmd = S3_CMD_RECT | S3_INC_X | S3_INC_Y | S3_DRAW; 496 497 while (bus_space_read_2(iot, ioh, S3_GP_STAT) & S3_GP_STAT_FIFO_1) 498 ; 499 500 bus_space_write_2(iot, ioh, S3_FRGD_MIX, S3_CSRC_FRGDCOL | S3_MIX_NEW); 501 bus_space_write_2(iot, ioh, S3_FRGD_COLOR, color); 502 bus_space_write_2(iot, ioh, S3_WRT_MASK, mask); 503 bus_space_write_2(iot, ioh, S3_CUR_X, x); 504 bus_space_write_2(iot, ioh, S3_CUR_Y, y); 505 bus_space_write_2(iot, ioh, S3_MULTIFUNC_CNTL, height-1); 506 bus_space_write_2(iot, ioh, S3_MAJ_AXIS_PCNT, width-1); 507 bus_space_write_2(iot, ioh, S3_CMD, cmd); 508 509 while (bus_space_read_2(iot, ioh, S3_GP_STAT) & S3_GP_STAT_BSY) 510 ; 511 } 512