1 // SPDX-License-Identifier: GPL-2.0-only OR MIT 2 /* Copyright 2021 Alyssa Rosenzweig <alyssa@rosenzweig.io> */ 3 /* Based on meson driver which is 4 * Copyright (C) 2016 BayLibre, SAS 5 * Author: Neil Armstrong <narmstrong@baylibre.com> 6 * Copyright (C) 2015 Amlogic, Inc. All rights reserved. 7 * Copyright (C) 2014 Endless Mobile 8 */ 9 10 #include <linux/component.h> 11 #include <linux/delay.h> 12 #include <linux/dma-mapping.h> 13 #include <linux/jiffies.h> 14 #include <linux/module.h> 15 #include <linux/of_address.h> 16 #include <linux/of_device.h> 17 18 #include <drm/drm_aperture.h> 19 #include <drm/drm_atomic.h> 20 #include <drm/drm_atomic_helper.h> 21 #include <drm/drm_crtc.h> 22 #include <drm/drm_drv.h> 23 #include <drm/drm_fb_helper.h> 24 #include <drm/drm_fbdev_dma.h> 25 #include <drm/drm_fourcc.h> 26 #include <drm/drm_fb_dma_helper.h> 27 #include <drm/drm_gem_dma_helper.h> 28 #include <drm/drm_gem_framebuffer_helper.h> 29 #include <drm/drm_simple_kms_helper.h> 30 #include <drm/drm_mode.h> 31 #include <drm/drm_modeset_helper.h> 32 #include <drm/drm_module.h> 33 #include <drm/drm_of.h> 34 #include <drm/drm_probe_helper.h> 35 #include <drm/drm_vblank.h> 36 #include <drm/drm_fixed.h> 37 38 #include "dcp.h" 39 40 #define DRIVER_NAME "apple" 41 #define DRIVER_DESC "Apple display controller DRM driver" 42 43 #define FRAC_16_16(mult, div) (((mult) << 16) / (div)) 44 45 #define MAX_COPROCESSORS 2 46 47 struct apple_drm_private { 48 struct drm_device drm; 49 }; 50 51 DEFINE_DRM_GEM_DMA_FOPS(apple_fops); 52 53 #define DART_PAGE_SIZE 16384 54 55 static int apple_drm_gem_dumb_create(struct drm_file *file_priv, 56 struct drm_device *drm, 57 struct drm_mode_create_dumb *args) 58 { 59 args->pitch = ALIGN(DIV_ROUND_UP(args->width * args->bpp, 8), 64); 60 args->size = round_up(args->pitch * args->height, DART_PAGE_SIZE); 61 62 return drm_gem_dma_dumb_create_internal(file_priv, drm, args); 63 } 64 65 static const struct drm_driver apple_drm_driver = { 66 DRM_GEM_DMA_DRIVER_OPS_WITH_DUMB_CREATE(apple_drm_gem_dumb_create), 67 .name = DRIVER_NAME, 68 .desc = DRIVER_DESC, 69 .date = "20221106", 70 .major = 1, 71 .minor = 0, 72 .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC, 73 .fops = &apple_fops, 74 }; 75 76 static int apple_plane_atomic_check(struct drm_plane *plane, 77 struct drm_atomic_state *state) 78 { 79 struct drm_plane_state *new_plane_state; 80 struct drm_crtc_state *crtc_state; 81 82 new_plane_state = drm_atomic_get_new_plane_state(state, plane); 83 84 if (!new_plane_state->crtc) 85 return 0; 86 87 crtc_state = drm_atomic_get_crtc_state(state, new_plane_state->crtc); 88 if (IS_ERR(crtc_state)) 89 return PTR_ERR(crtc_state); 90 91 /* 92 * DCP limits downscaling to 2x and upscaling to 4x. Attempting to 93 * scale outside these bounds errors out when swapping. 94 * 95 * This function also takes care of clipping the src/dest rectangles, 96 * which is required for correct operation. Partially off-screen 97 * surfaces may appear corrupted. 98 * 99 * DCP does not distinguish plane types in the hardware, so we set 100 * can_position. If the primary plane does not fill the screen, the 101 * hardware will fill in zeroes (black). 102 */ 103 return drm_atomic_helper_check_plane_state(new_plane_state, 104 crtc_state, 105 FRAC_16_16(1, 4), 106 FRAC_16_16(2, 1), 107 true, true); 108 } 109 110 static void apple_plane_atomic_update(struct drm_plane *plane, 111 struct drm_atomic_state *state) 112 { 113 /* Handled in atomic_flush */ 114 } 115 116 static const struct drm_plane_helper_funcs apple_plane_helper_funcs = { 117 .atomic_check = apple_plane_atomic_check, 118 .atomic_update = apple_plane_atomic_update, 119 }; 120 121 static void apple_plane_cleanup(struct drm_plane *plane) 122 { 123 drm_plane_cleanup(plane); 124 kfree(plane); 125 } 126 127 static const struct drm_plane_funcs apple_plane_funcs = { 128 .update_plane = drm_atomic_helper_update_plane, 129 .disable_plane = drm_atomic_helper_disable_plane, 130 .destroy = apple_plane_cleanup, 131 .reset = drm_atomic_helper_plane_reset, 132 .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, 133 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, 134 }; 135 136 /* 137 * Table of supported formats, mapping from DRM fourccs to DCP fourccs. 138 * 139 * For future work, DCP supports more formats not listed, including YUV 140 * formats, an extra RGBA format, and a biplanar RGB10_A8 format (fourcc b3a8) 141 * used for HDR. 142 * 143 * Note: we don't have non-alpha formats but userspace breaks without XRGB. It 144 * doesn't matter for the primary plane, but cursors/overlays must not 145 * advertise formats without alpha. 146 */ 147 static const u32 dcp_formats[] = { 148 DRM_FORMAT_XRGB2101010, 149 DRM_FORMAT_XRGB8888, 150 DRM_FORMAT_ARGB8888, 151 DRM_FORMAT_XBGR8888, 152 DRM_FORMAT_ABGR8888, 153 }; 154 155 u64 apple_format_modifiers[] = { 156 DRM_FORMAT_MOD_LINEAR, 157 DRM_FORMAT_MOD_INVALID 158 }; 159 160 static struct drm_plane *apple_plane_init(struct drm_device *dev, 161 unsigned long possible_crtcs, 162 enum drm_plane_type type) 163 { 164 int ret; 165 struct drm_plane *plane; 166 167 plane = kzalloc(sizeof(*plane), GFP_KERNEL); 168 169 ret = drm_universal_plane_init(dev, plane, possible_crtcs, 170 &apple_plane_funcs, 171 dcp_formats, ARRAY_SIZE(dcp_formats), 172 apple_format_modifiers, type, NULL); 173 if (ret) 174 return ERR_PTR(ret); 175 176 drm_plane_helper_add(plane, &apple_plane_helper_funcs); 177 178 return plane; 179 } 180 181 static enum drm_connector_status 182 apple_connector_detect(struct drm_connector *connector, bool force) 183 { 184 struct apple_connector *apple_connector = to_apple_connector(connector); 185 186 return apple_connector->connected ? connector_status_connected : 187 connector_status_disconnected; 188 } 189 190 static void apple_crtc_atomic_enable(struct drm_crtc *crtc, 191 struct drm_atomic_state *state) 192 { 193 struct drm_crtc_state *crtc_state; 194 crtc_state = drm_atomic_get_new_crtc_state(state, crtc); 195 196 if (crtc_state->active_changed && crtc_state->active) { 197 struct apple_crtc *apple_crtc = to_apple_crtc(crtc); 198 dcp_poweron(apple_crtc->dcp); 199 } 200 201 if (crtc_state->active) 202 dcp_crtc_atomic_modeset(crtc, state); 203 } 204 205 static void apple_crtc_atomic_disable(struct drm_crtc *crtc, 206 struct drm_atomic_state *state) 207 { 208 struct drm_crtc_state *crtc_state; 209 crtc_state = drm_atomic_get_new_crtc_state(state, crtc); 210 211 if (crtc_state->active_changed && !crtc_state->active) { 212 struct apple_crtc *apple_crtc = to_apple_crtc(crtc); 213 dcp_poweroff(apple_crtc->dcp); 214 } 215 216 if (crtc->state->event && !crtc->state->active) { 217 spin_lock_irq(&crtc->dev->event_lock); 218 drm_crtc_send_vblank_event(crtc, crtc->state->event); 219 spin_unlock_irq(&crtc->dev->event_lock); 220 221 crtc->state->event = NULL; 222 } 223 } 224 225 static void apple_crtc_atomic_begin(struct drm_crtc *crtc, 226 struct drm_atomic_state *state) 227 { 228 struct apple_crtc *apple_crtc = to_apple_crtc(crtc); 229 unsigned long flags; 230 231 if (crtc->state->event) { 232 spin_lock_irqsave(&crtc->dev->event_lock, flags); 233 apple_crtc->event = crtc->state->event; 234 spin_unlock_irqrestore(&crtc->dev->event_lock, flags); 235 crtc->state->event = NULL; 236 } 237 } 238 239 static void dcp_atomic_commit_tail(struct drm_atomic_state *old_state) 240 { 241 struct drm_device *dev = old_state->dev; 242 243 drm_atomic_helper_commit_modeset_disables(dev, old_state); 244 245 drm_atomic_helper_commit_modeset_enables(dev, old_state); 246 247 drm_atomic_helper_commit_planes(dev, old_state, 248 DRM_PLANE_COMMIT_ACTIVE_ONLY); 249 250 drm_atomic_helper_fake_vblank(old_state); 251 252 drm_atomic_helper_commit_hw_done(old_state); 253 254 drm_atomic_helper_wait_for_flip_done(dev, old_state); 255 256 drm_atomic_helper_cleanup_planes(dev, old_state); 257 } 258 259 static void apple_crtc_cleanup(struct drm_crtc *crtc) 260 { 261 drm_crtc_cleanup(crtc); 262 kfree(to_apple_crtc(crtc)); 263 } 264 265 static const struct drm_crtc_funcs apple_crtc_funcs = { 266 .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, 267 .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, 268 .destroy = apple_crtc_cleanup, 269 .page_flip = drm_atomic_helper_page_flip, 270 .reset = drm_atomic_helper_crtc_reset, 271 .set_config = drm_atomic_helper_set_config, 272 }; 273 274 static const struct drm_mode_config_funcs apple_mode_config_funcs = { 275 .atomic_check = drm_atomic_helper_check, 276 .atomic_commit = drm_atomic_helper_commit, 277 .fb_create = drm_gem_fb_create, 278 }; 279 280 static const struct drm_mode_config_helper_funcs apple_mode_config_helpers = { 281 .atomic_commit_tail = dcp_atomic_commit_tail, 282 }; 283 284 static void appledrm_connector_cleanup(struct drm_connector *connector) 285 { 286 drm_connector_cleanup(connector); 287 kfree(to_apple_connector(connector)); 288 } 289 290 static const struct drm_connector_funcs apple_connector_funcs = { 291 .fill_modes = drm_helper_probe_single_connector_modes, 292 .destroy = appledrm_connector_cleanup, 293 .reset = drm_atomic_helper_connector_reset, 294 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, 295 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, 296 .detect = apple_connector_detect, 297 }; 298 299 static const struct drm_connector_helper_funcs apple_connector_helper_funcs = { 300 .get_modes = dcp_get_modes, 301 .mode_valid = dcp_mode_valid, 302 }; 303 304 static const struct drm_crtc_helper_funcs apple_crtc_helper_funcs = { 305 .atomic_begin = apple_crtc_atomic_begin, 306 .atomic_check = dcp_crtc_atomic_check, 307 .atomic_flush = dcp_flush, 308 .atomic_enable = apple_crtc_atomic_enable, 309 .atomic_disable = apple_crtc_atomic_disable, 310 .mode_fixup = dcp_crtc_mode_fixup, 311 }; 312 313 static int apple_probe_per_dcp(struct device *dev, 314 struct drm_device *drm, 315 struct platform_device *dcp, 316 int num, bool dcp_ext) 317 { 318 struct apple_crtc *crtc; 319 struct apple_connector *connector; 320 struct apple_encoder *enc; 321 struct drm_plane *primary; 322 int ret; 323 324 primary = apple_plane_init(drm, 1U << num, DRM_PLANE_TYPE_PRIMARY); 325 326 if (IS_ERR(primary)) 327 return PTR_ERR(primary); 328 329 crtc = kzalloc(sizeof(*crtc), GFP_KERNEL); 330 ret = drm_crtc_init_with_planes(drm, &crtc->base, primary, NULL, 331 &apple_crtc_funcs, NULL); 332 if (ret) 333 return ret; 334 335 drm_crtc_helper_add(&crtc->base, &apple_crtc_helper_funcs); 336 drm_crtc_enable_color_mgmt(&crtc->base, 0, true, 0); 337 338 enc = drmm_simple_encoder_alloc(drm, struct apple_encoder, base, 339 DRM_MODE_ENCODER_TMDS); 340 if (IS_ERR(enc)) 341 return PTR_ERR(enc); 342 enc->base.possible_crtcs = drm_crtc_mask(&crtc->base); 343 344 connector = kzalloc(sizeof(*connector), GFP_KERNEL); 345 drm_connector_helper_add(&connector->base, 346 &apple_connector_helper_funcs); 347 348 #ifdef __linux__ 349 // HACK: 350 if (dcp_ext) 351 connector->base.fwnode = fwnode_handle_get(dev->fwnode); 352 #endif 353 354 ret = drm_connector_init(drm, &connector->base, &apple_connector_funcs, 355 dcp_get_connector_type(dcp)); 356 if (ret) 357 return ret; 358 359 connector->base.polled = DRM_CONNECTOR_POLL_HPD; 360 connector->connected = false; 361 connector->dcp = dcp; 362 363 INIT_WORK(&connector->hotplug_wq, dcp_hotplug); 364 365 crtc->dcp = dcp; 366 dcp_link(dcp, crtc, connector); 367 368 return drm_connector_attach_encoder(&connector->base, &enc->base); 369 } 370 371 static int apple_get_fb_resource(struct device *dev, const char *name, 372 struct resource *fb_r) 373 { 374 int idx, ret = -ENODEV; 375 struct device_node *node; 376 377 idx = of_property_match_string(dev->of_node, "memory-region-names", name); 378 379 node = of_parse_phandle(dev->of_node, "memory-region", idx); 380 if (!node) { 381 dev_err(dev, "reserved-memory node '%s' not found\n", name); 382 return -ENODEV; 383 } 384 385 if (!of_device_is_available(node)) { 386 dev_err(dev, "reserved-memory node '%s' is unavailable\n", name); 387 goto err; 388 } 389 390 if (!of_device_is_compatible(node, "framebuffer")) { 391 dev_err(dev, "reserved-memory node '%s' is incompatible\n", 392 node->full_name); 393 goto err; 394 } 395 396 ret = of_address_to_resource(node, 0, fb_r); 397 398 err: 399 of_node_put(node); 400 return ret; 401 } 402 403 static const struct of_device_id apple_dcp_id_tbl[] = { 404 { .compatible = "apple,dcp" }, 405 { .compatible = "apple,dcpext" }, 406 {}, 407 }; 408 409 static int apple_drm_init_dcp(struct device *dev) 410 { 411 struct apple_drm_private *apple = dev_get_drvdata(dev); 412 struct platform_device *dcp[MAX_COPROCESSORS]; 413 struct device_node *np; 414 u64 timeout; 415 int i, ret, num_dcp = 0; 416 417 for_each_matching_node(np, apple_dcp_id_tbl) { 418 bool dcp_ext; 419 if (!of_device_is_available(np)) { 420 of_node_put(np); 421 continue; 422 } 423 dcp_ext = of_device_is_compatible(np, "apple,dcpext"); 424 425 dcp[num_dcp] = of_find_device_by_node(np); 426 of_node_put(np); 427 if (!dcp[num_dcp]) 428 continue; 429 430 ret = apple_probe_per_dcp(dev, &apple->drm, dcp[num_dcp], 431 num_dcp, dcp_ext); 432 if (ret) 433 continue; 434 435 ret = dcp_start(dcp[num_dcp]); 436 if (ret) 437 continue; 438 439 num_dcp++; 440 } 441 442 if (num_dcp < 1) 443 return -ENODEV; 444 445 /* 446 * Starting DPTX might take some time. 447 */ 448 timeout = get_jiffies_64() + msecs_to_jiffies(3000); 449 450 for (i = 0; i < num_dcp; ++i) { 451 u64 jiffies = get_jiffies_64(); 452 u64 wait = time_after_eq64(jiffies, timeout) ? 453 0 : 454 timeout - jiffies; 455 ret = dcp_wait_ready(dcp[i], wait); 456 /* There is nothing we can do if a dcp/dcpext does not boot 457 * (successfully). Ignoring it should not do any harm now. 458 * Needs to reevaluated when adding dcpext support. 459 */ 460 if (ret) 461 dev_warn(dev, "DCP[%d] not ready: %d\n", i, ret); 462 } 463 /* HACK: Wait for dcp* to settle before a modeset */ 464 drm_msleep(100); 465 466 return 0; 467 } 468 469 static int apple_drm_init(struct device *dev) 470 { 471 struct apple_drm_private *apple; 472 struct resource fb_r; 473 resource_size_t fb_size; 474 int ret; 475 476 ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(42)); 477 if (ret) 478 return ret; 479 480 ret = apple_get_fb_resource(dev, "framebuffer", &fb_r); 481 if (ret) 482 return ret; 483 484 fb_size = fb_r.end - fb_r.start + 1; 485 ret = drm_aperture_remove_conflicting_framebuffers(fb_r.start, fb_size, 486 &apple_drm_driver); 487 if (ret) { 488 dev_err(dev, "Failed remove fb: %d\n", ret); 489 goto err_unbind; 490 } 491 492 #ifdef __linux__ 493 apple = devm_drm_dev_alloc(dev, &apple_drm_driver, 494 struct apple_drm_private, drm); 495 if (IS_ERR(apple)) 496 return PTR_ERR(apple); 497 #else 498 struct apldrm_softc *sc = (struct apldrm_softc *)dev; 499 apple = (struct apple_drm_private *)&sc->sc_ddev; 500 #endif 501 502 dev_set_drvdata(dev, apple); 503 504 ret = component_bind_all(dev, apple); 505 if (ret) 506 return ret; 507 508 ret = drmm_mode_config_init(&apple->drm); 509 if (ret) 510 goto err_unbind; 511 512 /* 513 * IOMFB::UPPipeDCP_H13P::verify_surfaces produces the error "plane 514 * requires a minimum of 32x32 for the source buffer" if smaller 515 */ 516 apple->drm.mode_config.min_width = 32; 517 apple->drm.mode_config.min_height = 32; 518 519 /* 520 * TODO: this is the max framebuffer size not the maximal supported 521 * output resolution. DCP reports the maximal framebuffer size take it 522 * from there. 523 * Hardcode it for now to the M1 Max DCP reported 'MaxSrcBufferWidth' 524 * and 'MaxSrcBufferHeight' of 16384. 525 */ 526 apple->drm.mode_config.max_width = 16384; 527 apple->drm.mode_config.max_height = 16384; 528 529 apple->drm.mode_config.funcs = &apple_mode_config_funcs; 530 apple->drm.mode_config.helper_private = &apple_mode_config_helpers; 531 532 ret = apple_drm_init_dcp(dev); 533 if (ret) 534 goto err_unbind; 535 536 drm_mode_config_reset(&apple->drm); 537 538 ret = drm_dev_register(&apple->drm, 0); 539 if (ret) 540 goto err_unbind; 541 542 drm_fbdev_dma_setup(&apple->drm, 32); 543 544 return 0; 545 546 err_unbind: 547 component_unbind_all(dev, NULL); 548 return ret; 549 } 550 551 static void apple_drm_uninit(struct device *dev) 552 { 553 struct apple_drm_private *apple = dev_get_drvdata(dev); 554 555 drm_dev_unregister(&apple->drm); 556 drm_atomic_helper_shutdown(&apple->drm); 557 558 component_unbind_all(dev, NULL); 559 560 dev_set_drvdata(dev, NULL); 561 } 562 563 static int apple_drm_bind(struct device *dev) 564 { 565 return apple_drm_init(dev); 566 } 567 568 static void apple_drm_unbind(struct device *dev) 569 { 570 apple_drm_uninit(dev); 571 } 572 573 const struct component_master_ops apple_drm_ops = { 574 .bind = apple_drm_bind, 575 .unbind = apple_drm_unbind, 576 }; 577 578 static int add_dcp_components(struct device *dev, 579 struct component_match **matchptr) 580 { 581 struct device_node *np; 582 int num = 0; 583 584 for_each_matching_node(np, apple_dcp_id_tbl) { 585 if (of_device_is_available(np)) { 586 drm_of_component_match_add(dev, matchptr, 587 component_compare_of, np); 588 num++; 589 } 590 of_node_put(np); 591 } 592 593 return num; 594 } 595 596 static int apple_platform_probe(struct platform_device *pdev) 597 { 598 struct device *mdev = &pdev->dev; 599 struct component_match *match = NULL; 600 int num_dcp; 601 602 /* add DCP components, handle less than 1 as probe error */ 603 num_dcp = add_dcp_components(mdev, &match); 604 if (num_dcp < 1) 605 return -ENODEV; 606 607 return component_master_add_with_match(mdev, &apple_drm_ops, match); 608 } 609 610 #ifdef __linux__ 611 612 static int apple_platform_remove(struct platform_device *pdev) 613 { 614 component_master_del(&pdev->dev, &apple_drm_ops); 615 616 return 0; 617 } 618 619 static const struct of_device_id of_match[] = { 620 { .compatible = "apple,display-subsystem" }, 621 {} 622 }; 623 MODULE_DEVICE_TABLE(of, of_match); 624 625 #endif 626 627 #ifdef CONFIG_PM_SLEEP 628 static int apple_platform_suspend(struct device *dev) 629 { 630 struct apple_drm_private *apple = dev_get_drvdata(dev); 631 632 if (apple) 633 return drm_mode_config_helper_suspend(&apple->drm); 634 635 return 0; 636 } 637 638 static int apple_platform_resume(struct device *dev) 639 { 640 struct apple_drm_private *apple = dev_get_drvdata(dev); 641 642 if (apple) 643 drm_mode_config_helper_resume(&apple->drm); 644 645 return 0; 646 } 647 648 static const struct dev_pm_ops apple_platform_pm_ops = { 649 .suspend = apple_platform_suspend, 650 .resume = apple_platform_resume, 651 }; 652 #endif 653 654 #ifdef __linux__ 655 656 static struct platform_driver apple_platform_driver = { 657 .driver = { 658 .name = "apple-drm", 659 .of_match_table = of_match, 660 #ifdef CONFIG_PM_SLEEP 661 .pm = &apple_platform_pm_ops, 662 #endif 663 }, 664 .probe = apple_platform_probe, 665 .remove = apple_platform_remove, 666 }; 667 668 drm_module_platform_driver(apple_platform_driver); 669 670 MODULE_AUTHOR("Alyssa Rosenzweig <alyssa@rosenzweig.io>"); 671 MODULE_DESCRIPTION(DRIVER_DESC); 672 MODULE_LICENSE("Dual MIT/GPL"); 673 674 #endif 675