1 // SPDX-License-Identifier: GPL-2.0-only 2 3 #include <linux/aperture.h> 4 #include <linux/ioport.h> 5 #include <linux/limits.h> 6 #include <linux/platform_device.h> 7 #include <linux/screen_info.h> 8 9 #include <drm/clients/drm_client_setup.h> 10 #include <drm/drm_atomic.h> 11 #include <drm/drm_atomic_state_helper.h> 12 #include <drm/drm_connector.h> 13 #include <drm/drm_damage_helper.h> 14 #include <drm/drm_device.h> 15 #include <drm/drm_drv.h> 16 #include <drm/drm_edid.h> 17 #include <drm/drm_fbdev_shmem.h> 18 #include <drm/drm_framebuffer.h> 19 #include <drm/drm_gem_atomic_helper.h> 20 #include <drm/drm_gem_framebuffer_helper.h> 21 #include <drm/drm_gem_shmem_helper.h> 22 #include <drm/drm_managed.h> 23 #include <drm/drm_modeset_helper_vtables.h> 24 #include <drm/drm_probe_helper.h> 25 26 #include <video/edid.h> 27 #include <video/pixel_format.h> 28 #include <video/vga.h> 29 30 #include "drm_sysfb_helper.h" 31 32 #define DRIVER_NAME "vesadrm" 33 #define DRIVER_DESC "DRM driver for VESA platform devices" 34 #define DRIVER_MAJOR 1 35 #define DRIVER_MINOR 0 36 37 #define VESADRM_GAMMA_LUT_SIZE 256 38 39 static int vesadrm_get_validated_int(struct drm_device *dev, const char *name, 40 u64 value, u32 max) 41 { 42 if (max > INT_MAX) 43 max = INT_MAX; 44 if (value > max) { 45 drm_err(dev, "%s of %llu exceeds maximum of %u\n", name, value, max); 46 return -EINVAL; 47 } 48 return value; 49 } 50 51 static int vesadrm_get_validated_int0(struct drm_device *dev, const char *name, 52 u64 value, u32 max) 53 { 54 if (!value) { 55 drm_err(dev, "%s of 0 not allowed\n", name); 56 return -EINVAL; 57 } 58 return vesadrm_get_validated_int(dev, name, value, max); 59 } 60 61 static s64 vesadrm_get_validated_size0(struct drm_device *dev, const char *name, 62 u64 value, u64 max) 63 { 64 if (!value) { 65 drm_err(dev, "vesadrm: %s of 0 not allowed\n", name); 66 return -EINVAL; 67 } else if (value > max) { 68 drm_err(dev, "vesadrm: %s of %llu exceeds maximum of %llu\n", name, value, max); 69 return -EINVAL; 70 } 71 return value; 72 } 73 74 static int vesadrm_get_width_si(struct drm_device *dev, const struct screen_info *si) 75 { 76 return vesadrm_get_validated_int0(dev, "width", si->lfb_width, U16_MAX); 77 } 78 79 static int vesadrm_get_height_si(struct drm_device *dev, const struct screen_info *si) 80 { 81 return vesadrm_get_validated_int0(dev, "height", si->lfb_height, U16_MAX); 82 } 83 84 static struct resource *vesadrm_get_memory_si(struct drm_device *dev, 85 const struct screen_info *si, 86 struct resource *res) 87 { 88 ssize_t num; 89 90 num = screen_info_resources(si, res, 1); 91 if (!num) { 92 drm_err(dev, "vesadrm: memory resource not found\n"); 93 return NULL; 94 } 95 96 return res; 97 } 98 99 static int vesadrm_get_stride_si(struct drm_device *dev, const struct screen_info *si, 100 const struct drm_format_info *format, 101 unsigned int width, unsigned int height, u64 size) 102 { 103 u64 lfb_linelength = si->lfb_linelength; 104 105 if (!lfb_linelength) 106 lfb_linelength = drm_format_info_min_pitch(format, 0, width); 107 108 return vesadrm_get_validated_int0(dev, "stride", lfb_linelength, div64_u64(size, height)); 109 } 110 111 static u64 vesadrm_get_visible_size_si(struct drm_device *dev, const struct screen_info *si, 112 unsigned int height, unsigned int stride, u64 size) 113 { 114 u64 vsize = PAGE_ALIGN(height * stride); 115 116 return vesadrm_get_validated_size0(dev, "visible size", vsize, size); 117 } 118 119 static const struct drm_format_info *vesadrm_get_format_si(struct drm_device *dev, 120 const struct screen_info *si) 121 { 122 static const struct { 123 struct pixel_format pixel; 124 u32 fourcc; 125 } vesa_formats[] = { 126 { PIXEL_FORMAT_XRGB1555, DRM_FORMAT_XRGB1555, }, 127 { PIXEL_FORMAT_RGB565, DRM_FORMAT_RGB565, }, 128 { PIXEL_FORMAT_RGB888, DRM_FORMAT_RGB888, }, 129 { PIXEL_FORMAT_XRGB8888, DRM_FORMAT_XRGB8888, }, 130 { PIXEL_FORMAT_XBGR8888, DRM_FORMAT_XBGR8888, }, 131 }; 132 const struct drm_format_info *format = NULL; 133 u32 bits_per_pixel; 134 size_t i; 135 136 bits_per_pixel = __screen_info_lfb_bits_per_pixel(si); 137 138 for (i = 0; i < ARRAY_SIZE(vesa_formats); ++i) { 139 const struct pixel_format *f = &vesa_formats[i].pixel; 140 141 if (bits_per_pixel == f->bits_per_pixel && 142 si->red_size == f->red.length && 143 si->red_pos == f->red.offset && 144 si->green_size == f->green.length && 145 si->green_pos == f->green.offset && 146 si->blue_size == f->blue.length && 147 si->blue_pos == f->blue.offset) { 148 format = drm_format_info(vesa_formats[i].fourcc); 149 break; 150 } 151 } 152 153 if (!format) 154 return ERR_PTR(-EINVAL); 155 if (format->is_color_indexed) 156 return ERR_PTR(-EINVAL); 157 158 return format; 159 } 160 161 /* 162 * VESA device 163 */ 164 165 struct vesadrm_device { 166 struct drm_sysfb_device sysfb; 167 168 #if defined(CONFIG_X86_32) 169 /* VESA Protected Mode interface */ 170 struct { 171 const u8 *PrimaryPalette; 172 } pmi; 173 #endif 174 175 void (*cmap_write)(struct vesadrm_device *vesa, unsigned int index, 176 u16 red, u16 green, u16 blue); 177 178 /* modesetting */ 179 u32 formats[DRM_SYSFB_PLANE_NFORMATS(1)]; 180 struct drm_plane primary_plane; 181 struct drm_crtc crtc; 182 struct drm_encoder encoder; 183 struct drm_connector connector; 184 }; 185 186 static struct vesadrm_device *to_vesadrm_device(struct drm_device *dev) 187 { 188 return container_of(to_drm_sysfb_device(dev), struct vesadrm_device, sysfb); 189 } 190 191 /* 192 * Palette 193 */ 194 195 static void vesadrm_vga_cmap_write(struct vesadrm_device *vesa, unsigned int index, 196 u16 red, u16 green, u16 blue) 197 { 198 u8 i8, r8, g8, b8; 199 200 if (index > 255) 201 return; 202 203 i8 = index; 204 r8 = red >> 8; 205 g8 = green >> 8; 206 b8 = blue >> 8; 207 208 outb_p(i8, VGA_PEL_IW); 209 outb_p(r8, VGA_PEL_D); 210 outb_p(g8, VGA_PEL_D); 211 outb_p(b8, VGA_PEL_D); 212 } 213 214 #if defined(CONFIG_X86_32) 215 static void vesadrm_pmi_cmap_write(struct vesadrm_device *vesa, unsigned int index, 216 u16 red, u16 green, u16 blue) 217 { 218 u32 i32 = index; 219 struct { 220 u8 b8; 221 u8 g8; 222 u8 r8; 223 u8 x8; 224 } PaletteEntry = { 225 blue >> 8, 226 green >> 8, 227 red >> 8, 228 0x00, 229 }; 230 231 if (index > 255) 232 return; 233 234 __asm__ __volatile__ ( 235 "call *(%%esi)" 236 : /* no return value */ 237 : "a" (0x4f09), 238 "b" (0), 239 "c" (1), 240 "d" (i32), 241 "D" (&PaletteEntry), 242 "S" (&vesa->pmi.PrimaryPalette)); 243 } 244 #endif 245 246 static void vesadrm_set_gamma_linear(struct vesadrm_device *vesa, 247 const struct drm_format_info *format) 248 { 249 struct drm_device *dev = &vesa->sysfb.dev; 250 size_t i; 251 u16 r16, g16, b16; 252 253 switch (format->format) { 254 case DRM_FORMAT_XRGB1555: 255 for (i = 0; i < 32; ++i) { 256 r16 = i * 8 + i / 4; 257 r16 |= (r16 << 8) | r16; 258 vesa->cmap_write(vesa, i, r16, r16, r16); 259 } 260 break; 261 case DRM_FORMAT_RGB565: 262 for (i = 0; i < 32; ++i) { 263 r16 = i * 8 + i / 4; 264 r16 |= (r16 << 8) | r16; 265 g16 = i * 4 + i / 16; 266 g16 |= (g16 << 8) | g16; 267 b16 = r16; 268 vesa->cmap_write(vesa, i, r16, g16, b16); 269 } 270 for (i = 32; i < 64; ++i) { 271 g16 = i * 4 + i / 16; 272 g16 |= (g16 << 8) | g16; 273 vesa->cmap_write(vesa, i, 0, g16, 0); 274 } 275 break; 276 case DRM_FORMAT_RGB888: 277 case DRM_FORMAT_XRGB8888: 278 case DRM_FORMAT_BGRX8888: 279 for (i = 0; i < 256; ++i) { 280 r16 = (i << 8) | i; 281 vesa->cmap_write(vesa, i, r16, r16, r16); 282 } 283 break; 284 default: 285 drm_warn_once(dev, "Unsupported format %p4cc for gamma correction\n", 286 &format->format); 287 break; 288 } 289 } 290 291 static void vesadrm_set_gamma_lut(struct vesadrm_device *vesa, 292 const struct drm_format_info *format, 293 struct drm_color_lut *lut) 294 { 295 struct drm_device *dev = &vesa->sysfb.dev; 296 size_t i; 297 u16 r16, g16, b16; 298 299 switch (format->format) { 300 case DRM_FORMAT_XRGB1555: 301 for (i = 0; i < 32; ++i) { 302 r16 = lut[i * 8 + i / 4].red; 303 g16 = lut[i * 8 + i / 4].green; 304 b16 = lut[i * 8 + i / 4].blue; 305 vesa->cmap_write(vesa, i, r16, g16, b16); 306 } 307 break; 308 case DRM_FORMAT_RGB565: 309 for (i = 0; i < 32; ++i) { 310 r16 = lut[i * 8 + i / 4].red; 311 g16 = lut[i * 4 + i / 16].green; 312 b16 = lut[i * 8 + i / 4].blue; 313 vesa->cmap_write(vesa, i, r16, g16, b16); 314 } 315 for (i = 32; i < 64; ++i) 316 vesa->cmap_write(vesa, i, 0, lut[i * 4 + i / 16].green, 0); 317 break; 318 case DRM_FORMAT_RGB888: 319 case DRM_FORMAT_XRGB8888: 320 case DRM_FORMAT_BGRX8888: 321 for (i = 0; i < 256; ++i) 322 vesa->cmap_write(vesa, i, lut[i].red, lut[i].green, lut[i].blue); 323 break; 324 default: 325 drm_warn_once(dev, "Unsupported format %p4cc for gamma correction\n", 326 &format->format); 327 break; 328 } 329 } 330 331 /* 332 * Modesetting 333 */ 334 335 static const u64 vesadrm_primary_plane_format_modifiers[] = { 336 DRM_SYSFB_PLANE_FORMAT_MODIFIERS, 337 }; 338 339 static const struct drm_plane_helper_funcs vesadrm_primary_plane_helper_funcs = { 340 DRM_SYSFB_PLANE_HELPER_FUNCS, 341 }; 342 343 static const struct drm_plane_funcs vesadrm_primary_plane_funcs = { 344 DRM_SYSFB_PLANE_FUNCS, 345 .destroy = drm_plane_cleanup, 346 }; 347 348 static void vesadrm_crtc_helper_atomic_flush(struct drm_crtc *crtc, 349 struct drm_atomic_state *state) 350 { 351 struct drm_device *dev = crtc->dev; 352 struct drm_sysfb_device *sysfb = to_drm_sysfb_device(dev); 353 struct vesadrm_device *vesa = to_vesadrm_device(dev); 354 struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); 355 struct drm_sysfb_crtc_state *sysfb_crtc_state = to_drm_sysfb_crtc_state(crtc_state); 356 357 /* 358 * The gamma LUT has to be reloaded after changing the primary 359 * plane's color format. 360 */ 361 if (crtc_state->enable && crtc_state->color_mgmt_changed) { 362 if (sysfb_crtc_state->format == sysfb->fb_format) { 363 if (crtc_state->gamma_lut) 364 vesadrm_set_gamma_lut(vesa, 365 sysfb_crtc_state->format, 366 crtc_state->gamma_lut->data); 367 else 368 vesadrm_set_gamma_linear(vesa, sysfb_crtc_state->format); 369 } else { 370 vesadrm_set_gamma_linear(vesa, sysfb_crtc_state->format); 371 } 372 } 373 } 374 375 static const struct drm_crtc_helper_funcs vesadrm_crtc_helper_funcs = { 376 DRM_SYSFB_CRTC_HELPER_FUNCS, 377 .atomic_flush = vesadrm_crtc_helper_atomic_flush, 378 }; 379 380 static const struct drm_crtc_funcs vesadrm_crtc_funcs = { 381 DRM_SYSFB_CRTC_FUNCS, 382 .destroy = drm_crtc_cleanup, 383 }; 384 385 static const struct drm_encoder_funcs vesadrm_encoder_funcs = { 386 .destroy = drm_encoder_cleanup, 387 }; 388 389 static const struct drm_connector_helper_funcs vesadrm_connector_helper_funcs = { 390 DRM_SYSFB_CONNECTOR_HELPER_FUNCS, 391 }; 392 393 static const struct drm_connector_funcs vesadrm_connector_funcs = { 394 DRM_SYSFB_CONNECTOR_FUNCS, 395 .destroy = drm_connector_cleanup, 396 }; 397 398 static const struct drm_mode_config_funcs vesadrm_mode_config_funcs = { 399 DRM_SYSFB_MODE_CONFIG_FUNCS, 400 }; 401 402 /* 403 * Init / Cleanup 404 */ 405 406 static struct vesadrm_device *vesadrm_device_create(struct drm_driver *drv, 407 struct platform_device *pdev) 408 { 409 const struct screen_info *si; 410 const struct drm_format_info *format; 411 int width, height, stride; 412 u64 vsize; 413 struct resource resbuf; 414 struct resource *res; 415 struct vesadrm_device *vesa; 416 struct drm_sysfb_device *sysfb; 417 struct drm_device *dev; 418 struct resource *mem = NULL; 419 void __iomem *screen_base; 420 struct drm_plane *primary_plane; 421 struct drm_crtc *crtc; 422 struct drm_encoder *encoder; 423 struct drm_connector *connector; 424 unsigned long max_width, max_height; 425 size_t nformats; 426 int ret; 427 428 si = dev_get_platdata(&pdev->dev); 429 if (!si) 430 return ERR_PTR(-ENODEV); 431 if (screen_info_video_type(si) != VIDEO_TYPE_VLFB) 432 return ERR_PTR(-ENODEV); 433 434 /* 435 * VESA DRM driver 436 */ 437 438 vesa = devm_drm_dev_alloc(&pdev->dev, drv, struct vesadrm_device, sysfb.dev); 439 if (IS_ERR(vesa)) 440 return ERR_CAST(vesa); 441 sysfb = &vesa->sysfb; 442 dev = &sysfb->dev; 443 platform_set_drvdata(pdev, dev); 444 445 /* 446 * Hardware settings 447 */ 448 449 format = vesadrm_get_format_si(dev, si); 450 if (IS_ERR(format)) 451 return ERR_CAST(format); 452 width = vesadrm_get_width_si(dev, si); 453 if (width < 0) 454 return ERR_PTR(width); 455 height = vesadrm_get_height_si(dev, si); 456 if (height < 0) 457 return ERR_PTR(height); 458 res = vesadrm_get_memory_si(dev, si, &resbuf); 459 if (!res) 460 return ERR_PTR(-EINVAL); 461 stride = vesadrm_get_stride_si(dev, si, format, width, height, resource_size(res)); 462 if (stride < 0) 463 return ERR_PTR(stride); 464 vsize = vesadrm_get_visible_size_si(dev, si, height, stride, resource_size(res)); 465 if (!vsize) 466 return ERR_PTR(-EINVAL); 467 468 drm_dbg(dev, "framebuffer format=%p4cc, size=%dx%d, stride=%d bytes\n", 469 &format->format, width, height, stride); 470 471 if (!__screen_info_vbe_mode_nonvga(si)) { 472 vesa->cmap_write = vesadrm_vga_cmap_write; 473 #if defined(CONFIG_X86_32) 474 } else { 475 phys_addr_t pmi_base = __screen_info_vesapm_info_base(si); 476 const u16 *pmi_addr = phys_to_virt(pmi_base); 477 478 vesa->pmi.PrimaryPalette = (u8 *)pmi_addr + pmi_addr[2]; 479 vesa->cmap_write = vesadrm_pmi_cmap_write; 480 #endif 481 } 482 483 #ifdef CONFIG_X86 484 if (drm_edid_header_is_valid(edid_info.dummy) == 8) 485 sysfb->edid = edid_info.dummy; 486 #endif 487 sysfb->fb_mode = drm_sysfb_mode(width, height, 0, 0); 488 sysfb->fb_format = format; 489 sysfb->fb_pitch = stride; 490 if (vesa->cmap_write) 491 sysfb->fb_gamma_lut_size = VESADRM_GAMMA_LUT_SIZE; 492 493 /* 494 * Memory management 495 */ 496 497 ret = devm_aperture_acquire_for_platform_device(pdev, res->start, vsize); 498 if (ret) { 499 drm_err(dev, "could not acquire memory range %pr: %d\n", res, ret); 500 return ERR_PTR(ret); 501 } 502 503 drm_dbg(dev, "using I/O memory framebuffer at %pr\n", res); 504 505 mem = devm_request_mem_region(&pdev->dev, res->start, vsize, drv->name); 506 if (!mem) { 507 /* 508 * We cannot make this fatal. Sometimes this comes from magic 509 * spaces our resource handlers simply don't know about. Use 510 * the I/O-memory resource as-is and try to map that instead. 511 */ 512 drm_warn(dev, "could not acquire memory region %pr\n", res); 513 mem = res; 514 } 515 516 screen_base = devm_ioremap_wc(&pdev->dev, mem->start, resource_size(mem)); 517 if (!screen_base) 518 return ERR_PTR(-ENOMEM); 519 iosys_map_set_vaddr_iomem(&sysfb->fb_addr, screen_base); 520 521 /* 522 * Modesetting 523 */ 524 525 ret = drmm_mode_config_init(dev); 526 if (ret) 527 return ERR_PTR(ret); 528 529 max_width = max_t(unsigned long, width, DRM_SHADOW_PLANE_MAX_WIDTH); 530 max_height = max_t(unsigned long, height, DRM_SHADOW_PLANE_MAX_HEIGHT); 531 532 dev->mode_config.min_width = width; 533 dev->mode_config.max_width = max_width; 534 dev->mode_config.min_height = height; 535 dev->mode_config.max_height = max_height; 536 dev->mode_config.preferred_depth = format->depth; 537 dev->mode_config.funcs = &vesadrm_mode_config_funcs; 538 539 /* Primary plane */ 540 541 nformats = drm_fb_build_fourcc_list(dev, &format->format, 1, 542 vesa->formats, ARRAY_SIZE(vesa->formats)); 543 544 primary_plane = &vesa->primary_plane; 545 ret = drm_universal_plane_init(dev, primary_plane, 0, &vesadrm_primary_plane_funcs, 546 vesa->formats, nformats, 547 vesadrm_primary_plane_format_modifiers, 548 DRM_PLANE_TYPE_PRIMARY, NULL); 549 if (ret) 550 return ERR_PTR(ret); 551 drm_plane_helper_add(primary_plane, &vesadrm_primary_plane_helper_funcs); 552 drm_plane_enable_fb_damage_clips(primary_plane); 553 554 /* CRTC */ 555 556 crtc = &vesa->crtc; 557 ret = drm_crtc_init_with_planes(dev, crtc, primary_plane, NULL, 558 &vesadrm_crtc_funcs, NULL); 559 if (ret) 560 return ERR_PTR(ret); 561 drm_crtc_helper_add(crtc, &vesadrm_crtc_helper_funcs); 562 563 if (sysfb->fb_gamma_lut_size) { 564 ret = drm_mode_crtc_set_gamma_size(crtc, sysfb->fb_gamma_lut_size); 565 if (!ret) 566 drm_crtc_enable_color_mgmt(crtc, 0, false, sysfb->fb_gamma_lut_size); 567 } 568 569 /* Encoder */ 570 571 encoder = &vesa->encoder; 572 ret = drm_encoder_init(dev, encoder, &vesadrm_encoder_funcs, 573 DRM_MODE_ENCODER_NONE, NULL); 574 if (ret) 575 return ERR_PTR(ret); 576 encoder->possible_crtcs = drm_crtc_mask(crtc); 577 578 /* Connector */ 579 580 connector = &vesa->connector; 581 ret = drm_connector_init(dev, connector, &vesadrm_connector_funcs, 582 DRM_MODE_CONNECTOR_Unknown); 583 if (ret) 584 return ERR_PTR(ret); 585 drm_connector_helper_add(connector, &vesadrm_connector_helper_funcs); 586 drm_connector_set_panel_orientation_with_quirk(connector, 587 DRM_MODE_PANEL_ORIENTATION_UNKNOWN, 588 width, height); 589 if (sysfb->edid) 590 drm_connector_attach_edid_property(connector); 591 592 ret = drm_connector_attach_encoder(connector, encoder); 593 if (ret) 594 return ERR_PTR(ret); 595 596 drm_mode_config_reset(dev); 597 598 return vesa; 599 } 600 601 /* 602 * DRM driver 603 */ 604 605 DEFINE_DRM_GEM_FOPS(vesadrm_fops); 606 607 static struct drm_driver vesadrm_driver = { 608 DRM_GEM_SHMEM_DRIVER_OPS, 609 DRM_FBDEV_SHMEM_DRIVER_OPS, 610 .name = DRIVER_NAME, 611 .desc = DRIVER_DESC, 612 .major = DRIVER_MAJOR, 613 .minor = DRIVER_MINOR, 614 .driver_features = DRIVER_ATOMIC | DRIVER_GEM | DRIVER_MODESET, 615 .fops = &vesadrm_fops, 616 }; 617 618 /* 619 * Platform driver 620 */ 621 622 static int vesadrm_probe(struct platform_device *pdev) 623 { 624 struct vesadrm_device *vesa; 625 struct drm_sysfb_device *sysfb; 626 struct drm_device *dev; 627 int ret; 628 629 vesa = vesadrm_device_create(&vesadrm_driver, pdev); 630 if (IS_ERR(vesa)) 631 return PTR_ERR(vesa); 632 sysfb = &vesa->sysfb; 633 dev = &sysfb->dev; 634 635 ret = drm_dev_register(dev, 0); 636 if (ret) 637 return ret; 638 639 drm_client_setup(dev, sysfb->fb_format); 640 641 return 0; 642 } 643 644 static void vesadrm_remove(struct platform_device *pdev) 645 { 646 struct drm_device *dev = platform_get_drvdata(pdev); 647 648 drm_dev_unplug(dev); 649 } 650 651 static struct platform_driver vesadrm_platform_driver = { 652 .driver = { 653 .name = "vesa-framebuffer", 654 }, 655 .probe = vesadrm_probe, 656 .remove = vesadrm_remove, 657 }; 658 659 module_platform_driver(vesadrm_platform_driver); 660 661 MODULE_DESCRIPTION(DRIVER_DESC); 662 MODULE_LICENSE("GPL"); 663