1 /*- 2 * Copyright (c) 2013 The FreeBSD Foundation 3 * All rights reserved. 4 * 5 * This software was developed by Aleksandr Rybalko under sponsorship from the 6 * FreeBSD Foundation. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $FreeBSD$ 30 */ 31 32 #include <sys/cdefs.h> 33 __FBSDID("$FreeBSD$"); 34 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/malloc.h> 38 #include <sys/queue.h> 39 #include <sys/fbio.h> 40 #include <dev/vt/vt.h> 41 #include <dev/vt/hw/fb/vt_fb.h> 42 #include <dev/vt/colors/vt_termcolors.h> 43 44 void vt_fb_drawrect(struct vt_device *vd, int x1, int y1, int x2, int y2, 45 int fill, term_color_t color); 46 void vt_fb_setpixel(struct vt_device *vd, int x, int y, term_color_t color); 47 48 static struct vt_driver vt_fb_driver = { 49 .vd_name = "fb", 50 .vd_init = vt_fb_init, 51 .vd_blank = vt_fb_blank, 52 .vd_bitbltchr = vt_fb_bitbltchr, 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 }; 60 61 VT_DRIVER_DECLARE(vt_fb, vt_fb_driver); 62 63 static void 64 vt_fb_mem_wr1(struct fb_info *sc, uint32_t o, uint8_t v) 65 { 66 67 KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 68 *(uint8_t *)(sc->fb_vbase + o) = v; 69 } 70 71 static void 72 vt_fb_mem_wr2(struct fb_info *sc, uint32_t o, uint16_t v) 73 { 74 75 KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 76 *(uint16_t *)(sc->fb_vbase + o) = v; 77 } 78 79 static void 80 vt_fb_mem_wr4(struct fb_info *sc, uint32_t o, uint32_t v) 81 { 82 83 KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 84 *(uint32_t *)(sc->fb_vbase + o) = v; 85 } 86 87 int 88 vt_fb_ioctl(struct vt_device *vd, u_long cmd, caddr_t data, struct thread *td) 89 { 90 struct fb_info *info; 91 int error = 0; 92 93 info = vd->vd_softc; 94 95 switch (cmd) { 96 case FBIOGTYPE: 97 bcopy(info, (struct fbtype *)data, sizeof(struct fbtype)); 98 break; 99 100 case FBIO_GETWINORG: /* get frame buffer window origin */ 101 *(u_int *)data = 0; 102 break; 103 104 case FBIO_GETDISPSTART: /* get display start address */ 105 ((video_display_start_t *)data)->x = 0; 106 ((video_display_start_t *)data)->y = 0; 107 break; 108 109 case FBIO_GETLINEWIDTH: /* get scan line width in bytes */ 110 *(u_int *)data = info->fb_stride; 111 break; 112 113 case FBIO_BLANK: /* blank display */ 114 if (vd->vd_driver->vd_blank == NULL) 115 return (ENODEV); 116 vd->vd_driver->vd_blank(vd, TC_BLACK); 117 break; 118 119 default: 120 error = ENOIOCTL; 121 break; 122 } 123 124 return (error); 125 } 126 127 int 128 vt_fb_mmap(struct vt_device *vd, vm_ooffset_t offset, vm_paddr_t *paddr, 129 int prot, vm_memattr_t *memattr) 130 { 131 struct fb_info *info; 132 133 info = vd->vd_softc; 134 135 if (info->fb_flags & FB_FLAG_NOMMAP) 136 return (ENODEV); 137 138 if (offset >= 0 && offset < info->fb_size) { 139 *paddr = info->fb_pbase + offset; 140 #ifdef VM_MEMATTR_WRITE_COMBINING 141 *memattr = VM_MEMATTR_WRITE_COMBINING; 142 #endif 143 return (0); 144 } 145 146 return (EINVAL); 147 } 148 149 void 150 vt_fb_setpixel(struct vt_device *vd, int x, int y, term_color_t color) 151 { 152 struct fb_info *info; 153 uint32_t c; 154 u_int o; 155 156 info = vd->vd_softc; 157 c = info->fb_cmap[color]; 158 o = info->fb_stride * y + x * FBTYPE_GET_BYTESPP(info); 159 160 KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer")); 161 162 switch (FBTYPE_GET_BYTESPP(info)) { 163 case 1: 164 vt_fb_mem_wr1(info, o, c); 165 break; 166 case 2: 167 vt_fb_mem_wr2(info, o, c); 168 break; 169 case 3: 170 vt_fb_mem_wr1(info, o, (c >> 16) & 0xff); 171 vt_fb_mem_wr1(info, o + 1, (c >> 8) & 0xff); 172 vt_fb_mem_wr1(info, o + 2, c & 0xff); 173 break; 174 case 4: 175 vt_fb_mem_wr4(info, o, c); 176 break; 177 default: 178 /* panic? */ 179 return; 180 } 181 182 } 183 184 void 185 vt_fb_drawrect(struct vt_device *vd, int x1, int y1, int x2, int y2, int fill, 186 term_color_t color) 187 { 188 int x, y; 189 190 for (y = y1; y <= y2; y++) { 191 if (fill || (y == y1) || (y == y2)) { 192 for (x = x1; x <= x2; x++) 193 vt_fb_setpixel(vd, x, y, color); 194 } else { 195 vt_fb_setpixel(vd, x1, y, color); 196 vt_fb_setpixel(vd, x2, y, color); 197 } 198 } 199 } 200 201 void 202 vt_fb_blank(struct vt_device *vd, term_color_t color) 203 { 204 struct fb_info *info; 205 uint32_t c; 206 u_int o, h; 207 208 info = vd->vd_softc; 209 c = info->fb_cmap[color]; 210 211 KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer")); 212 213 switch (FBTYPE_GET_BYTESPP(info)) { 214 case 1: 215 for (h = 0; h < info->fb_height; h++) 216 for (o = 0; o < info->fb_stride; o++) 217 vt_fb_mem_wr1(info, h*info->fb_stride + o, c); 218 break; 219 case 2: 220 for (h = 0; h < info->fb_height; h++) 221 for (o = 0; o < info->fb_stride; o += 2) 222 vt_fb_mem_wr2(info, h*info->fb_stride + o, c); 223 break; 224 case 3: 225 for (h = 0; h < info->fb_height; h++) 226 for (o = 0; o < info->fb_stride; o += 3) { 227 vt_fb_mem_wr1(info, h*info->fb_stride + o, 228 (c >> 16) & 0xff); 229 vt_fb_mem_wr1(info, h*info->fb_stride + o + 1, 230 (c >> 8) & 0xff); 231 vt_fb_mem_wr1(info, h*info->fb_stride + o + 2, 232 c & 0xff); 233 } 234 break; 235 case 4: 236 for (h = 0; h < info->fb_height; h++) 237 for (o = 0; o < info->fb_stride; o += 4) 238 vt_fb_mem_wr4(info, h*info->fb_stride + o, c); 239 break; 240 default: 241 /* panic? */ 242 return; 243 } 244 } 245 246 void 247 vt_fb_bitbltchr(struct vt_device *vd, const uint8_t *src, const uint8_t *mask, 248 int bpl, vt_axis_t top, vt_axis_t left, unsigned int width, 249 unsigned int height, term_color_t fg, term_color_t bg) 250 { 251 struct fb_info *info; 252 uint32_t fgc, bgc, cc, o; 253 int c, l, bpp; 254 u_long line; 255 uint8_t b, m; 256 const uint8_t *ch; 257 258 info = vd->vd_softc; 259 bpp = FBTYPE_GET_BYTESPP(info); 260 fgc = info->fb_cmap[fg]; 261 bgc = info->fb_cmap[bg]; 262 b = m = 0; 263 if (bpl == 0) 264 bpl = (width + 7) >> 3; /* Bytes per sorce line. */ 265 266 /* Don't try to put off screen pixels */ 267 if (((left + width) > info->fb_width) || ((top + height) > 268 info->fb_height)) 269 return; 270 271 KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer")); 272 273 line = (info->fb_stride * top) + (left * bpp); 274 for (l = 0; l < height; l++) { 275 ch = src; 276 for (c = 0; c < width; c++) { 277 if (c % 8 == 0) 278 b = *ch++; 279 else 280 b <<= 1; 281 if (mask != NULL) { 282 if (c % 8 == 0) 283 m = *mask++; 284 else 285 m <<= 1; 286 /* Skip pixel write, if mask has no bit set. */ 287 if ((m & 0x80) == 0) 288 continue; 289 } 290 o = line + (c * bpp); 291 cc = b & 0x80 ? fgc : bgc; 292 293 switch(bpp) { 294 case 1: 295 vt_fb_mem_wr1(info, o, cc); 296 break; 297 case 2: 298 vt_fb_mem_wr2(info, o, cc); 299 break; 300 case 3: 301 /* Packed mode, so unaligned. Byte access. */ 302 vt_fb_mem_wr1(info, o, (cc >> 16) & 0xff); 303 vt_fb_mem_wr1(info, o + 1, (cc >> 8) & 0xff); 304 vt_fb_mem_wr1(info, o + 2, cc & 0xff); 305 break; 306 case 4: 307 vt_fb_mem_wr4(info, o, cc); 308 break; 309 default: 310 /* panic? */ 311 break; 312 } 313 } 314 line += info->fb_stride; 315 src += bpl; 316 } 317 } 318 319 void 320 vt_fb_postswitch(struct vt_device *vd) 321 { 322 struct fb_info *info; 323 324 info = vd->vd_softc; 325 326 if (info->enter != NULL) 327 info->enter(info->fb_priv); 328 } 329 330 static int 331 vt_fb_init_cmap(uint32_t *cmap, int depth) 332 { 333 334 switch (depth) { 335 case 8: 336 return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB, 337 0x7, 5, 0x7, 2, 0x3, 0)); 338 case 15: 339 return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB, 340 0x1f, 10, 0x1f, 5, 0x1f, 0)); 341 case 16: 342 return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB, 343 0x1f, 11, 0x3f, 5, 0x1f, 0)); 344 case 24: 345 case 32: /* Ignore alpha. */ 346 return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB, 347 0xff, 16, 0xff, 8, 0xff, 0)); 348 default: 349 return (1); 350 } 351 } 352 353 int 354 vt_fb_init(struct vt_device *vd) 355 { 356 struct fb_info *info; 357 int err; 358 359 info = vd->vd_softc; 360 vd->vd_height = info->fb_height; 361 vd->vd_width = info->fb_width; 362 363 if (info->fb_size == 0) 364 return (CN_DEAD); 365 366 if (info->fb_pbase == 0) 367 info->fb_flags |= FB_FLAG_NOMMAP; 368 369 if (info->fb_cmsize <= 0) { 370 err = vt_fb_init_cmap(info->fb_cmap, FBTYPE_GET_BPP(info)); 371 if (err) 372 return (CN_DEAD); 373 info->fb_cmsize = 16; 374 } 375 376 /* Clear the screen. */ 377 vd->vd_driver->vd_blank(vd, TC_BLACK); 378 379 /* Wakeup screen. KMS need this. */ 380 vt_fb_postswitch(vd); 381 382 return (CN_INTERNAL); 383 } 384 385 int 386 vt_fb_attach(struct fb_info *info) 387 { 388 389 vt_allocate(&vt_fb_driver, info); 390 391 return (0); 392 } 393 394 void 395 vt_fb_resume(void) 396 { 397 398 vt_resume(); 399 } 400 401 void 402 vt_fb_suspend(void) 403 { 404 405 vt_suspend(); 406 } 407