vt_fb.c revision 270431
1256904Sray/*- 2256904Sray * Copyright (c) 2013 The FreeBSD Foundation 3256904Sray * All rights reserved. 4256904Sray * 5256904Sray * This software was developed by Aleksandr Rybalko under sponsorship from the 6256904Sray * FreeBSD Foundation. 7256904Sray * 8256904Sray * Redistribution and use in source and binary forms, with or without 9256904Sray * modification, are permitted provided that the following conditions 10256904Sray * are met: 11256904Sray * 1. Redistributions of source code must retain the above copyright 12256904Sray * notice, this list of conditions and the following disclaimer. 13256904Sray * 2. Redistributions in binary form must reproduce the above copyright 14256904Sray * notice, this list of conditions and the following disclaimer in the 15256904Sray * documentation and/or other materials provided with the distribution. 16256904Sray * 17256904Sray * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18256904Sray * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19256904Sray * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20256904Sray * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21256904Sray * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22256904Sray * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23256904Sray * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24256904Sray * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25256904Sray * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26256904Sray * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27256904Sray * SUCH DAMAGE. 28256904Sray * 29256904Sray * $FreeBSD: head/sys/dev/vt/hw/fb/vt_fb.c 270431 2014-08-23 20:35:33Z dumbbell $ 30256904Sray */ 31256904Sray 32256904Sray#include <sys/cdefs.h> 33256904Sray__FBSDID("$FreeBSD: head/sys/dev/vt/hw/fb/vt_fb.c 270431 2014-08-23 20:35:33Z dumbbell $"); 34256904Sray 35256904Sray#include <sys/param.h> 36256904Sray#include <sys/systm.h> 37256904Sray#include <sys/malloc.h> 38256904Sray#include <sys/queue.h> 39256904Sray#include <sys/fbio.h> 40256904Sray#include <dev/vt/vt.h> 41256904Sray#include <dev/vt/hw/fb/vt_fb.h> 42256904Sray#include <dev/vt/colors/vt_termcolors.h> 43256904Sray 44270411Sdumbbellstatic vd_drawrect_t vt_fb_drawrect; 45270411Sdumbbellstatic vd_setpixel_t vt_fb_setpixel; 46259777Sray 47256904Sraystatic struct vt_driver vt_fb_driver = { 48265397Sray .vd_name = "fb", 49256904Sray .vd_init = vt_fb_init, 50256904Sray .vd_blank = vt_fb_blank, 51270411Sdumbbell .vd_bitblt_text = vt_fb_bitblt_text, 52270431Sdumbbell .vd_bitblt_bmp = vt_fb_bitblt_bitmap, 53261552Sray .vd_drawrect = vt_fb_drawrect, 54261552Sray .vd_setpixel = vt_fb_setpixel, 55256904Sray .vd_postswitch = vt_fb_postswitch, 56256904Sray .vd_priority = VD_PRIORITY_GENERIC+10, 57259777Sray .vd_fb_ioctl = vt_fb_ioctl, 58259777Sray .vd_fb_mmap = vt_fb_mmap, 59256904Sray}; 60256904Sray 61265397SrayVT_DRIVER_DECLARE(vt_fb, vt_fb_driver); 62265397Sray 63269620Snwhitehornstatic void 64269620Snwhitehornvt_fb_mem_wr1(struct fb_info *sc, uint32_t o, uint8_t v) 65269620Snwhitehorn{ 66269620Snwhitehorn 67269620Snwhitehorn KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 68269620Snwhitehorn *(uint8_t *)(sc->fb_vbase + o) = v; 69269620Snwhitehorn} 70269620Snwhitehorn 71269620Snwhitehornstatic void 72269620Snwhitehornvt_fb_mem_wr2(struct fb_info *sc, uint32_t o, uint16_t v) 73269620Snwhitehorn{ 74269620Snwhitehorn 75269620Snwhitehorn KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 76269620Snwhitehorn *(uint16_t *)(sc->fb_vbase + o) = v; 77269620Snwhitehorn} 78269620Snwhitehorn 79269620Snwhitehornstatic void 80269620Snwhitehornvt_fb_mem_wr4(struct fb_info *sc, uint32_t o, uint32_t v) 81269620Snwhitehorn{ 82269620Snwhitehorn 83269620Snwhitehorn KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 84269620Snwhitehorn *(uint32_t *)(sc->fb_vbase + o) = v; 85269620Snwhitehorn} 86269620Snwhitehorn 87268771Snwhitehornint 88259777Srayvt_fb_ioctl(struct vt_device *vd, u_long cmd, caddr_t data, struct thread *td) 89259777Sray{ 90259777Sray struct fb_info *info; 91268771Snwhitehorn int error = 0; 92259777Sray 93259777Sray info = vd->vd_softc; 94259777Sray 95268771Snwhitehorn switch (cmd) { 96268771Snwhitehorn case FBIOGTYPE: 97268771Snwhitehorn bcopy(info, (struct fbtype *)data, sizeof(struct fbtype)); 98268771Snwhitehorn break; 99259777Sray 100268771Snwhitehorn case FBIO_GETWINORG: /* get frame buffer window origin */ 101268771Snwhitehorn *(u_int *)data = 0; 102268771Snwhitehorn break; 103268771Snwhitehorn 104268771Snwhitehorn case FBIO_GETDISPSTART: /* get display start address */ 105268771Snwhitehorn ((video_display_start_t *)data)->x = 0; 106268771Snwhitehorn ((video_display_start_t *)data)->y = 0; 107268771Snwhitehorn break; 108268771Snwhitehorn 109268771Snwhitehorn case FBIO_GETLINEWIDTH: /* get scan line width in bytes */ 110268771Snwhitehorn *(u_int *)data = info->fb_stride; 111268771Snwhitehorn break; 112268771Snwhitehorn 113268771Snwhitehorn case FBIO_BLANK: /* blank display */ 114268771Snwhitehorn if (vd->vd_driver->vd_blank == NULL) 115268771Snwhitehorn return (ENODEV); 116268771Snwhitehorn vd->vd_driver->vd_blank(vd, TC_BLACK); 117268771Snwhitehorn break; 118268771Snwhitehorn 119268771Snwhitehorn default: 120268771Snwhitehorn error = ENOIOCTL; 121268771Snwhitehorn break; 122268771Snwhitehorn } 123268771Snwhitehorn 124268771Snwhitehorn return (error); 125259777Sray} 126259777Sray 127268771Snwhitehornint 128260953Srayvt_fb_mmap(struct vt_device *vd, vm_ooffset_t offset, vm_paddr_t *paddr, 129260953Sray int prot, vm_memattr_t *memattr) 130259777Sray{ 131259777Sray struct fb_info *info; 132259777Sray 133259777Sray info = vd->vd_softc; 134259777Sray 135268771Snwhitehorn if (info->fb_flags & FB_FLAG_NOMMAP) 136268771Snwhitehorn return (ENODEV); 137259777Sray 138268771Snwhitehorn if (offset >= 0 && offset < info->fb_size) { 139268771Snwhitehorn *paddr = info->fb_pbase + offset; 140268771Snwhitehorn #ifdef VM_MEMATTR_WRITE_COMBINING 141268771Snwhitehorn *memattr = VM_MEMATTR_WRITE_COMBINING; 142268771Snwhitehorn #endif 143268771Snwhitehorn return (0); 144268771Snwhitehorn } 145268771Snwhitehorn 146268771Snwhitehorn return (EINVAL); 147259777Sray} 148259777Sray 149270411Sdumbbellstatic void 150261552Srayvt_fb_setpixel(struct vt_device *vd, int x, int y, term_color_t color) 151261552Sray{ 152261552Sray struct fb_info *info; 153261552Sray uint32_t c; 154261552Sray u_int o; 155261552Sray 156261552Sray info = vd->vd_softc; 157261552Sray c = info->fb_cmap[color]; 158261552Sray o = info->fb_stride * y + x * FBTYPE_GET_BYTESPP(info); 159261552Sray 160269620Snwhitehorn KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer")); 161269620Snwhitehorn 162261552Sray switch (FBTYPE_GET_BYTESPP(info)) { 163261552Sray case 1: 164269620Snwhitehorn vt_fb_mem_wr1(info, o, c); 165261552Sray break; 166261552Sray case 2: 167269620Snwhitehorn vt_fb_mem_wr2(info, o, c); 168261552Sray break; 169261552Sray case 3: 170269620Snwhitehorn vt_fb_mem_wr1(info, o, (c >> 16) & 0xff); 171269620Snwhitehorn vt_fb_mem_wr1(info, o + 1, (c >> 8) & 0xff); 172269620Snwhitehorn vt_fb_mem_wr1(info, o + 2, c & 0xff); 173261552Sray break; 174261552Sray case 4: 175269620Snwhitehorn vt_fb_mem_wr4(info, o, c); 176261552Sray break; 177261552Sray default: 178261552Sray /* panic? */ 179261552Sray return; 180261552Sray } 181261552Sray 182261552Sray} 183261552Sray 184270411Sdumbbellstatic void 185261552Srayvt_fb_drawrect(struct vt_device *vd, int x1, int y1, int x2, int y2, int fill, 186261552Sray term_color_t color) 187261552Sray{ 188261552Sray int x, y; 189261552Sray 190261552Sray for (y = y1; y <= y2; y++) { 191261552Sray if (fill || (y == y1) || (y == y2)) { 192261552Sray for (x = x1; x <= x2; x++) 193261552Sray vt_fb_setpixel(vd, x, y, color); 194261552Sray } else { 195261552Sray vt_fb_setpixel(vd, x1, y, color); 196261552Sray vt_fb_setpixel(vd, x2, y, color); 197261552Sray } 198261552Sray } 199261552Sray} 200261552Sray 201261552Srayvoid 202256904Srayvt_fb_blank(struct vt_device *vd, term_color_t color) 203256904Sray{ 204256904Sray struct fb_info *info; 205256904Sray uint32_t c; 206268771Snwhitehorn u_int o, h; 207256904Sray 208256904Sray info = vd->vd_softc; 209256904Sray c = info->fb_cmap[color]; 210257725Sray 211269620Snwhitehorn KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer")); 212269620Snwhitehorn 213256904Sray switch (FBTYPE_GET_BYTESPP(info)) { 214256904Sray case 1: 215268796Snwhitehorn for (h = 0; h < info->fb_height; h++) 216268771Snwhitehorn for (o = 0; o < info->fb_stride; o++) 217269620Snwhitehorn vt_fb_mem_wr1(info, h*info->fb_stride + o, c); 218256904Sray break; 219256904Sray case 2: 220268796Snwhitehorn for (h = 0; h < info->fb_height; h++) 221268771Snwhitehorn for (o = 0; o < info->fb_stride; o += 2) 222269620Snwhitehorn vt_fb_mem_wr2(info, h*info->fb_stride + o, c); 223256904Sray break; 224256904Sray case 3: 225268796Snwhitehorn for (h = 0; h < info->fb_height; h++) 226268771Snwhitehorn for (o = 0; o < info->fb_stride; o += 3) { 227269620Snwhitehorn vt_fb_mem_wr1(info, h*info->fb_stride + o, 228268771Snwhitehorn (c >> 16) & 0xff); 229269620Snwhitehorn vt_fb_mem_wr1(info, h*info->fb_stride + o + 1, 230268771Snwhitehorn (c >> 8) & 0xff); 231269620Snwhitehorn vt_fb_mem_wr1(info, h*info->fb_stride + o + 2, 232268771Snwhitehorn c & 0xff); 233268771Snwhitehorn } 234256904Sray break; 235256904Sray case 4: 236268796Snwhitehorn for (h = 0; h < info->fb_height; h++) 237268771Snwhitehorn for (o = 0; o < info->fb_stride; o += 4) 238269620Snwhitehorn vt_fb_mem_wr4(info, h*info->fb_stride + o, c); 239256904Sray break; 240256904Sray default: 241256904Sray /* panic? */ 242256904Sray return; 243256904Sray } 244256904Sray} 245256904Sray 246270431Sdumbbellvoid 247270411Sdumbbellvt_fb_bitblt_bitmap(struct vt_device *vd, const struct vt_window *vw, 248270411Sdumbbell const uint8_t *pattern, const uint8_t *mask, 249270411Sdumbbell unsigned int width, unsigned int height, 250270411Sdumbbell unsigned int x, unsigned int y, term_color_t fg, term_color_t bg) 251256904Sray{ 252256904Sray struct fb_info *info; 253256904Sray uint32_t fgc, bgc, cc, o; 254270411Sdumbbell int c, l, bpp, bpl; 255256904Sray u_long line; 256257988Sray uint8_t b, m; 257257988Sray const uint8_t *ch; 258256904Sray 259256904Sray info = vd->vd_softc; 260256904Sray bpp = FBTYPE_GET_BYTESPP(info); 261256904Sray fgc = info->fb_cmap[fg]; 262256904Sray bgc = info->fb_cmap[bg]; 263258781Snwhitehorn b = m = 0; 264270411Sdumbbell bpl = (width + 7) >> 3; /* Bytes per source line. */ 265256904Sray 266257988Sray /* Don't try to put off screen pixels */ 267270411Sdumbbell if (((x + width) > info->fb_width) || ((y + height) > 268257988Sray info->fb_height)) 269257988Sray return; 270257988Sray 271269620Snwhitehorn KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer")); 272269620Snwhitehorn 273270411Sdumbbell line = (info->fb_stride * y) + (x * bpp); 274256904Sray for (l = 0; l < height; l++) { 275270411Sdumbbell ch = pattern; 276256904Sray for (c = 0; c < width; c++) { 277256904Sray if (c % 8 == 0) 278257988Sray b = *ch++; 279256904Sray else 280256904Sray b <<= 1; 281257988Sray if (mask != NULL) { 282257988Sray if (c % 8 == 0) 283257988Sray m = *mask++; 284257988Sray else 285257988Sray m <<= 1; 286257988Sray /* Skip pixel write, if mask has no bit set. */ 287257988Sray if ((m & 0x80) == 0) 288257988Sray continue; 289257988Sray } 290256904Sray o = line + (c * bpp); 291256904Sray cc = b & 0x80 ? fgc : bgc; 292256904Sray 293256904Sray switch(bpp) { 294256904Sray case 1: 295269620Snwhitehorn vt_fb_mem_wr1(info, o, cc); 296256904Sray break; 297256904Sray case 2: 298269620Snwhitehorn vt_fb_mem_wr2(info, o, cc); 299256904Sray break; 300256904Sray case 3: 301256904Sray /* Packed mode, so unaligned. Byte access. */ 302269620Snwhitehorn vt_fb_mem_wr1(info, o, (cc >> 16) & 0xff); 303269620Snwhitehorn vt_fb_mem_wr1(info, o + 1, (cc >> 8) & 0xff); 304269620Snwhitehorn vt_fb_mem_wr1(info, o + 2, cc & 0xff); 305256904Sray break; 306256904Sray case 4: 307269620Snwhitehorn vt_fb_mem_wr4(info, o, cc); 308256904Sray break; 309256904Sray default: 310256904Sray /* panic? */ 311256904Sray break; 312256904Sray } 313256904Sray } 314256904Sray line += info->fb_stride; 315270411Sdumbbell pattern += bpl; 316256904Sray } 317256904Sray} 318256904Sray 319257725Srayvoid 320270411Sdumbbellvt_fb_bitblt_text(struct vt_device *vd, const struct vt_window *vw, 321270411Sdumbbell const term_rect_t *area) 322270411Sdumbbell{ 323270411Sdumbbell unsigned int col, row, x, y; 324270411Sdumbbell struct vt_font *vf; 325270411Sdumbbell term_char_t c; 326270411Sdumbbell term_color_t fg, bg; 327270411Sdumbbell const uint8_t *pattern; 328270411Sdumbbell 329270411Sdumbbell vf = vw->vw_font; 330270411Sdumbbell 331270411Sdumbbell for (row = area->tr_begin.tp_row; row < area->tr_end.tp_row; ++row) { 332270411Sdumbbell for (col = area->tr_begin.tp_col; col < area->tr_end.tp_col; 333270411Sdumbbell ++col) { 334270411Sdumbbell x = col * vf->vf_width + vw->vw_offset.tp_col; 335270411Sdumbbell y = row * vf->vf_height + vw->vw_offset.tp_row; 336270411Sdumbbell 337270411Sdumbbell c = VTBUF_GET_FIELD(&vw->vw_buf, row, col); 338270411Sdumbbell pattern = vtfont_lookup(vf, c); 339270411Sdumbbell vt_determine_colors(c, 340270411Sdumbbell VTBUF_ISCURSOR(&vw->vw_buf, row, col), &fg, &bg); 341270411Sdumbbell 342270411Sdumbbell vt_fb_bitblt_bitmap(vd, vw, 343270411Sdumbbell pattern, NULL, vf->vf_width, vf->vf_height, 344270411Sdumbbell x, y, fg, bg); 345270411Sdumbbell } 346270411Sdumbbell } 347270411Sdumbbell 348270411Sdumbbell#ifndef SC_NO_CUTPASTE 349270411Sdumbbell if (!vd->vd_mshown) 350270411Sdumbbell return; 351270411Sdumbbell 352270411Sdumbbell term_rect_t drawn_area; 353270411Sdumbbell 354270411Sdumbbell drawn_area.tr_begin.tp_col = area->tr_begin.tp_col * vf->vf_width + 355270411Sdumbbell vw->vw_offset.tp_col; 356270411Sdumbbell drawn_area.tr_begin.tp_row = area->tr_begin.tp_row * vf->vf_height + 357270411Sdumbbell vw->vw_offset.tp_row; 358270411Sdumbbell drawn_area.tr_end.tp_col = area->tr_end.tp_col * vf->vf_width + 359270411Sdumbbell vw->vw_offset.tp_col; 360270411Sdumbbell drawn_area.tr_end.tp_row = area->tr_end.tp_row * vf->vf_height + 361270411Sdumbbell vw->vw_offset.tp_row; 362270411Sdumbbell 363270411Sdumbbell if (vt_is_cursor_in_area(vd, &drawn_area)) { 364270411Sdumbbell vt_fb_bitblt_bitmap(vd, vw, 365270411Sdumbbell vd->vd_mcursor->map, vd->vd_mcursor->mask, 366270411Sdumbbell vd->vd_mcursor->width, vd->vd_mcursor->height, 367270411Sdumbbell vd->vd_mx_drawn, vd->vd_my_drawn, 368270411Sdumbbell vd->vd_mcursor_fg, vd->vd_mcursor_bg); 369270411Sdumbbell } 370270411Sdumbbell#endif 371270411Sdumbbell} 372270411Sdumbbell 373270411Sdumbbellvoid 374256904Srayvt_fb_postswitch(struct vt_device *vd) 375256904Sray{ 376256904Sray struct fb_info *info; 377256904Sray 378256904Sray info = vd->vd_softc; 379256904Sray 380256904Sray if (info->enter != NULL) 381256904Sray info->enter(info->fb_priv); 382256904Sray} 383256904Sray 384256904Sraystatic int 385256904Srayvt_fb_init_cmap(uint32_t *cmap, int depth) 386256904Sray{ 387256904Sray 388256904Sray switch (depth) { 389256904Sray case 8: 390269783Sdumbbell return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB, 391256904Sray 0x7, 5, 0x7, 2, 0x3, 0)); 392256904Sray case 15: 393269783Sdumbbell return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB, 394256904Sray 0x1f, 10, 0x1f, 5, 0x1f, 0)); 395256904Sray case 16: 396269783Sdumbbell return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB, 397256904Sray 0x1f, 11, 0x3f, 5, 0x1f, 0)); 398256904Sray case 24: 399256904Sray case 32: /* Ignore alpha. */ 400269783Sdumbbell return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB, 401269783Sdumbbell 0xff, 16, 0xff, 8, 0xff, 0)); 402256904Sray default: 403256904Sray return (1); 404256904Sray } 405256904Sray} 406256904Sray 407257725Srayint 408256904Srayvt_fb_init(struct vt_device *vd) 409256904Sray{ 410256904Sray struct fb_info *info; 411256904Sray int err; 412256904Sray 413256904Sray info = vd->vd_softc; 414256904Sray vd->vd_height = info->fb_height; 415256904Sray vd->vd_width = info->fb_width; 416256904Sray 417269620Snwhitehorn if (info->fb_size == 0) 418269620Snwhitehorn return (CN_DEAD); 419269620Snwhitehorn 420269620Snwhitehorn if (info->fb_pbase == 0) 421269620Snwhitehorn info->fb_flags |= FB_FLAG_NOMMAP; 422269620Snwhitehorn 423256904Sray if (info->fb_cmsize <= 0) { 424256904Sray err = vt_fb_init_cmap(info->fb_cmap, FBTYPE_GET_BPP(info)); 425256904Sray if (err) 426256904Sray return (CN_DEAD); 427256904Sray info->fb_cmsize = 16; 428256904Sray } 429256904Sray 430256904Sray /* Clear the screen. */ 431269437Snwhitehorn vd->vd_driver->vd_blank(vd, TC_BLACK); 432256904Sray 433256904Sray /* Wakeup screen. KMS need this. */ 434256904Sray vt_fb_postswitch(vd); 435256904Sray 436256904Sray return (CN_INTERNAL); 437256904Sray} 438256904Sray 439256904Srayint 440256904Srayvt_fb_attach(struct fb_info *info) 441256904Sray{ 442256904Sray 443256904Sray vt_allocate(&vt_fb_driver, info); 444257725Sray 445256904Sray return (0); 446256904Sray} 447257815Sray 448257815Srayvoid 449257815Srayvt_fb_resume(void) 450257815Sray{ 451257815Sray 452257815Sray vt_resume(); 453257815Sray} 454257815Sray 455257815Srayvoid 456257815Srayvt_fb_suspend(void) 457257815Sray{ 458257815Sray 459257815Sray vt_suspend(); 460257815Sray} 461