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