1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2013 The FreeBSD Foundation 5 * 6 * This software was developed by Aleksandr Rybalko under sponsorship from the 7 * FreeBSD Foundation. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 #include <sys/param.h> 32 #include <sys/systm.h> 33 #include <sys/malloc.h> 34 #include <sys/queue.h> 35 #include <sys/fbio.h> 36 #include <sys/kernel.h> 37 #include <dev/vt/vt.h> 38 #include <dev/vt/hw/fb/vt_fb.h> 39 #include <dev/vt/colors/vt_termcolors.h> 40 41 #include <vm/vm.h> 42 #include <vm/pmap.h> 43 44 static struct vt_driver vt_fb_driver = { 45 .vd_name = "fb", 46 .vd_init = vt_fb_init, 47 .vd_fini = vt_fb_fini, 48 .vd_blank = vt_fb_blank, 49 .vd_bitblt_text = vt_fb_bitblt_text, 50 .vd_invalidate_text = vt_fb_invalidate_text, 51 .vd_bitblt_bmp = vt_fb_bitblt_bitmap, 52 .vd_bitblt_argb = vt_fb_bitblt_argb, 53 .vd_drawrect = vt_fb_drawrect, 54 .vd_setpixel = vt_fb_setpixel, 55 .vd_postswitch = vt_fb_postswitch, 56 .vd_priority = VD_PRIORITY_GENERIC+10, 57 .vd_fb_ioctl = vt_fb_ioctl, 58 .vd_fb_mmap = vt_fb_mmap, 59 .vd_suspend = vt_fb_suspend, 60 .vd_resume = vt_fb_resume, 61 }; 62 63 VT_DRIVER_DECLARE(vt_fb, vt_fb_driver); 64 65 static void 66 vt_fb_mem_wr1(struct fb_info *sc, uint32_t o, uint8_t v) 67 { 68 69 KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 70 *(uint8_t *)(sc->fb_vbase + o) = v; 71 } 72 73 static void 74 vt_fb_mem_wr2(struct fb_info *sc, uint32_t o, uint16_t v) 75 { 76 77 KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 78 *(uint16_t *)(sc->fb_vbase + o) = v; 79 } 80 81 static void 82 vt_fb_mem_wr4(struct fb_info *sc, uint32_t o, uint32_t v) 83 { 84 85 KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 86 *(uint32_t *)(sc->fb_vbase + o) = v; 87 } 88 89 int 90 vt_fb_ioctl(struct vt_device *vd, u_long cmd, caddr_t data, struct thread *td) 91 { 92 struct fb_info *info; 93 int error = 0; 94 95 info = vd->vd_softc; 96 97 switch (cmd) { 98 case FBIOGTYPE: 99 bcopy(info, (struct fbtype *)data, sizeof(struct fbtype)); 100 break; 101 102 case FBIO_GETWINORG: /* get frame buffer window origin */ 103 *(u_int *)data = 0; 104 break; 105 106 case FBIO_GETDISPSTART: /* get display start address */ 107 ((video_display_start_t *)data)->x = 0; 108 ((video_display_start_t *)data)->y = 0; 109 break; 110 111 case FBIO_GETLINEWIDTH: /* get scan line width in bytes */ 112 *(u_int *)data = info->fb_stride; 113 break; 114 115 case FBIO_BLANK: /* blank display */ 116 if (vd->vd_driver->vd_blank == NULL) 117 return (ENODEV); 118 vd->vd_driver->vd_blank(vd, TC_BLACK); 119 break; 120 121 case FBIO_GETRGBOFFS: /* get RGB offsets */ 122 if (info->fb_rgboffs.red == 0 && info->fb_rgboffs.green == 0 && 123 info->fb_rgboffs.blue == 0) 124 return (ENOTTY); 125 memcpy((struct fb_rgboffs *)data, &info->fb_rgboffs, 126 sizeof(struct fb_rgboffs)); 127 break; 128 129 default: 130 error = ENOIOCTL; 131 break; 132 } 133 134 return (error); 135 } 136 137 int 138 vt_fb_mmap(struct vt_device *vd, vm_ooffset_t offset, vm_paddr_t *paddr, 139 int prot, vm_memattr_t *memattr) 140 { 141 struct fb_info *info; 142 143 info = vd->vd_softc; 144 145 if (info->fb_flags & FB_FLAG_NOMMAP) 146 return (ENODEV); 147 148 if (offset < info->fb_size) { 149 if (info->fb_pbase == 0) { 150 *paddr = vtophys((uint8_t *)info->fb_vbase + offset); 151 } else { 152 *paddr = info->fb_pbase + offset; 153 if (info->fb_flags & FB_FLAG_MEMATTR) 154 *memattr = info->fb_memattr; 155 #ifdef VM_MEMATTR_WRITE_COMBINING 156 else 157 *memattr = VM_MEMATTR_WRITE_COMBINING; 158 #endif 159 } 160 return (0); 161 } 162 163 return (EINVAL); 164 } 165 166 void 167 vt_fb_setpixel(struct vt_device *vd, int x, int y, term_color_t color) 168 { 169 struct fb_info *info; 170 uint32_t c; 171 u_int o; 172 173 info = vd->vd_softc; 174 c = info->fb_cmap[color]; 175 o = info->fb_stride * y + x * FBTYPE_GET_BYTESPP(info); 176 177 if (info->fb_flags & FB_FLAG_NOWRITE) 178 return; 179 180 KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer")); 181 182 switch (FBTYPE_GET_BYTESPP(info)) { 183 case 1: 184 vt_fb_mem_wr1(info, o, c); 185 break; 186 case 2: 187 vt_fb_mem_wr2(info, o, c); 188 break; 189 case 3: 190 vt_fb_mem_wr1(info, o, (c >> 16) & 0xff); 191 vt_fb_mem_wr1(info, o + 1, (c >> 8) & 0xff); 192 vt_fb_mem_wr1(info, o + 2, c & 0xff); 193 break; 194 case 4: 195 vt_fb_mem_wr4(info, o, c); 196 break; 197 default: 198 /* panic? */ 199 return; 200 } 201 } 202 203 void 204 vt_fb_drawrect(struct vt_device *vd, int x1, int y1, int x2, int y2, int fill, 205 term_color_t color) 206 { 207 int x, y; 208 209 for (y = y1; y <= y2; y++) { 210 if (fill || (y == y1) || (y == y2)) { 211 for (x = x1; x <= x2; x++) 212 vt_fb_setpixel(vd, x, y, color); 213 } else { 214 vt_fb_setpixel(vd, x1, y, color); 215 vt_fb_setpixel(vd, x2, y, color); 216 } 217 } 218 } 219 220 void 221 vt_fb_blank(struct vt_device *vd, term_color_t color) 222 { 223 struct fb_info *info; 224 uint32_t c; 225 u_int o, h; 226 227 info = vd->vd_softc; 228 c = info->fb_cmap[color]; 229 230 if (info->fb_flags & FB_FLAG_NOWRITE) 231 return; 232 233 KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer")); 234 235 switch (FBTYPE_GET_BYTESPP(info)) { 236 case 1: 237 for (h = 0; h < info->fb_height; h++) 238 for (o = 0; o < info->fb_stride; o++) 239 vt_fb_mem_wr1(info, h*info->fb_stride + o, c); 240 break; 241 case 2: 242 for (h = 0; h < info->fb_height; h++) 243 for (o = 0; o < info->fb_stride - 1; o += 2) 244 vt_fb_mem_wr2(info, h*info->fb_stride + o, c); 245 break; 246 case 3: 247 for (h = 0; h < info->fb_height; h++) 248 for (o = 0; o < info->fb_stride - 2; o += 3) { 249 vt_fb_mem_wr1(info, h*info->fb_stride + o, 250 (c >> 16) & 0xff); 251 vt_fb_mem_wr1(info, h*info->fb_stride + o + 1, 252 (c >> 8) & 0xff); 253 vt_fb_mem_wr1(info, h*info->fb_stride + o + 2, 254 c & 0xff); 255 } 256 break; 257 case 4: 258 for (h = 0; h < info->fb_height; h++) 259 for (o = 0; o < info->fb_stride - 3; o += 4) 260 vt_fb_mem_wr4(info, h*info->fb_stride + o, c); 261 break; 262 default: 263 /* panic? */ 264 return; 265 } 266 } 267 268 void 269 vt_fb_bitblt_bitmap(struct vt_device *vd, const struct vt_window *vw, 270 const uint8_t *pattern, const uint8_t *mask, 271 unsigned int width, unsigned int height, 272 unsigned int x, unsigned int y, term_color_t fg, term_color_t bg) 273 { 274 struct fb_info *info; 275 uint32_t fgc, bgc, cc, o; 276 int bpp, bpl, xi, yi; 277 int bit, byte; 278 279 info = vd->vd_softc; 280 bpp = FBTYPE_GET_BYTESPP(info); 281 fgc = info->fb_cmap[fg]; 282 bgc = info->fb_cmap[bg]; 283 bpl = (width + 7) / 8; /* Bytes per source line. */ 284 285 if (info->fb_flags & FB_FLAG_NOWRITE) 286 return; 287 288 KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer")); 289 290 /* Bound by right and bottom edges. */ 291 if (y + height > vw->vw_draw_area.tr_end.tp_row) { 292 if (y >= vw->vw_draw_area.tr_end.tp_row) 293 return; 294 height = vw->vw_draw_area.tr_end.tp_row - y; 295 } 296 if (x + width > vw->vw_draw_area.tr_end.tp_col) { 297 if (x >= vw->vw_draw_area.tr_end.tp_col) 298 return; 299 width = vw->vw_draw_area.tr_end.tp_col - x; 300 } 301 for (yi = 0; yi < height; yi++) { 302 for (xi = 0; xi < width; xi++) { 303 byte = yi * bpl + xi / 8; 304 bit = 0x80 >> (xi % 8); 305 /* Skip pixel write, if mask bit not set. */ 306 if (mask != NULL && (mask[byte] & bit) == 0) 307 continue; 308 o = (y + yi) * info->fb_stride + (x + xi) * bpp; 309 o += vd->vd_transpose; 310 cc = pattern[byte] & bit ? fgc : bgc; 311 312 switch(bpp) { 313 case 1: 314 vt_fb_mem_wr1(info, o, cc); 315 break; 316 case 2: 317 vt_fb_mem_wr2(info, o, cc); 318 break; 319 case 3: 320 /* Packed mode, so unaligned. Byte access. */ 321 vt_fb_mem_wr1(info, o, (cc >> 16) & 0xff); 322 vt_fb_mem_wr1(info, o + 1, (cc >> 8) & 0xff); 323 vt_fb_mem_wr1(info, o + 2, cc & 0xff); 324 break; 325 case 4: 326 vt_fb_mem_wr4(info, o, cc); 327 break; 328 default: 329 /* panic? */ 330 break; 331 } 332 } 333 } 334 } 335 336 int 337 vt_fb_bitblt_argb(struct vt_device *vd, const struct vt_window *vw, 338 const uint8_t *argb, 339 unsigned int width, unsigned int height, 340 unsigned int x, unsigned int y) 341 { 342 struct fb_info *info; 343 uint32_t o, cc; 344 int bpp, xi, yi; 345 346 info = vd->vd_softc; 347 bpp = FBTYPE_GET_BYTESPP(info); 348 if (bpp != 4) 349 return (EOPNOTSUPP); 350 351 if (info->fb_flags & FB_FLAG_NOWRITE) 352 return (0); 353 354 KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer")); 355 356 /* Bound by right and bottom edges. */ 357 if (y + height > vw->vw_draw_area.tr_end.tp_row) { 358 if (y >= vw->vw_draw_area.tr_end.tp_row) 359 return (EINVAL); 360 height = vw->vw_draw_area.tr_end.tp_row - y; 361 } 362 if (x + width > vw->vw_draw_area.tr_end.tp_col) { 363 if (x >= vw->vw_draw_area.tr_end.tp_col) 364 return (EINVAL); 365 width = vw->vw_draw_area.tr_end.tp_col - x; 366 } 367 for (yi = 0; yi < height; yi++) { 368 for (xi = 0; xi < (width * 4); xi += 4) { 369 o = (y + yi) * info->fb_stride + (x + (xi / 4)) * bpp; 370 o += vd->vd_transpose; 371 cc = (argb[yi * width * 4 + xi] << 16) | 372 (argb[yi * width * 4 + xi + 1] << 8) | 373 (argb[yi * width * 4 + xi + 2]) | 374 (argb[yi * width * 4 + xi + 3] << 24); 375 vt_fb_mem_wr4(info, o, cc); 376 } 377 } 378 379 return (0); 380 } 381 382 void 383 vt_fb_bitblt_text(struct vt_device *vd, const struct vt_window *vw, 384 const term_rect_t *area) 385 { 386 unsigned int col, row, x, y; 387 struct vt_font *vf; 388 term_char_t c; 389 term_color_t fg, bg; 390 const uint8_t *pattern; 391 size_t z; 392 393 vf = vw->vw_font; 394 395 for (row = area->tr_begin.tp_row; row < area->tr_end.tp_row; ++row) { 396 for (col = area->tr_begin.tp_col; col < area->tr_end.tp_col; 397 ++col) { 398 x = col * vf->vf_width + 399 vw->vw_draw_area.tr_begin.tp_col; 400 y = row * vf->vf_height + 401 vw->vw_draw_area.tr_begin.tp_row; 402 403 c = VTBUF_GET_FIELD(&vw->vw_buf, row, col); 404 pattern = vtfont_lookup(vf, c); 405 vt_determine_colors(c, 406 VTBUF_ISCURSOR(&vw->vw_buf, row, col), &fg, &bg); 407 408 z = row * PIXEL_WIDTH(VT_FB_MAX_WIDTH) + col; 409 if (z >= PIXEL_HEIGHT(VT_FB_MAX_HEIGHT) * 410 PIXEL_WIDTH(VT_FB_MAX_WIDTH)) 411 continue; 412 if (vd->vd_drawn && (vd->vd_drawn[z] == c) && 413 vd->vd_drawnfg && (vd->vd_drawnfg[z] == fg) && 414 vd->vd_drawnbg && (vd->vd_drawnbg[z] == bg)) 415 continue; 416 417 vt_fb_bitblt_bitmap(vd, vw, 418 pattern, NULL, vf->vf_width, vf->vf_height, 419 x, y, fg, bg); 420 421 if (vd->vd_drawn) 422 vd->vd_drawn[z] = c; 423 if (vd->vd_drawnfg) 424 vd->vd_drawnfg[z] = fg; 425 if (vd->vd_drawnbg) 426 vd->vd_drawnbg[z] = bg; 427 } 428 } 429 430 #ifndef SC_NO_CUTPASTE 431 if (!vd->vd_mshown) 432 return; 433 434 term_rect_t drawn_area; 435 436 drawn_area.tr_begin.tp_col = area->tr_begin.tp_col * vf->vf_width; 437 drawn_area.tr_begin.tp_row = area->tr_begin.tp_row * vf->vf_height; 438 drawn_area.tr_end.tp_col = area->tr_end.tp_col * vf->vf_width; 439 drawn_area.tr_end.tp_row = area->tr_end.tp_row * vf->vf_height; 440 441 if (vt_is_cursor_in_area(vd, &drawn_area)) { 442 vt_fb_bitblt_bitmap(vd, vw, 443 vd->vd_mcursor->map, vd->vd_mcursor->mask, 444 vd->vd_mcursor->width, vd->vd_mcursor->height, 445 vd->vd_mx_drawn + vw->vw_draw_area.tr_begin.tp_col, 446 vd->vd_my_drawn + vw->vw_draw_area.tr_begin.tp_row, 447 vd->vd_mcursor_fg, vd->vd_mcursor_bg); 448 } 449 #endif 450 } 451 452 void 453 vt_fb_invalidate_text(struct vt_device *vd, const term_rect_t *area) 454 { 455 unsigned int col, row; 456 size_t z; 457 458 for (row = area->tr_begin.tp_row; row < area->tr_end.tp_row; ++row) { 459 for (col = area->tr_begin.tp_col; col < area->tr_end.tp_col; 460 ++col) { 461 z = row * PIXEL_WIDTH(VT_FB_MAX_WIDTH) + col; 462 if (z >= PIXEL_HEIGHT(VT_FB_MAX_HEIGHT) * 463 PIXEL_WIDTH(VT_FB_MAX_WIDTH)) 464 continue; 465 if (vd->vd_drawn) 466 vd->vd_drawn[z] = 0; 467 if (vd->vd_drawnfg) 468 vd->vd_drawnfg[z] = 0; 469 if (vd->vd_drawnbg) 470 vd->vd_drawnbg[z] = 0; 471 } 472 } 473 } 474 475 void 476 vt_fb_postswitch(struct vt_device *vd) 477 { 478 struct fb_info *info; 479 480 info = vd->vd_softc; 481 482 if (info->enter != NULL) 483 info->enter(info->fb_priv); 484 } 485 486 static int 487 vt_fb_init_colors(struct fb_info *info) 488 { 489 490 switch (FBTYPE_GET_BPP(info)) { 491 case 8: 492 return (vt_config_cons_colors(info, COLOR_FORMAT_RGB, 493 0x7, 5, 0x7, 2, 0x3, 0)); 494 case 15: 495 return (vt_config_cons_colors(info, COLOR_FORMAT_RGB, 496 0x1f, 10, 0x1f, 5, 0x1f, 0)); 497 case 16: 498 return (vt_config_cons_colors(info, COLOR_FORMAT_RGB, 499 0x1f, 11, 0x3f, 5, 0x1f, 0)); 500 case 24: 501 case 32: /* Ignore alpha. */ 502 return (vt_config_cons_colors(info, COLOR_FORMAT_RGB, 503 0xff, 16, 0xff, 8, 0xff, 0)); 504 default: 505 return (1); 506 } 507 } 508 509 int 510 vt_fb_init(struct vt_device *vd) 511 { 512 struct fb_info *info; 513 u_int margin; 514 int bg, err; 515 term_color_t c; 516 517 info = vd->vd_softc; 518 vd->vd_height = MIN(VT_FB_MAX_HEIGHT, info->fb_height); 519 margin = (info->fb_height - vd->vd_height) >> 1; 520 vd->vd_transpose = margin * info->fb_stride; 521 vd->vd_width = MIN(VT_FB_MAX_WIDTH, info->fb_width); 522 margin = (info->fb_width - vd->vd_width) >> 1; 523 vd->vd_transpose += margin * (info->fb_bpp / NBBY); 524 vd->vd_video_dev = info->fb_video_dev; 525 526 if (info->fb_size == 0) 527 return (CN_DEAD); 528 529 if (info->fb_pbase == 0 && info->fb_vbase == 0) 530 info->fb_flags |= FB_FLAG_NOMMAP; 531 532 if (info->fb_cmsize <= 0) { 533 err = vt_fb_init_colors(info); 534 if (err) 535 return (CN_DEAD); 536 info->fb_cmsize = 16; 537 } 538 539 c = TC_BLACK; 540 if (TUNABLE_INT_FETCH("teken.bg_color", &bg) != 0) { 541 if (bg == TC_WHITE) 542 bg |= TC_LIGHT; 543 c = bg; 544 } 545 /* Clear the screen. */ 546 vd->vd_driver->vd_blank(vd, c); 547 548 /* Wakeup screen. KMS need this. */ 549 vt_fb_postswitch(vd); 550 551 return (CN_INTERNAL); 552 } 553 554 void 555 vt_fb_fini(struct vt_device *vd, void *softc) 556 { 557 558 vd->vd_video_dev = NULL; 559 } 560 561 int 562 vt_fb_attach(struct fb_info *info) 563 { 564 int ret; 565 566 ret = vt_allocate(&vt_fb_driver, info); 567 568 return (ret); 569 } 570 571 int 572 vt_fb_detach(struct fb_info *info) 573 { 574 int ret; 575 576 ret = vt_deallocate(&vt_fb_driver, info); 577 578 return (ret); 579 } 580 581 void 582 vt_fb_suspend(struct vt_device *vd) 583 { 584 585 vt_suspend(vd); 586 } 587 588 void 589 vt_fb_resume(struct vt_device *vd) 590 { 591 592 vt_resume(vd); 593 } 594