1/* $NetBSD: diofb.c,v 1.2 2011/02/12 16:40:29 tsutsui Exp $ */ 2/* $OpenBSD: diofb.c,v 1.18 2010/12/26 15:40:59 miod Exp $ */ 3 4/* 5 * Copyright (c) 2005, Miodrag Vallat 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 25 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28/* 29 * Copyright (c) 1988 University of Utah. 30 * Copyright (c) 1990, 1993 31 * The Regents of the University of California. All rights reserved. 32 * 33 * This code is derived from software contributed to Berkeley by 34 * the Systems Programming Group of the University of Utah Computer 35 * Science Department. 36 * 37 * Redistribution and use in source and binary forms, with or without 38 * modification, are permitted provided that the following conditions 39 * are met: 40 * 1. Redistributions of source code must retain the above copyright 41 * notice, this list of conditions and the following disclaimer. 42 * 2. Redistributions in binary form must reproduce the above copyright 43 * notice, this list of conditions and the following disclaimer in the 44 * documentation and/or other materials provided with the distribution. 45 * 3. Neither the name of the University nor the names of its contributors 46 * may be used to endorse or promote products derived from this software 47 * without specific prior written permission. 48 * 49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 52 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 59 * SUCH DAMAGE. 60 */ 61 62#include <sys/param.h> 63#include <sys/conf.h> 64#include <sys/proc.h> 65#include <sys/ioctl.h> 66#include <sys/tty.h> 67#include <sys/systm.h> 68#include <sys/device.h> 69#include <sys/bus.h> 70#include <sys/cpu.h> 71 72#include <machine/autoconf.h> 73 74#include <dev/wscons/wsconsio.h> 75#include <dev/wscons/wsdisplayvar.h> 76#include <dev/rasops/rasops.h> 77 78#include <hp300/dev/dioreg.h> 79#include <hp300/dev/diovar.h> 80#include <hp300/dev/diofbreg.h> 81#include <hp300/dev/diofbvar.h> 82 83static void diofb_do_cursor(struct rasops_info *); 84static void diofb_copycols(void *, int, int, int, int); 85static void diofb_erasecols(void *, int, int, int, long); 86static void diofb_copyrows(void *, int, int, int); 87static void diofb_eraserows(void *, int, int, long); 88static int diofb_allocattr(void *, int, int, int, long *); 89 90struct diofb diofb_cn; 91 92/* 93 * Frame buffer geometry initialization 94 */ 95 96int 97diofb_fbinquire(struct diofb *fb, int scode, struct diofbreg *fbr) 98{ 99 int fboff, regsize; 100 101 if (ISIIOVA(fbr)) 102 fb->regaddr = (uint8_t *)IIOP(fbr); 103 else 104 fb->regaddr = dio_scodetopa(scode); 105 106 if (fb->fbwidth == 0 || fb->fbheight == 0) { 107 fb->fbwidth = (fbr->fbwmsb << 8) | fbr->fbwlsb; 108 fb->fbheight = (fbr->fbhmsb << 8) | fbr->fbhlsb; 109 } 110 fb->fbsize = fb->fbwidth * fb->fbheight; 111 112 fb->regkva = (uint8_t *)fbr; 113 fboff = (fbr->fbomsb << 8) | fbr->fbolsb; 114 fb->fbaddr = (uint8_t *) (*((uint8_t *)fbr + fboff) << 16); 115 116 if (fb->regaddr >= (uint8_t *)DIOII_BASE) { 117 /* 118 * For DIO-II space the fbaddr just computed is 119 * the offset from the select code base (regaddr) 120 * of the framebuffer. Hence it is also implicitly 121 * the size of the set. 122 */ 123 regsize = (uintptr_t)fb->fbaddr; 124 fb->fbaddr = fb->regaddr + (uintptr_t)fb->fbaddr; 125 fb->fbkva = (uint8_t *)fbr + regsize; 126 } else { 127 /* 128 * For internal or DIO-I space we need to map the separate 129 * framebuffer. 130 */ 131 fb->fbkva = iomap(fb->fbaddr, fb->fbsize); 132 if (fb->fbkva == NULL) 133 return ENOMEM; 134 } 135 if (fb->dwidth == 0 || fb->dheight == 0) { 136 fb->dwidth = (fbr->dwmsb << 8) | fbr->dwlsb; 137 fb->dheight = (fbr->dhmsb << 8) | fbr->dhlsb; 138 } 139 140 /* 141 * Some displays, such as the DaVinci, appear to return a display 142 * height larger than the frame buffer height. 143 */ 144 if (fb->dwidth > fb->fbwidth) 145 fb->dwidth = fb->fbwidth; 146 if (fb->dheight > fb->fbheight) 147 fb->dheight = fb->fbheight; 148 149 fb->planes = fbr->num_planes; 150 if (fb->planes > 8) 151 fb->planes = 8; 152 fb->planemask = (1 << fb->planes) - 1; 153 154 fb->mapmode = WSDISPLAYIO_MODE_DUMBFB; 155 156 return 0; 157} 158 159/* 160 * Frame buffer rasops and colormap setup 161 */ 162 163void 164diofb_fbsetup(struct diofb *fb) 165{ 166 struct rasops_info *ri = &fb->ri; 167 168 /* 169 * Pretend we are an 8bpp frame buffer, unless ri_depth is already 170 * initialized, since this is how it is supposed to be addressed. 171 * (Hyperion forces 1bpp because it is really 1bpp addressed). 172 */ 173 if (ri->ri_depth == 0) 174 ri->ri_depth = 8; 175 ri->ri_stride = (fb->fbwidth * ri->ri_depth) / 8; 176 177 ri->ri_flg = RI_CENTER | RI_FULLCLEAR; 178 /* We don't really support colors on less than 4bpp frame buffers */ 179 if (fb->planes < 4) 180 ri->ri_flg |= RI_FORCEMONO; 181 if (fb == &diofb_cn) 182 ri->ri_flg |= RI_NO_AUTO; 183 ri->ri_bits = fb->fbkva; 184 ri->ri_width = fb->dwidth; 185 ri->ri_height = fb->dheight; 186 ri->ri_hw = fb; 187 188 /* 189 * Ask for an unholy big display, rasops will trim this to more 190 * reasonable values. 191 */ 192 rasops_init(ri, 160, 160); 193 194 diofb_resetcmap(fb); 195 196 /* 197 * For low depth frame buffers, since we have faked a 8bpp frame buffer 198 * to rasops, we actually have to remove capabilities. 199 */ 200 if (fb->planes == 4) { 201 ri->ri_ops.allocattr = diofb_allocattr; 202 ri->ri_caps &= ~WSSCREEN_HILIT; 203 } 204 205 ri->ri_ops.copycols = diofb_copycols; 206 ri->ri_ops.erasecols = diofb_erasecols; 207 if (ri->ri_depth != 1) { 208 ri->ri_ops.copyrows = diofb_copyrows; 209 ri->ri_ops.eraserows = diofb_eraserows; 210 ri->ri_do_cursor = diofb_do_cursor; 211 } 212 213 /* Clear entire display, including non visible areas */ 214 (*fb->bmv)(fb, 0, 0, 0, 0, fb->fbwidth, fb->fbheight, RR_CLEAR, 0xff); 215 216 fb->wsd.name = fb->wsdname; 217 fb->wsd.ncols = ri->ri_cols; 218 fb->wsd.nrows = ri->ri_rows; 219 fb->wsd.textops = &ri->ri_ops; 220 fb->wsd.fontwidth = ri->ri_font->fontwidth; 221 fb->wsd.fontheight = ri->ri_font->fontheight; 222 fb->wsd.capabilities = ri->ri_caps; 223 strlcpy(fb->wsdname, "std", sizeof(fb->wsdname)); 224} 225 226/* 227 * Setup default emulation mode colormap 228 */ 229void 230diofb_resetcmap(struct diofb *fb) 231{ 232 const u_char *color; 233 u_int i; 234 235 /* start with the rasops colormap */ 236 color = (const u_char *)rasops_cmap; 237 for (i = 0; i < 256; i++) { 238 fb->cmap.r[i] = *color++; 239 fb->cmap.g[i] = *color++; 240 fb->cmap.b[i] = *color++; 241 } 242 243 /* 244 * Tweak colormap 245 * 246 * Due to the way rasops cursor work, we need to provide 247 * copies of the 8 or 16 basic colors at extra locations 248 * in 4bpp and 6bpp mode. This is because missing planes 249 * accept writes but read back as zero. 250 * 251 * So, in 6bpp mode: 252 * 00 gets inverted to ff, read back as 3f 253 * 3f gets inverted to c0, read back as 00 254 * and in 4bpp mode: 255 * 00 gets inverted to ff, read back as 0f 256 * 0f gets inverted to f0, read back as 00 257 */ 258 259 switch (fb->planes) { 260 case 6: 261 /* 262 * 00-0f normal colors 263 * 30-3f inverted colors 264 * c0-cf normal colors 265 * f0-ff inverted colors 266 */ 267 memcpy(fb->cmap.r + 0xc0, fb->cmap.r + 0x00, 0x10); 268 memcpy(fb->cmap.g + 0xc0, fb->cmap.g + 0x00, 0x10); 269 memcpy(fb->cmap.b + 0xc0, fb->cmap.b + 0x00, 0x10); 270 memcpy(fb->cmap.r + 0x30, fb->cmap.r + 0xf0, 0x10); 271 memcpy(fb->cmap.g + 0x30, fb->cmap.g + 0xf0, 0x10); 272 memcpy(fb->cmap.b + 0x30, fb->cmap.b + 0xf0, 0x10); 273 break; 274 case 4: 275 /* 276 * 00-07 normal colors 277 * 08-0f inverted colors 278 * highlighted colors are not available. 279 */ 280 memcpy(fb->cmap.r + 0x08, fb->cmap.r + 0xf8, 0x08); 281 memcpy(fb->cmap.g + 0x08, fb->cmap.g + 0xf8, 0x08); 282 memcpy(fb->cmap.b + 0x08, fb->cmap.b + 0xf8, 0x08); 283 break; 284 } 285} 286 287/* 288 * Attachment helpers 289 */ 290 291void 292diofb_cnattach(struct diofb *fb) 293{ 294 long defattr; 295 struct rasops_info *ri; 296 297 ri = &fb->ri; 298 ri->ri_ops.allocattr(ri, 0, 0, 0, &defattr); 299 wsdisplay_cnattach(&fb->wsd, ri, 0, 0, defattr); 300} 301 302void 303diofb_end_attach(device_t self, struct wsdisplay_accessops *accessops, 304 struct diofb *fb, int console, const char *descr) 305{ 306 struct wsemuldisplaydev_attach_args waa; 307 308 aprint_normal(": %dx%d", fb->dwidth, fb->dheight); 309 310 if (fb->planes == 1) 311 aprint_normal(" monochrome"); 312 else 313 aprint_normal("x%d", fb->planes); 314 315 if (descr != NULL) 316 aprint_normal(" %s", descr); 317 aprint_normal(" frame buffer\n"); 318 319 fb->scrlist[0] = &fb->wsd; 320 fb->wsl.nscreens = 1; 321 fb->wsl.screens = (const struct wsscreen_descr **)fb->scrlist; 322 323 waa.console = console; 324 waa.scrdata = &fb->wsl; 325 waa.accessops = accessops; 326 waa.accesscookie = fb; 327 328 config_found(self, &waa, wsemuldisplaydevprint); 329} 330 331/* 332 * Common wsdisplay emulops for DIO frame buffers 333 */ 334 335int 336diofb_allocattr(void *cookie, int fg, int bg, int flg, long *attr) 337{ 338 339 if ((flg & (WSATTR_BLINK | WSATTR_HILIT)) != 0) 340 return EINVAL; 341 342 if ((flg & WSATTR_WSCOLORS) == 0) { 343 fg = WSCOL_WHITE; 344 bg = WSCOL_BLACK; 345 } 346 347 if ((flg & WSATTR_REVERSE) != 0) { 348 int swap; 349 swap = fg; 350 fg = bg; 351 bg = swap; 352 } 353 354 flg = ((flg & WSATTR_UNDERLINE) ? 1 : 0); 355 356 *attr = (bg << 16) | (fg << 24) | flg; 357 358 return 0; 359} 360 361void 362diofb_copycols(void *cookie, int row, int src, int dst, int n) 363{ 364 struct rasops_info *ri = cookie; 365 struct diofb *fb = ri->ri_hw; 366 367 n *= ri->ri_font->fontwidth; 368 src *= ri->ri_font->fontwidth; 369 dst *= ri->ri_font->fontwidth; 370 row *= ri->ri_font->fontheight; 371 372 (*fb->bmv)(fb, ri->ri_xorigin + src, ri->ri_yorigin + row, 373 ri->ri_xorigin + dst, ri->ri_yorigin + row, 374 n, ri->ri_font->fontheight, RR_COPY, 0xff); 375} 376 377void 378diofb_copyrows(void *cookie, int src, int dst, int n) 379{ 380 struct rasops_info *ri = cookie; 381 struct diofb *fb = ri->ri_hw; 382 383 n *= ri->ri_font->fontheight; 384 src *= ri->ri_font->fontheight; 385 dst *= ri->ri_font->fontheight; 386 387 (*fb->bmv)(fb, ri->ri_xorigin, ri->ri_yorigin + src, 388 ri->ri_xorigin, ri->ri_yorigin + dst, 389 ri->ri_emuwidth, n, RR_COPY, 0xff); 390} 391 392void 393diofb_erasecols(void *cookie, int row, int col, int num, long attr) 394{ 395 struct rasops_info *ri = cookie; 396 struct diofb *fb = ri->ri_hw; 397 int fg, bg; 398 int snum, scol, srow; 399 400 rasops_unpack_attr(attr, &fg, &bg, NULL); 401 402 snum = num * ri->ri_font->fontwidth; 403 scol = col * ri->ri_font->fontwidth + ri->ri_xorigin; 404 srow = row * ri->ri_font->fontheight + ri->ri_yorigin; 405 406 /* 407 * If this is too tricky for the simple raster ops engine, 408 * pass the fun to rasops. 409 */ 410 if ((*fb->bmv)(fb, scol, srow, scol, srow, snum, 411 ri->ri_font->fontheight, RR_CLEAR, 0xff ^ bg) != 0) 412 rasops_erasecols(cookie, row, col, num, attr); 413} 414 415void 416diofb_eraserows(void *cookie, int row, int num, long attr) 417{ 418 struct rasops_info *ri = cookie; 419 struct diofb *fb = ri->ri_hw; 420 int fg, bg; 421 int srow, snum; 422 int rc; 423 424 rasops_unpack_attr(attr, &fg, &bg, NULL); 425 bg ^= 0xff; 426 427 if (num == ri->ri_rows && (ri->ri_flg & RI_FULLCLEAR)) { 428 rc = (*fb->bmv)(fb, 0, 0, 0, 0, ri->ri_width, ri->ri_height, 429 RR_CLEAR, bg); 430 } else { 431 srow = row * ri->ri_font->fontheight + ri->ri_yorigin; 432 snum = num * ri->ri_font->fontheight; 433 rc = (*fb->bmv)(fb, ri->ri_xorigin, srow, ri->ri_xorigin, 434 srow, ri->ri_emuwidth, snum, RR_CLEAR, bg); 435 } 436 if (rc != 0) 437 rasops_eraserows(cookie, row, num, attr); 438} 439 440void 441diofb_do_cursor(struct rasops_info *ri) 442{ 443 struct diofb *fb = ri->ri_hw; 444 int x, y; 445 446 x = ri->ri_ccol * ri->ri_font->fontwidth + ri->ri_xorigin; 447 y = ri->ri_crow * ri->ri_font->fontheight + ri->ri_yorigin; 448 (*fb->bmv)(fb, x, y, x, y, ri->ri_font->fontwidth, 449 ri->ri_font->fontheight, RR_INVERT, 0xff); 450} 451 452/* 453 * Common wsdisplay accessops for DIO frame buffers 454 */ 455 456int 457diofb_alloc_screen(void *v, const struct wsscreen_descr *type, 458 void **cookiep, int *curxp, int *curyp, long *attrp) 459{ 460 struct diofb *fb = v; 461 struct rasops_info *ri = &fb->ri; 462 463 if (fb->nscreens > 0) 464 return ENOMEM; 465 466 *cookiep = ri; 467 *curxp = *curyp = 0; 468 ri->ri_ops.allocattr(ri, 0, 0, 0, attrp); 469 fb->nscreens++; 470 471 return 0; 472} 473 474void 475diofb_free_screen(void *v, void *cookie) 476{ 477 struct diofb *fb = v; 478 479 fb->nscreens--; 480} 481 482int 483diofb_show_screen(void *v, void *cookie, int waitok, 484 void (*cb)(void *, int, int), void *cbarg) 485{ 486 487 return 0; 488} 489 490paddr_t 491diofb_mmap(void *v, void *vs, off_t offset, int prot) 492{ 493 struct diofb *fb = v; 494 495 if ((offset & PAGE_MASK) != 0) 496 return -1; 497 498 switch (fb->mapmode) { 499 case WSDISPLAYIO_MODE_MAPPED: 500 if (offset >= 0 && offset < DIOFB_REGSPACE) 501 return m68k_btop(fb->regaddr + offset); 502 offset -= DIOFB_REGSPACE; 503 /* FALLTHROUGH */ 504 case WSDISPLAYIO_MODE_DUMBFB: 505 if (offset >= 0 && offset < fb->fbsize) 506 return m68k_btop(fb->fbaddr + offset); 507 break; 508 } 509 510 return -1; 511} 512 513int 514diofb_getcmap(struct diofb *fb, struct wsdisplay_cmap *cm) 515{ 516 u_int index = cm->index, count = cm->count; 517 u_int colcount = 1 << fb->planes; 518 int error; 519 520 if (index >= colcount || count > colcount - index) 521 return EINVAL; 522 523 if ((error = copyout(fb->cmap.r + index, cm->red, count)) != 0) 524 return error; 525 if ((error = copyout(fb->cmap.g + index, cm->green, count)) != 0) 526 return error; 527 if ((error = copyout(fb->cmap.b + index, cm->blue, count)) != 0) 528 return error; 529 530 return 0; 531} 532