vt_fb.c revision 271117
13125Sdg/*- 23125Sdg * Copyright (c) 2013 The FreeBSD Foundation 33125Sdg * All rights reserved. 43125Sdg * 53125Sdg * This software was developed by Aleksandr Rybalko under sponsorship from the 63125Sdg * FreeBSD Foundation. 73125Sdg * 83125Sdg * Redistribution and use in source and binary forms, with or without 93125Sdg * modification, are permitted provided that the following conditions 103125Sdg * are met: 113125Sdg * 1. Redistributions of source code must retain the above copyright 123125Sdg * notice, this list of conditions and the following disclaimer. 133125Sdg * 2. Redistributions in binary form must reproduce the above copyright 143125Sdg * notice, this list of conditions and the following disclaimer in the 153125Sdg * documentation and/or other materials provided with the distribution. 163125Sdg * 173125Sdg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 183125Sdg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 193125Sdg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 203125Sdg * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 213125Sdg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 223125Sdg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 233125Sdg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 243125Sdg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 253125Sdg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 263125Sdg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 273125Sdg * SUCH DAMAGE. 283125Sdg * 293125Sdg * $FreeBSD: stable/10/sys/dev/vt/hw/fb/vt_fb.c 271117 2014-09-04 18:43:40Z emaste $ 3050479Speter */ 313125Sdg 323125Sdg#include <sys/cdefs.h> 333125Sdg__FBSDID("$FreeBSD: stable/10/sys/dev/vt/hw/fb/vt_fb.c 271117 2014-09-04 18:43:40Z emaste $"); 343125Sdg 353125Sdg#include <sys/param.h> 363125Sdg#include <sys/systm.h> 373125Sdg#include <sys/malloc.h> 383125Sdg#include <sys/queue.h> 39169857Sdds#include <sys/fbio.h> 40169857Sdds#include <dev/vt/vt.h> 413125Sdg#include <dev/vt/hw/fb/vt_fb.h> 423125Sdg#include <dev/vt/colors/vt_termcolors.h> 43169857Sdds 443125Sdgvoid vt_fb_drawrect(struct vt_device *vd, int x1, int y1, int x2, int y2, 45169857Sdds int fill, term_color_t color); 46169857Sddsvoid vt_fb_setpixel(struct vt_device *vd, int x, int y, term_color_t color); 47169857Sdds 48169857Sddsstatic struct vt_driver vt_fb_driver = { 49169857Sdds .vd_name = "fb", 503125Sdg .vd_init = vt_fb_init, 513125Sdg .vd_blank = vt_fb_blank, 523125Sdg .vd_bitbltchr = vt_fb_bitbltchr, 533125Sdg .vd_maskbitbltchr = vt_fb_maskbitbltchr, 543125Sdg .vd_drawrect = vt_fb_drawrect, 55169857Sdds .vd_setpixel = vt_fb_setpixel, 563125Sdg .vd_postswitch = vt_fb_postswitch, 57169857Sdds .vd_priority = VD_PRIORITY_GENERIC+10, 58169857Sdds .vd_fb_ioctl = vt_fb_ioctl, 59169857Sdds .vd_fb_mmap = vt_fb_mmap, 60169857Sdds}; 613125Sdg 623125SdgVT_DRIVER_DECLARE(vt_fb, vt_fb_driver); 633125Sdg 643125Sdgstatic void 6599829Salfredvt_fb_mem_wr1(struct fb_info *sc, uint32_t o, uint8_t v) 663125Sdg{ 67169857Sdds 68169857Sdds KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 69169857Sdds *(uint8_t *)(sc->fb_vbase + o) = v; 70169857Sdds} 71169857Sdds 72169857Sddsstatic void 73169857Sddsvt_fb_mem_wr2(struct fb_info *sc, uint32_t o, uint16_t v) 743125Sdg{ 7599829Salfred 7699829Salfred KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 7799829Salfred *(uint16_t *)(sc->fb_vbase + o) = v; 7899829Salfred} 7999829Salfred 803125Sdgstatic void 81169857Sddsvt_fb_mem_wr4(struct fb_info *sc, uint32_t o, uint32_t v) 82169857Sdds{ 83169857Sdds 843125Sdg KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 8599829Salfred *(uint32_t *)(sc->fb_vbase + o) = v; 8699829Salfred} 8799829Salfred 8899829Salfredint 8999829Salfredvt_fb_ioctl(struct vt_device *vd, u_long cmd, caddr_t data, struct thread *td) 903125Sdg{ 913125Sdg struct fb_info *info; 923125Sdg int error = 0; 933125Sdg 943125Sdg info = vd->vd_softc; 9599829Salfred 963125Sdg switch (cmd) { 97169670Sdds case FBIOGTYPE: 983125Sdg bcopy(info, (struct fbtype *)data, sizeof(struct fbtype)); 993125Sdg break; 1003125Sdg 1013125Sdg case FBIO_GETWINORG: /* get frame buffer window origin */ 1023125Sdg *(u_int *)data = 0; 1033125Sdg break; 1043125Sdg 1053125Sdg case FBIO_GETDISPSTART: /* get display start address */ 1063125Sdg ((video_display_start_t *)data)->x = 0; 1073125Sdg ((video_display_start_t *)data)->y = 0; 1083125Sdg break; 1093125Sdg 1103125Sdg case FBIO_GETLINEWIDTH: /* get scan line width in bytes */ 111 *(u_int *)data = info->fb_stride; 112 break; 113 114 case FBIO_BLANK: /* blank display */ 115 if (vd->vd_driver->vd_blank == NULL) 116 return (ENODEV); 117 vd->vd_driver->vd_blank(vd, TC_BLACK); 118 break; 119 120 default: 121 error = ENOIOCTL; 122 break; 123 } 124 125 return (error); 126} 127 128int 129vt_fb_mmap(struct vt_device *vd, vm_ooffset_t offset, vm_paddr_t *paddr, 130 int prot, vm_memattr_t *memattr) 131{ 132 struct fb_info *info; 133 134 info = vd->vd_softc; 135 136 if (info->fb_flags & FB_FLAG_NOMMAP) 137 return (ENODEV); 138 139 if (offset >= 0 && offset < info->fb_size) { 140 *paddr = info->fb_pbase + offset; 141 #ifdef VM_MEMATTR_WRITE_COMBINING 142 *memattr = VM_MEMATTR_WRITE_COMBINING; 143 #endif 144 return (0); 145 } 146 147 return (EINVAL); 148} 149 150void 151vt_fb_setpixel(struct vt_device *vd, int x, int y, term_color_t color) 152{ 153 struct fb_info *info; 154 uint32_t c; 155 u_int o; 156 157 info = vd->vd_softc; 158 c = info->fb_cmap[color]; 159 o = info->fb_stride * y + x * FBTYPE_GET_BYTESPP(info); 160 161 KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer")); 162 163 switch (FBTYPE_GET_BYTESPP(info)) { 164 case 1: 165 vt_fb_mem_wr1(info, o, c); 166 break; 167 case 2: 168 vt_fb_mem_wr2(info, o, c); 169 break; 170 case 3: 171 vt_fb_mem_wr1(info, o, (c >> 16) & 0xff); 172 vt_fb_mem_wr1(info, o + 1, (c >> 8) & 0xff); 173 vt_fb_mem_wr1(info, o + 2, c & 0xff); 174 break; 175 case 4: 176 vt_fb_mem_wr4(info, o, c); 177 break; 178 default: 179 /* panic? */ 180 return; 181 } 182 183} 184 185void 186vt_fb_drawrect(struct vt_device *vd, int x1, int y1, int x2, int y2, int fill, 187 term_color_t color) 188{ 189 int x, y; 190 191 for (y = y1; y <= y2; y++) { 192 if (fill || (y == y1) || (y == y2)) { 193 for (x = x1; x <= x2; x++) 194 vt_fb_setpixel(vd, x, y, color); 195 } else { 196 vt_fb_setpixel(vd, x1, y, color); 197 vt_fb_setpixel(vd, x2, y, color); 198 } 199 } 200} 201 202void 203vt_fb_blank(struct vt_device *vd, term_color_t color) 204{ 205 struct fb_info *info; 206 uint32_t c; 207 u_int o, h; 208 209 info = vd->vd_softc; 210 c = info->fb_cmap[color]; 211 212 KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer")); 213 214 switch (FBTYPE_GET_BYTESPP(info)) { 215 case 1: 216 for (h = 0; h < info->fb_height; h++) 217 for (o = 0; o < info->fb_stride; o++) 218 vt_fb_mem_wr1(info, h*info->fb_stride + o, c); 219 break; 220 case 2: 221 for (h = 0; h < info->fb_height; h++) 222 for (o = 0; o < info->fb_stride; o += 2) 223 vt_fb_mem_wr2(info, h*info->fb_stride + o, c); 224 break; 225 case 3: 226 for (h = 0; h < info->fb_height; h++) 227 for (o = 0; o < info->fb_stride; o += 3) { 228 vt_fb_mem_wr1(info, h*info->fb_stride + o, 229 (c >> 16) & 0xff); 230 vt_fb_mem_wr1(info, h*info->fb_stride + o + 1, 231 (c >> 8) & 0xff); 232 vt_fb_mem_wr1(info, h*info->fb_stride + o + 2, 233 c & 0xff); 234 } 235 break; 236 case 4: 237 for (h = 0; h < info->fb_height; h++) 238 for (o = 0; o < info->fb_stride; o += 4) 239 vt_fb_mem_wr4(info, h*info->fb_stride + o, c); 240 break; 241 default: 242 /* panic? */ 243 return; 244 } 245} 246 247void 248vt_fb_bitbltchr(struct vt_device *vd, const uint8_t *src, const uint8_t *mask, 249 int bpl, vt_axis_t top, vt_axis_t left, unsigned int width, 250 unsigned int height, term_color_t fg, term_color_t bg) 251{ 252 struct fb_info *info; 253 uint32_t fgc, bgc, cc, o; 254 int c, l, bpp; 255 u_long line; 256 uint8_t b; 257 const uint8_t *ch; 258 259 info = vd->vd_softc; 260 bpp = FBTYPE_GET_BYTESPP(info); 261 fgc = info->fb_cmap[fg]; 262 bgc = info->fb_cmap[bg]; 263 b = 0; 264 if (bpl == 0) 265 bpl = (width + 7) >> 3; /* Bytes per sorce line. */ 266 267 /* Don't try to put off screen pixels */ 268 if (((left + width) > info->fb_width) || ((top + height) > 269 info->fb_height)) 270 return; 271 272 KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer")); 273 274 line = (info->fb_stride * top) + (left * bpp); 275 for (l = 0; l < height; l++) { 276 ch = src; 277 for (c = 0; c < width; c++) { 278 if (c % 8 == 0) 279 b = *ch++; 280 else 281 b <<= 1; 282 o = line + (c * bpp); 283 cc = b & 0x80 ? fgc : bgc; 284 285 switch(bpp) { 286 case 1: 287 vt_fb_mem_wr1(info, o, cc); 288 break; 289 case 2: 290 vt_fb_mem_wr2(info, o, cc); 291 break; 292 case 3: 293 /* Packed mode, so unaligned. Byte access. */ 294 vt_fb_mem_wr1(info, o, (cc >> 16) & 0xff); 295 vt_fb_mem_wr1(info, o + 1, (cc >> 8) & 0xff); 296 vt_fb_mem_wr1(info, o + 2, cc & 0xff); 297 break; 298 case 4: 299 vt_fb_mem_wr4(info, o, cc); 300 break; 301 default: 302 /* panic? */ 303 break; 304 } 305 } 306 line += info->fb_stride; 307 src += bpl; 308 } 309} 310 311void 312vt_fb_maskbitbltchr(struct vt_device *vd, const uint8_t *src, const uint8_t *mask, 313 int bpl, vt_axis_t top, vt_axis_t left, unsigned int width, 314 unsigned int height, term_color_t fg, term_color_t bg) 315{ 316 struct fb_info *info; 317 uint32_t fgc, bgc, cc, o; 318 int c, l, bpp; 319 u_long line; 320 uint8_t b, m; 321 const uint8_t *ch; 322 323 info = vd->vd_softc; 324 bpp = FBTYPE_GET_BYTESPP(info); 325 fgc = info->fb_cmap[fg]; 326 bgc = info->fb_cmap[bg]; 327 b = m = 0; 328 if (bpl == 0) 329 bpl = (width + 7) >> 3; /* Bytes per sorce line. */ 330 331 /* Don't try to put off screen pixels */ 332 if (((left + width) > info->fb_width) || ((top + height) > 333 info->fb_height)) 334 return; 335 336 KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer")); 337 338 line = (info->fb_stride * top) + (left * bpp); 339 for (l = 0; l < height; l++) { 340 ch = src; 341 for (c = 0; c < width; c++) { 342 if (c % 8 == 0) 343 b = *ch++; 344 else 345 b <<= 1; 346 if (mask != NULL) { 347 if (c % 8 == 0) 348 m = *mask++; 349 else 350 m <<= 1; 351 /* Skip pixel write, if mask has no bit set. */ 352 if ((m & 0x80) == 0) 353 continue; 354 } 355 o = line + (c * bpp); 356 cc = b & 0x80 ? fgc : bgc; 357 358 switch(bpp) { 359 case 1: 360 vt_fb_mem_wr1(info, o, cc); 361 break; 362 case 2: 363 vt_fb_mem_wr2(info, o, cc); 364 break; 365 case 3: 366 /* Packed mode, so unaligned. Byte access. */ 367 vt_fb_mem_wr1(info, o, (cc >> 16) & 0xff); 368 vt_fb_mem_wr1(info, o + 1, (cc >> 8) & 0xff); 369 vt_fb_mem_wr1(info, o + 2, cc & 0xff); 370 break; 371 case 4: 372 vt_fb_mem_wr4(info, o, cc); 373 break; 374 default: 375 /* panic? */ 376 break; 377 } 378 } 379 line += info->fb_stride; 380 src += bpl; 381 } 382} 383 384void 385vt_fb_postswitch(struct vt_device *vd) 386{ 387 struct fb_info *info; 388 389 info = vd->vd_softc; 390 391 if (info->enter != NULL) 392 info->enter(info->fb_priv); 393} 394 395static int 396vt_fb_init_cmap(uint32_t *cmap, int depth) 397{ 398 399 switch (depth) { 400 case 8: 401 return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB, 402 0x7, 5, 0x7, 2, 0x3, 0)); 403 case 15: 404 return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB, 405 0x1f, 10, 0x1f, 5, 0x1f, 0)); 406 case 16: 407 return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB, 408 0x1f, 11, 0x3f, 5, 0x1f, 0)); 409 case 24: 410 case 32: /* Ignore alpha. */ 411 return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB, 412 0xff, 16, 0xff, 8, 0xff, 0)); 413 default: 414 return (1); 415 } 416} 417 418int 419vt_fb_init(struct vt_device *vd) 420{ 421 struct fb_info *info; 422 int err; 423 424 info = vd->vd_softc; 425 vd->vd_height = info->fb_height; 426 vd->vd_width = info->fb_width; 427 428 if (info->fb_size == 0) 429 return (CN_DEAD); 430 431 if (info->fb_pbase == 0) 432 info->fb_flags |= FB_FLAG_NOMMAP; 433 434 if (info->fb_cmsize <= 0) { 435 err = vt_fb_init_cmap(info->fb_cmap, FBTYPE_GET_BPP(info)); 436 if (err) 437 return (CN_DEAD); 438 info->fb_cmsize = 16; 439 } 440 441 /* Clear the screen. */ 442 vd->vd_driver->vd_blank(vd, TC_BLACK); 443 444 /* Wakeup screen. KMS need this. */ 445 vt_fb_postswitch(vd); 446 447 return (CN_INTERNAL); 448} 449 450int 451vt_fb_attach(struct fb_info *info) 452{ 453 454 vt_allocate(&vt_fb_driver, info); 455 456 return (0); 457} 458 459void 460vt_fb_resume(void) 461{ 462 463 vt_resume(); 464} 465 466void 467vt_fb_suspend(void) 468{ 469 470 vt_suspend(); 471} 472