vt_fb.c revision 271769
1163953Srrs/*- 2185694Srrs * Copyright (c) 2013 The FreeBSD Foundation 3235828Stuexen * All rights reserved. 4235828Stuexen * 5163953Srrs * This software was developed by Aleksandr Rybalko under sponsorship from the 6163953Srrs * FreeBSD Foundation. 7163953Srrs * 8163953Srrs * Redistribution and use in source and binary forms, with or without 9163953Srrs * modification, are permitted provided that the following conditions 10228653Stuexen * are met: 11163953Srrs * 1. Redistributions of source code must retain the above copyright 12163953Srrs * notice, this list of conditions and the following disclaimer. 13163953Srrs * 2. Redistributions in binary form must reproduce the above copyright 14228653Stuexen * notice, this list of conditions and the following disclaimer in the 15163953Srrs * documentation and/or other materials provided with the distribution. 16163953Srrs * 17163953Srrs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18163953Srrs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19163953Srrs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20163953Srrs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21163953Srrs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22163953Srrs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23163953Srrs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24163953Srrs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25163953Srrs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26163953Srrs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27163953Srrs * SUCH DAMAGE. 28163953Srrs * 29163953Srrs * $FreeBSD: stable/10/sys/dev/vt/hw/fb/vt_fb.c 271769 2014-09-18 14:38:18Z dumbbell $ 30163953Srrs */ 31163953Srrs 32163953Srrs#include <sys/cdefs.h> 33163953Srrs__FBSDID("$FreeBSD: stable/10/sys/dev/vt/hw/fb/vt_fb.c 271769 2014-09-18 14:38:18Z dumbbell $"); 34163953Srrs 35163953Srrs#include <sys/param.h> 36235828Stuexen#include <sys/systm.h> 37235828Stuexen#include <sys/malloc.h> 38163953Srrs#include <sys/queue.h> 39267724Stuexen#include <sys/fbio.h> 40179157Srrs#include <dev/vt/vt.h> 41267724Stuexen#include <dev/vt/hw/fb/vt_fb.h> 42267724Stuexen#include <dev/vt/colors/vt_termcolors.h> 43167598Srrs 44167598Srrsstatic struct vt_driver vt_fb_driver = { 45163953Srrs .vd_name = "fb", 46167598Srrs .vd_init = vt_fb_init, 47168299Srrs .vd_blank = vt_fb_blank, 48167598Srrs .vd_bitblt_text = vt_fb_bitblt_text, 49167598Srrs .vd_bitblt_bmp = vt_fb_bitblt_bitmap, 50167598Srrs .vd_drawrect = vt_fb_drawrect, 51167598Srrs .vd_setpixel = vt_fb_setpixel, 52168299Srrs .vd_postswitch = vt_fb_postswitch, 53168299Srrs .vd_priority = VD_PRIORITY_GENERIC+10, 54167598Srrs .vd_fb_ioctl = vt_fb_ioctl, 55167598Srrs .vd_fb_mmap = vt_fb_mmap, 56167598Srrs}; 57168299Srrs 58168299SrrsVT_DRIVER_DECLARE(vt_fb, vt_fb_driver); 59168299Srrs 60168299Srrsstatic void 61167598Srrsvt_fb_mem_wr1(struct fb_info *sc, uint32_t o, uint8_t v) 62168299Srrs{ 63167598Srrs 64171990Srrs KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 65171990Srrs *(uint8_t *)(sc->fb_vbase + o) = v; 66171990Srrs} 67171990Srrs 68171990Srrsstatic void 69294157Stuexenvt_fb_mem_wr2(struct fb_info *sc, uint32_t o, uint16_t v) 70294157Stuexen{ 71167598Srrs 72167598Srrs KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 73167598Srrs *(uint16_t *)(sc->fb_vbase + o) = v; 74170056Srrs} 75170181Srrs 76170056Srrsstatic void 77167598Srrsvt_fb_mem_wr4(struct fb_info *sc, uint32_t o, uint32_t v) 78167598Srrs{ 79167598Srrs 80167598Srrs KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 81167598Srrs *(uint32_t *)(sc->fb_vbase + o) = v; 82163953Srrs} 83163953Srrs 84163953Srrsint 85163953Srrsvt_fb_ioctl(struct vt_device *vd, u_long cmd, caddr_t data, struct thread *td) 86167598Srrs{ 87167598Srrs struct fb_info *info; 88199866Stuexen int error = 0; 89167598Srrs 90218211Srrs info = vd->vd_softc; 91167598Srrs 92218211Srrs switch (cmd) { 93167598Srrs case FBIOGTYPE: 94167598Srrs bcopy(info, (struct fbtype *)data, sizeof(struct fbtype)); 95167598Srrs break; 96167598Srrs 97167598Srrs case FBIO_GETWINORG: /* get frame buffer window origin */ 98171477Srrs *(u_int *)data = 0; 99171477Srrs break; 100171477Srrs 101171477Srrs case FBIO_GETDISPSTART: /* get display start address */ 102171440Srrs ((video_display_start_t *)data)->x = 0; 103171440Srrs ((video_display_start_t *)data)->y = 0; 104171440Srrs break; 105171440Srrs 106171440Srrs case FBIO_GETLINEWIDTH: /* get scan line width in bytes */ 107163953Srrs *(u_int *)data = info->fb_stride; 108163953Srrs break; 109163953Srrs 110163953Srrs case FBIO_BLANK: /* blank display */ 111163953Srrs if (vd->vd_driver->vd_blank == NULL) 112163953Srrs return (ENODEV); 113163953Srrs vd->vd_driver->vd_blank(vd, TC_BLACK); 114163953Srrs break; 115163953Srrs 116163953Srrs default: 117163953Srrs error = ENOIOCTL; 118163953Srrs break; 119163953Srrs } 120163953Srrs 121163953Srrs return (error); 122163953Srrs} 123163953Srrs 124163953Srrsint 125163953Srrsvt_fb_mmap(struct vt_device *vd, vm_ooffset_t offset, vm_paddr_t *paddr, 126163953Srrs int prot, vm_memattr_t *memattr) 127163953Srrs{ 128163953Srrs struct fb_info *info; 129163953Srrs 130163953Srrs info = vd->vd_softc; 131163953Srrs 132163953Srrs if (info->fb_flags & FB_FLAG_NOMMAP) 133163953Srrs return (ENODEV); 134163953Srrs 135163953Srrs if (offset >= 0 && offset < info->fb_size) { 136163953Srrs *paddr = info->fb_pbase + offset; 137163953Srrs #ifdef VM_MEMATTR_WRITE_COMBINING 138163953Srrs *memattr = VM_MEMATTR_WRITE_COMBINING; 139163953Srrs #endif 140163953Srrs return (0); 141163953Srrs } 142163953Srrs 143163953Srrs return (EINVAL); 144163953Srrs} 145163953Srrs 146163953Srrsvoid 147163953Srrsvt_fb_setpixel(struct vt_device *vd, int x, int y, term_color_t color) 148163953Srrs{ 149163953Srrs struct fb_info *info; 150163953Srrs uint32_t c; 151163953Srrs u_int o; 152163953Srrs 153163953Srrs info = vd->vd_softc; 154163953Srrs c = info->fb_cmap[color]; 155163953Srrs o = info->fb_stride * y + x * FBTYPE_GET_BYTESPP(info); 156163953Srrs 157163953Srrs KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer")); 158163953Srrs 159163953Srrs switch (FBTYPE_GET_BYTESPP(info)) { 160163953Srrs case 1: 161163953Srrs vt_fb_mem_wr1(info, o, c); 162163953Srrs break; 163163953Srrs case 2: 164163953Srrs vt_fb_mem_wr2(info, o, c); 165163953Srrs break; 166163953Srrs case 3: 167163953Srrs vt_fb_mem_wr1(info, o, (c >> 16) & 0xff); 168163953Srrs vt_fb_mem_wr1(info, o + 1, (c >> 8) & 0xff); 169163953Srrs vt_fb_mem_wr1(info, o + 2, c & 0xff); 170163953Srrs break; 171163953Srrs case 4: 172163953Srrs vt_fb_mem_wr4(info, o, c); 173163953Srrs break; 174163953Srrs default: 175163953Srrs /* panic? */ 176163953Srrs return; 177163953Srrs } 178163953Srrs 179163953Srrs} 180163953Srrs 181163953Srrsvoid 182163953Srrsvt_fb_drawrect(struct vt_device *vd, int x1, int y1, int x2, int y2, int fill, 183163953Srrs term_color_t color) 184163953Srrs{ 185163953Srrs int x, y; 186163953Srrs 187163953Srrs for (y = y1; y <= y2; y++) { 188163953Srrs if (fill || (y == y1) || (y == y2)) { 189163953Srrs for (x = x1; x <= x2; x++) 190163953Srrs vt_fb_setpixel(vd, x, y, color); 191163953Srrs } else { 192163953Srrs vt_fb_setpixel(vd, x1, y, color); 193163953Srrs vt_fb_setpixel(vd, x2, y, color); 194163953Srrs } 195163953Srrs } 196163953Srrs} 197163953Srrs 198163953Srrsvoid 199163953Srrsvt_fb_blank(struct vt_device *vd, term_color_t color) 200178197Srrs{ 201178197Srrs struct fb_info *info; 202178197Srrs uint32_t c; 203178197Srrs u_int o, h; 204178197Srrs 205178197Srrs info = vd->vd_softc; 206178197Srrs c = info->fb_cmap[color]; 207178197Srrs 208178197Srrs KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer")); 209178197Srrs 210178197Srrs switch (FBTYPE_GET_BYTESPP(info)) { 211178197Srrs case 1: 212178197Srrs for (h = 0; h < info->fb_height; h++) 213178197Srrs for (o = 0; o < info->fb_stride; o++) 214178197Srrs vt_fb_mem_wr1(info, h*info->fb_stride + o, c); 215178197Srrs break; 216178197Srrs case 2: 217178197Srrs for (h = 0; h < info->fb_height; h++) 218178197Srrs for (o = 0; o < info->fb_stride; o += 2) 219178197Srrs vt_fb_mem_wr2(info, h*info->fb_stride + o, c); 220178197Srrs break; 221178197Srrs case 3: 222178197Srrs for (h = 0; h < info->fb_height; h++) 223178197Srrs for (o = 0; o < info->fb_stride; o += 3) { 224178197Srrs vt_fb_mem_wr1(info, h*info->fb_stride + o, 225178197Srrs (c >> 16) & 0xff); 226178197Srrs vt_fb_mem_wr1(info, h*info->fb_stride + o + 1, 227178197Srrs (c >> 8) & 0xff); 228189371Srrs vt_fb_mem_wr1(info, h*info->fb_stride + o + 2, 229189790Srrs c & 0xff); 230189790Srrs } 231163953Srrs break; 232170744Srrs case 4: 233170744Srrs for (h = 0; h < info->fb_height; h++) 234170744Srrs for (o = 0; o < info->fb_stride; o += 4) 235170744Srrs vt_fb_mem_wr4(info, h*info->fb_stride + o, c); 236163953Srrs break; 237170744Srrs default: 238170744Srrs /* panic? */ 239163953Srrs return; 240171943Srrs } 241163953Srrs} 242163953Srrs 243163953Srrsvoid 244163953Srrsvt_fb_bitblt_bitmap(struct vt_device *vd, const struct vt_window *vw, 245163953Srrs const uint8_t *pattern, const uint8_t *mask, 246163953Srrs unsigned int width, unsigned int height, 247163953Srrs unsigned int x, unsigned int y, term_color_t fg, term_color_t bg) 248163953Srrs{ 249163953Srrs struct fb_info *info; 250163953Srrs uint32_t fgc, bgc, cc, o; 251163953Srrs int c, l, bpp, bpl; 252163953Srrs u_long line; 253163953Srrs uint8_t b, m; 254163953Srrs const uint8_t *ch; 255163953Srrs 256163953Srrs info = vd->vd_softc; 257163953Srrs bpp = FBTYPE_GET_BYTESPP(info); 258163953Srrs fgc = info->fb_cmap[fg]; 259170744Srrs bgc = info->fb_cmap[bg]; 260170744Srrs b = m = 0; 261163953Srrs bpl = (width + 7) >> 3; /* Bytes per source line. */ 262170744Srrs 263163953Srrs KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer")); 264163953Srrs 265163953Srrs line = (info->fb_stride * y) + (x * bpp); 266163953Srrs for (l = 0; 267163953Srrs l < height && y + l < vw->vw_draw_area.tr_end.tp_row; 268163953Srrs l++) { 269163953Srrs ch = pattern; 270163953Srrs for (c = 0; 271163953Srrs c < width && x + c < vw->vw_draw_area.tr_end.tp_col; 272179157Srrs c++) { 273179157Srrs if (c % 8 == 0) 274179157Srrs b = *ch++; 275163953Srrs else 276163953Srrs b <<= 1; 277163953Srrs if (mask != NULL) { 278163953Srrs if (c % 8 == 0) 279163953Srrs m = *mask++; 280163953Srrs else 281163953Srrs m <<= 1; 282163953Srrs /* Skip pixel write, if mask has no bit set. */ 283163953Srrs if ((m & 0x80) == 0) 284163953Srrs continue; 285163953Srrs } 286163953Srrs o = line + (c * bpp); 287163953Srrs cc = b & 0x80 ? fgc : bgc; 288163953Srrs 289163953Srrs switch(bpp) { 290163953Srrs case 1: 291163953Srrs vt_fb_mem_wr1(info, o, cc); 292163953Srrs break; 293163953Srrs case 2: 294163953Srrs vt_fb_mem_wr2(info, o, cc); 295163953Srrs break; 296163953Srrs case 3: 297163953Srrs /* Packed mode, so unaligned. Byte access. */ 298163953Srrs vt_fb_mem_wr1(info, o, (cc >> 16) & 0xff); 299163953Srrs vt_fb_mem_wr1(info, o + 1, (cc >> 8) & 0xff); 300163953Srrs vt_fb_mem_wr1(info, o + 2, cc & 0xff); 301163953Srrs break; 302163953Srrs case 4: 303163953Srrs vt_fb_mem_wr4(info, o, cc); 304163953Srrs break; 305163953Srrs default: 306163953Srrs /* panic? */ 307163953Srrs break; 308163953Srrs } 309163953Srrs } 310163953Srrs line += info->fb_stride; 311163953Srrs pattern += bpl; 312163953Srrs } 313163953Srrs} 314163953Srrs 315163953Srrsvoid 316163953Srrsvt_fb_bitblt_text(struct vt_device *vd, const struct vt_window *vw, 317163953Srrs const term_rect_t *area) 318163953Srrs{ 319163953Srrs unsigned int col, row, x, y; 320163953Srrs struct vt_font *vf; 321163953Srrs term_char_t c; 322163953Srrs term_color_t fg, bg; 323163953Srrs const uint8_t *pattern; 324163953Srrs 325163953Srrs vf = vw->vw_font; 326163953Srrs 327163953Srrs for (row = area->tr_begin.tp_row; row < area->tr_end.tp_row; ++row) { 328163953Srrs for (col = area->tr_begin.tp_col; col < area->tr_end.tp_col; 329163953Srrs ++col) { 330163953Srrs x = col * vf->vf_width + 331163953Srrs vw->vw_draw_area.tr_begin.tp_col; 332163953Srrs y = row * vf->vf_height + 333163953Srrs vw->vw_draw_area.tr_begin.tp_row; 334163953Srrs 335217913Stuexen c = VTBUF_GET_FIELD(&vw->vw_buf, row, col); 336235557Stuexen pattern = vtfont_lookup(vf, c); 337218186Srrs vt_determine_colors(c, 338218186Srrs VTBUF_ISCURSOR(&vw->vw_buf, row, col), &fg, &bg); 339218186Srrs 340218186Srrs vt_fb_bitblt_bitmap(vd, vw, 341218186Srrs pattern, NULL, vf->vf_width, vf->vf_height, 342218186Srrs x, y, fg, bg); 343219397Srrs } 344219397Srrs } 345218186Srrs 346218186Srrs#ifndef SC_NO_CUTPASTE 347163953Srrs if (!vd->vd_mshown) 348163953Srrs return; 349163953Srrs 350163953Srrs term_rect_t drawn_area; 351163953Srrs 352163953Srrs drawn_area.tr_begin.tp_col = area->tr_begin.tp_col * vf->vf_width; 353163953Srrs drawn_area.tr_begin.tp_row = area->tr_begin.tp_row * vf->vf_height; 354163953Srrs drawn_area.tr_end.tp_col = area->tr_end.tp_col * vf->vf_width; 355163953Srrs drawn_area.tr_end.tp_row = area->tr_end.tp_row * vf->vf_height; 356163953Srrs 357163953Srrs if (vt_is_cursor_in_area(vd, &drawn_area)) { 358163953Srrs vt_fb_bitblt_bitmap(vd, vw, 359163953Srrs vd->vd_mcursor->map, vd->vd_mcursor->mask, 360243157Stuexen vd->vd_mcursor->width, vd->vd_mcursor->height, 361163953Srrs vd->vd_mx_drawn + vw->vw_draw_area.tr_begin.tp_col, 362163953Srrs vd->vd_my_drawn + vw->vw_draw_area.tr_begin.tp_row, 363163953Srrs vd->vd_mcursor_fg, vd->vd_mcursor_bg); 364163953Srrs } 365163953Srrs#endif 366163953Srrs} 367163953Srrs 368163953Srrsvoid 369163953Srrsvt_fb_postswitch(struct vt_device *vd) 370163953Srrs{ 371163953Srrs struct fb_info *info; 372163953Srrs 373163953Srrs info = vd->vd_softc; 374163953Srrs 375163953Srrs if (info->enter != NULL) 376163953Srrs info->enter(info->fb_priv); 377164205Srrs} 378167598Srrs 379171990Srrsstatic int 380228391Stuexenvt_fb_init_cmap(uint32_t *cmap, int depth) 381228391Stuexen{ 382163953Srrs 383163953Srrs switch (depth) { 384163953Srrs case 8: 385228907Stuexen return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB, 386163953Srrs 0x7, 5, 0x7, 2, 0x3, 0)); 387163953Srrs case 15: 388163953Srrs return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB, 389163953Srrs 0x1f, 10, 0x1f, 5, 0x1f, 0)); 390163953Srrs case 16: 391163953Srrs return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB, 392163953Srrs 0x1f, 11, 0x3f, 5, 0x1f, 0)); 393163953Srrs case 24: 394163953Srrs case 32: /* Ignore alpha. */ 395163953Srrs return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB, 396163953Srrs 0xff, 16, 0xff, 8, 0xff, 0)); 397163953Srrs default: 398163953Srrs return (1); 399163953Srrs } 400163953Srrs} 401163953Srrs 402188854Srrsint 403163953Srrsvt_fb_init(struct vt_device *vd) 404163953Srrs{ 405163953Srrs struct fb_info *info; 406163953Srrs int err; 407233660Srrs 408233660Srrs info = vd->vd_softc; 409163953Srrs vd->vd_height = info->fb_height; 410163953Srrs vd->vd_width = info->fb_width; 411163953Srrs 412163953Srrs if (info->fb_size == 0) 413163953Srrs return (CN_DEAD); 414163953Srrs 415163953Srrs if (info->fb_pbase == 0) 416163953Srrs info->fb_flags |= FB_FLAG_NOMMAP; 417218129Srrs 418163953Srrs if (info->fb_cmsize <= 0) { 419163953Srrs err = vt_fb_init_cmap(info->fb_cmap, FBTYPE_GET_BPP(info)); 420163953Srrs if (err) 421163953Srrs return (CN_DEAD); 422163953Srrs info->fb_cmsize = 16; 423163953Srrs } 424163953Srrs 425163953Srrs /* Clear the screen. */ 426163953Srrs vd->vd_driver->vd_blank(vd, TC_BLACK); 427163953Srrs 428163953Srrs /* Wakeup screen. KMS need this. */ 429163953Srrs vt_fb_postswitch(vd); 430163953Srrs 431163953Srrs return (CN_INTERNAL); 432163953Srrs} 433163953Srrs 434163953Srrsint 435163953Srrsvt_fb_attach(struct fb_info *info) 436163953Srrs{ 437163953Srrs 438163953Srrs vt_allocate(&vt_fb_driver, info); 439163953Srrs 440163953Srrs return (0); 441163953Srrs} 442163953Srrs 443163953Srrsvoid 444163953Srrsvt_fb_resume(void) 445185694Srrs{ 446185694Srrs 447185694Srrs vt_resume(); 448163953Srrs} 449163953Srrs 450163953Srrsvoid 451163953Srrsvt_fb_suspend(void) 452163953Srrs{ 453163953Srrs 454163953Srrs vt_suspend(); 455163953Srrs} 456163953Srrs