1 // SPDX-License-Identifier: GPL-2.0-only OR MIT 2 /* Copyright 2021 Alyssa Rosenzweig <alyssa@rosenzweig.io> */ 3 4 #include <linux/align.h> 5 #include <linux/apple-mailbox.h> 6 #include <linux/bitmap.h> 7 #include <linux/clk.h> 8 #include <linux/completion.h> 9 #include <linux/component.h> 10 #include <linux/delay.h> 11 #include <linux/dma-mapping.h> 12 #include <linux/gpio/consumer.h> 13 #include <linux/iommu.h> 14 #include <linux/jiffies.h> 15 #include <linux/kernel.h> 16 #include <linux/module.h> 17 #include <linux/moduleparam.h> 18 #include <linux/of_address.h> 19 #include <linux/of_device.h> 20 #include <linux/of_platform.h> 21 #include <linux/slab.h> 22 #include <linux/soc/apple/rtkit.h> 23 #include <linux/string.h> 24 #include <linux/workqueue.h> 25 26 #include <drm/drm_fb_dma_helper.h> 27 #include <drm/drm_fourcc.h> 28 #include <drm/drm_framebuffer.h> 29 #include <drm/drm_module.h> 30 #include <drm/drm_probe_helper.h> 31 #include <drm/drm_vblank.h> 32 33 #include "afk.h" 34 #include "dcp.h" 35 #include "dcp-internal.h" 36 #include "iomfb.h" 37 #include "parser.h" 38 #include "trace.h" 39 40 #define APPLE_DCP_COPROC_CPU_CONTROL 0x44 41 #define APPLE_DCP_COPROC_CPU_CONTROL_RUN BIT(4) 42 43 #define DCP_BOOT_TIMEOUT msecs_to_jiffies(1000) 44 45 static bool show_notch; 46 module_param(show_notch, bool, 0644); 47 MODULE_PARM_DESC(show_notch, "Use the full display height and shows the notch"); 48 49 /* HACK: moved here to avoid circular dependency between apple_drv and dcp */ 50 void dcp_drm_crtc_vblank(struct apple_crtc *crtc) 51 { 52 unsigned long flags; 53 54 spin_lock_irqsave(&crtc->base.dev->event_lock, flags); 55 if (crtc->event) { 56 drm_crtc_send_vblank_event(&crtc->base, crtc->event); 57 crtc->event = NULL; 58 } 59 spin_unlock_irqrestore(&crtc->base.dev->event_lock, flags); 60 } 61 62 void dcp_set_dimensions(struct apple_dcp *dcp) 63 { 64 int i; 65 int width_mm = dcp->width_mm; 66 int height_mm = dcp->height_mm; 67 68 if (width_mm == 0 || height_mm == 0) { 69 width_mm = dcp->panel.width_mm; 70 height_mm = dcp->panel.height_mm; 71 } 72 73 /* Set the connector info */ 74 if (dcp->connector) { 75 struct drm_connector *connector = &dcp->connector->base; 76 77 mutex_lock(&connector->dev->mode_config.mutex); 78 connector->display_info.width_mm = width_mm; 79 connector->display_info.height_mm = height_mm; 80 mutex_unlock(&connector->dev->mode_config.mutex); 81 } 82 83 /* 84 * Fix up any probed modes. Modes are created when parsing 85 * TimingElements, dimensions are calculated when parsing 86 * DisplayAttributes, and TimingElements may be sent first 87 */ 88 for (i = 0; i < dcp->nr_modes; ++i) { 89 dcp->modes[i].mode.width_mm = width_mm; 90 dcp->modes[i].mode.height_mm = height_mm; 91 } 92 } 93 94 bool dcp_has_panel(struct apple_dcp *dcp) 95 { 96 return dcp->panel.width_mm > 0; 97 } 98 99 /* 100 * Helper to send a DRM vblank event. We do not know how call swap_submit_dcp 101 * without surfaces. To avoid timeouts in drm_atomic_helper_wait_for_vblanks 102 * send a vblank event via a workqueue. 103 */ 104 static void dcp_delayed_vblank(struct work_struct *work) 105 { 106 struct apple_dcp *dcp; 107 108 dcp = container_of(work, struct apple_dcp, vblank_wq); 109 mdelay(5); 110 dcp_drm_crtc_vblank(dcp->crtc); 111 } 112 113 static void dcp_recv_msg(void *cookie, u8 endpoint, u64 message) 114 { 115 struct apple_dcp *dcp = cookie; 116 117 trace_dcp_recv_msg(dcp, endpoint, message); 118 119 switch (endpoint) { 120 case IOMFB_ENDPOINT: 121 return iomfb_recv_msg(dcp, message); 122 case SYSTEM_ENDPOINT: 123 afk_receive_message(dcp->systemep, message); 124 return; 125 case DISP0_ENDPOINT: 126 afk_receive_message(dcp->ibootep, message); 127 return; 128 case DPTX_ENDPOINT: 129 afk_receive_message(dcp->dptxep, message); 130 return; 131 default: 132 WARN(endpoint, "unknown DCP endpoint %hhu\n", endpoint); 133 } 134 } 135 136 static void dcp_rtk_crashed(void *cookie) 137 { 138 struct apple_dcp *dcp = cookie; 139 140 dcp->crashed = true; 141 dev_err(dcp->dev, "DCP has crashed\n"); 142 if (dcp->connector) { 143 dcp->connector->connected = 0; 144 schedule_work(&dcp->connector->hotplug_wq); 145 } 146 complete(&dcp->start_done); 147 } 148 149 static int dcp_rtk_shmem_setup(void *cookie, struct apple_rtkit_shmem *bfr) 150 { 151 struct apple_dcp *dcp = cookie; 152 153 if (bfr->iova) { 154 struct iommu_domain *domain = 155 iommu_get_domain_for_dev(dcp->dev); 156 phys_addr_t phy_addr; 157 158 if (!domain) 159 return -ENOMEM; 160 161 // TODO: get map from device-tree 162 phy_addr = iommu_iova_to_phys(domain, bfr->iova); 163 if (!phy_addr) 164 return -ENOMEM; 165 166 // TODO: verify phy_addr, cache attribute 167 bfr->buffer = memremap(phy_addr, bfr->size, MEMREMAP_WB); 168 if (!bfr->buffer) 169 return -ENOMEM; 170 171 bfr->is_mapped = true; 172 dev_info(dcp->dev, 173 "shmem_setup: iova: %lx -> pa: %lx -> iomem: %lx\n", 174 (uintptr_t)bfr->iova, (uintptr_t)phy_addr, 175 (uintptr_t)bfr->buffer); 176 } else { 177 bfr->buffer = dma_alloc_coherent(dcp->dev, bfr->size, 178 &bfr->iova, GFP_KERNEL); 179 if (!bfr->buffer) 180 return -ENOMEM; 181 182 dev_info(dcp->dev, "shmem_setup: iova: %lx, buffer: %lx\n", 183 (uintptr_t)bfr->iova, (uintptr_t)bfr->buffer); 184 } 185 186 return 0; 187 } 188 189 static void dcp_rtk_shmem_destroy(void *cookie, struct apple_rtkit_shmem *bfr) 190 { 191 struct apple_dcp *dcp = cookie; 192 193 if (bfr->is_mapped) 194 memunmap(bfr->buffer); 195 else 196 dma_free_coherent(dcp->dev, bfr->size, bfr->buffer, bfr->iova); 197 } 198 199 static struct apple_rtkit_ops rtkit_ops = { 200 .crashed = dcp_rtk_crashed, 201 .recv_message = dcp_recv_msg, 202 .shmem_setup = dcp_rtk_shmem_setup, 203 .shmem_destroy = dcp_rtk_shmem_destroy, 204 }; 205 206 void dcp_send_message(struct apple_dcp *dcp, u8 endpoint, u64 message) 207 { 208 trace_dcp_send_msg(dcp, endpoint, message); 209 apple_rtkit_send_message(dcp->rtk, endpoint, message, NULL, 210 true); 211 } 212 213 int dcp_crtc_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state) 214 { 215 struct platform_device *pdev = to_apple_crtc(crtc)->dcp; 216 struct apple_dcp *dcp = platform_get_drvdata(pdev); 217 struct drm_plane_state *new_state; 218 struct drm_plane *plane; 219 struct drm_crtc_state *crtc_state; 220 int plane_idx, plane_count = 0; 221 bool needs_modeset; 222 223 if (dcp->crashed) 224 return -EINVAL; 225 226 crtc_state = drm_atomic_get_new_crtc_state(state, crtc); 227 228 needs_modeset = drm_atomic_crtc_needs_modeset(crtc_state) || !dcp->valid_mode; 229 if (!needs_modeset && !dcp->connector->connected) { 230 dev_err(dcp->dev, "crtc_atomic_check: disconnected but no modeset\n"); 231 return -EINVAL; 232 } 233 234 for_each_new_plane_in_state(state, plane, new_state, plane_idx) { 235 /* skip planes not for this crtc */ 236 if (new_state->crtc != crtc) 237 continue; 238 239 plane_count += 1; 240 } 241 242 if (plane_count > DCP_MAX_PLANES) { 243 dev_err(dcp->dev, "crtc_atomic_check: Blend supports only 2 layers!\n"); 244 return -EINVAL; 245 } 246 247 return 0; 248 } 249 EXPORT_SYMBOL_GPL(dcp_crtc_atomic_check); 250 251 int dcp_get_connector_type(struct platform_device *pdev) 252 { 253 struct apple_dcp *dcp = platform_get_drvdata(pdev); 254 255 return (dcp->connector_type); 256 } 257 EXPORT_SYMBOL_GPL(dcp_get_connector_type); 258 259 #define DPTX_CONNECT_TIMEOUT msecs_to_jiffies(1000) 260 261 static int dcp_dptx_connect(struct apple_dcp *dcp, u32 port) 262 { 263 int ret = 0; 264 265 if (!dcp->phy) { 266 dev_warn(dcp->dev, "dcp_dptx_connect: missing phy\n"); 267 return -ENODEV; 268 } 269 dev_info(dcp->dev, "%s(port=%d)\n", __func__, port); 270 271 mutex_lock(&dcp->hpd_mutex); 272 if (!dcp->dptxport[port].enabled) { 273 dev_warn(dcp->dev, "dcp_dptx_connect: dptx service for port %d not enabled\n", port); 274 ret = -ENODEV; 275 goto out_unlock; 276 } 277 278 if (dcp->dptxport[port].connected) 279 goto out_unlock; 280 281 reinit_completion(&dcp->dptxport[port].linkcfg_completion); 282 dcp->dptxport[port].atcphy = dcp->phy; 283 dptxport_connect(dcp->dptxport[port].service, 0, dcp->dptx_phy, dcp->dptx_die); 284 dptxport_request_display(dcp->dptxport[port].service); 285 dcp->dptxport[port].connected = true; 286 287 mutex_unlock(&dcp->hpd_mutex); 288 ret = wait_for_completion_timeout(&dcp->dptxport[port].linkcfg_completion, 289 DPTX_CONNECT_TIMEOUT); 290 if (ret < 0) 291 dev_warn(dcp->dev, "dcp_dptx_connect: port %d link complete failed:%d\n", 292 port, ret); 293 else 294 dev_dbg(dcp->dev, "dcp_dptx_connect: waited %d ms for link\n", 295 jiffies_to_msecs(DPTX_CONNECT_TIMEOUT - ret)); 296 297 usleep_range(5, 10); 298 299 return 0; 300 301 out_unlock: 302 mutex_unlock(&dcp->hpd_mutex); 303 return ret; 304 } 305 306 static int dcp_dptx_disconnect(struct apple_dcp *dcp, u32 port) 307 { 308 dev_info(dcp->dev, "%s(port=%d)\n", __func__, port); 309 310 mutex_lock(&dcp->hpd_mutex); 311 if (dcp->dptxport[port].enabled && dcp->dptxport[port].connected) { 312 dptxport_release_display(dcp->dptxport[port].service); 313 dcp->dptxport[port].connected = false; 314 } 315 mutex_unlock(&dcp->hpd_mutex); 316 317 return 0; 318 } 319 320 static irqreturn_t dcp_dp2hdmi_hpd(int irq, void *data) 321 { 322 struct apple_dcp *dcp = data; 323 bool connected = gpiod_get_value_cansleep(dcp->hdmi_hpd); 324 325 /* do nothing on disconnect and trust that dcp detects it itself. 326 * Parallel disconnect HPDs result drm disabling the CRTC even when it 327 * should not. 328 * The interrupt should be changed to rising but for now the disconnect 329 * IRQs might be helpful for debugging. 330 */ 331 dev_info(dcp->dev, "DP2HDMI HPD irq, connected:%d\n", connected); 332 333 if (connected) 334 dcp_dptx_connect(dcp, 0); 335 336 return IRQ_HANDLED; 337 } 338 339 void dcp_link(struct platform_device *pdev, struct apple_crtc *crtc, 340 struct apple_connector *connector) 341 { 342 struct apple_dcp *dcp = platform_get_drvdata(pdev); 343 344 dcp->crtc = crtc; 345 dcp->connector = connector; 346 } 347 EXPORT_SYMBOL_GPL(dcp_link); 348 349 int dcp_start(struct platform_device *pdev) 350 { 351 struct apple_dcp *dcp = platform_get_drvdata(pdev); 352 int ret; 353 354 init_completion(&dcp->start_done); 355 356 /* start RTKit endpoints */ 357 ret = systemep_init(dcp); 358 if (ret) 359 dev_warn(dcp->dev, "Failed to start system endpoint: %d\n", ret); 360 361 if (dcp->phy && dcp->fw_compat >= DCP_FIRMWARE_V_13_5) { 362 ret = ibootep_init(dcp); 363 if (ret) 364 dev_warn(dcp->dev, "Failed to start IBOOT endpoint: %d\n", 365 ret); 366 367 ret = dptxep_init(dcp); 368 if (ret) 369 dev_warn(dcp->dev, "Failed to start DPTX endpoint: %d\n", 370 ret); 371 else if (dcp->dptxport[0].enabled) { 372 bool connected; 373 /* force disconnect on start - necessary if the display 374 * is already up from m1n1 375 */ 376 dptxport_set_hpd(dcp->dptxport[0].service, false); 377 dptxport_release_display(dcp->dptxport[0].service); 378 usleep_range(10 * USEC_PER_MSEC, 25 * USEC_PER_MSEC); 379 380 connected = gpiod_get_value_cansleep(dcp->hdmi_hpd); 381 dev_info(dcp->dev, "%s: DP2HDMI HPD connected:%d\n", __func__, connected); 382 383 // necessary on j473/j474 but not on j314c 384 if (connected) 385 dcp_dptx_connect(dcp, 0); 386 } 387 } else if (dcp->phy) 388 dev_warn(dcp->dev, "OS firmware incompatible with dptxport EP\n"); 389 390 ret = iomfb_start_rtkit(dcp); 391 if (ret) 392 dev_err(dcp->dev, "Failed to start IOMFB endpoint: %d\n", ret); 393 394 return ret; 395 } 396 EXPORT_SYMBOL(dcp_start); 397 398 static int dcp_enable_dp2hdmi_hpd(struct apple_dcp *dcp) 399 { 400 if (dcp->hdmi_hpd_irq) 401 enable_irq(dcp->hdmi_hpd_irq); 402 403 return 0; 404 } 405 406 int dcp_wait_ready(struct platform_device *pdev, u64 timeout) 407 { 408 struct apple_dcp *dcp = platform_get_drvdata(pdev); 409 int ret; 410 411 if (dcp->crashed) 412 return -ENODEV; 413 if (dcp->active) 414 return dcp_enable_dp2hdmi_hpd(dcp);; 415 if (timeout <= 0) 416 return -ETIMEDOUT; 417 418 ret = wait_for_completion_timeout(&dcp->start_done, timeout); 419 if (ret < 0) 420 return ret; 421 422 if (dcp->crashed) 423 return -ENODEV; 424 425 if (dcp->active) 426 dcp_enable_dp2hdmi_hpd(dcp); 427 428 return dcp->active ? 0 : -ETIMEDOUT; 429 } 430 EXPORT_SYMBOL(dcp_wait_ready); 431 432 static void __maybe_unused dcp_sleep(struct apple_dcp *dcp) 433 { 434 switch (dcp->fw_compat) { 435 case DCP_FIRMWARE_V_12_3: 436 iomfb_sleep_v12_3(dcp); 437 break; 438 case DCP_FIRMWARE_V_13_5: 439 iomfb_sleep_v13_3(dcp); 440 break; 441 default: 442 WARN_ONCE(true, "Unexpected firmware version: %u\n", dcp->fw_compat); 443 break; 444 } 445 } 446 447 void dcp_poweron(struct platform_device *pdev) 448 { 449 struct apple_dcp *dcp = platform_get_drvdata(pdev); 450 451 if (dcp->hdmi_hpd) { 452 bool connected = gpiod_get_value_cansleep(dcp->hdmi_hpd); 453 dev_info(dcp->dev, "%s: DP2HDMI HPD connected:%d\n", __func__, connected); 454 455 if (connected) 456 dcp_dptx_connect(dcp, 0); 457 } 458 459 switch (dcp->fw_compat) { 460 case DCP_FIRMWARE_V_12_3: 461 iomfb_poweron_v12_3(dcp); 462 break; 463 case DCP_FIRMWARE_V_13_5: 464 iomfb_poweron_v13_3(dcp); 465 break; 466 default: 467 WARN_ONCE(true, "Unexpected firmware version: %u\n", dcp->fw_compat); 468 break; 469 } 470 } 471 EXPORT_SYMBOL(dcp_poweron); 472 473 void dcp_poweroff(struct platform_device *pdev) 474 { 475 struct apple_dcp *dcp = platform_get_drvdata(pdev); 476 477 switch (dcp->fw_compat) { 478 case DCP_FIRMWARE_V_12_3: 479 iomfb_poweroff_v12_3(dcp); 480 break; 481 case DCP_FIRMWARE_V_13_5: 482 iomfb_poweroff_v13_3(dcp); 483 break; 484 default: 485 WARN_ONCE(true, "Unexpected firmware version: %u\n", dcp->fw_compat); 486 break; 487 } 488 489 if (dcp->hdmi_hpd) { 490 bool connected = gpiod_get_value_cansleep(dcp->hdmi_hpd); 491 if (!connected) 492 dcp_dptx_disconnect(dcp, 0); 493 } 494 } 495 EXPORT_SYMBOL(dcp_poweroff); 496 497 static void dcp_work_register_backlight(struct work_struct *work) 498 { 499 int ret; 500 struct apple_dcp *dcp; 501 502 dcp = container_of(work, struct apple_dcp, bl_register_wq); 503 504 mutex_lock(&dcp->bl_register_mutex); 505 if (dcp->brightness.bl_dev) 506 goto out_unlock; 507 508 /* try to register backlight device, */ 509 ret = dcp_backlight_register(dcp); 510 if (ret) { 511 dev_err(dcp->dev, "Unable to register backlight device\n"); 512 dcp->brightness.maximum = 0; 513 } 514 515 out_unlock: 516 mutex_unlock(&dcp->bl_register_mutex); 517 } 518 519 static void dcp_work_update_backlight(struct work_struct *work) 520 { 521 struct apple_dcp *dcp; 522 523 dcp = container_of(work, struct apple_dcp, bl_update_wq); 524 525 dcp_backlight_update(dcp); 526 } 527 528 static int dcp_create_piodma_iommu_dev(struct apple_dcp *dcp) 529 { 530 int ret; 531 struct device_node *node = of_get_child_by_name(dcp->dev->of_node, "piodma"); 532 533 if (!node) 534 return dev_err_probe(dcp->dev, -ENODEV, 535 "Failed to get piodma child DT node\n"); 536 537 dcp->piodma = of_platform_device_create(node, NULL, dcp->dev); 538 if (!dcp->piodma) { 539 of_node_put(node); 540 return dev_err_probe(dcp->dev, -ENODEV, "Failed to gcreate piodma pdev for %pOF\n", node); 541 } 542 543 ret = dma_set_mask_and_coherent(&dcp->piodma->dev, DMA_BIT_MASK(42)); 544 if (ret) 545 goto err_destroy_pdev; 546 547 ret = of_dma_configure(&dcp->piodma->dev, node, true); 548 if (ret) { 549 ret = dev_err_probe(dcp->dev, ret, 550 "Failed to configure IOMMU child DMA\n"); 551 goto err_destroy_pdev; 552 } 553 of_node_put(node); 554 555 dcp->iommu_dom = iommu_domain_alloc(&platform_bus_type); 556 if (!dcp->iommu_dom) { 557 ret = -ENOMEM; 558 goto err_destroy_pdev; 559 } 560 561 ret = iommu_attach_device(dcp->iommu_dom, &dcp->piodma->dev); 562 if (ret) { 563 ret = dev_err_probe(dcp->dev, ret, 564 "Failed to attach IOMMU child domain\n"); 565 goto err_free_domain; 566 } 567 568 return 0; 569 err_free_domain: 570 iommu_domain_free(dcp->iommu_dom); 571 err_destroy_pdev: 572 of_node_put(node); 573 of_platform_device_destroy(&dcp->piodma->dev, NULL); 574 return ret; 575 } 576 577 static int dcp_get_bw_scratch_reg(struct apple_dcp *dcp, u32 expected) 578 { 579 struct of_phandle_args ph_args; 580 u32 addr_idx, disp_idx, offset; 581 int ret; 582 583 ret = of_parse_phandle_with_args(dcp->dev->of_node, "apple,bw-scratch", 584 "#apple,bw-scratch-cells", 0, &ph_args); 585 if (ret < 0) { 586 dev_err(dcp->dev, "Failed to read 'apple,bw-scratch': %d\n", ret); 587 return ret; 588 } 589 590 if (ph_args.args_count != 3) { 591 dev_err(dcp->dev, "Unexpected 'apple,bw-scratch' arg count %d\n", 592 ph_args.args_count); 593 ret = -EINVAL; 594 goto err_of_node_put; 595 } 596 597 addr_idx = ph_args.args[0]; 598 disp_idx = ph_args.args[1]; 599 offset = ph_args.args[2]; 600 601 if (disp_idx != expected || disp_idx >= MAX_DISP_REGISTERS) { 602 dev_err(dcp->dev, "Unexpected disp_reg value in 'apple,bw-scratch': %d\n", 603 disp_idx); 604 ret = -EINVAL; 605 goto err_of_node_put; 606 } 607 608 ret = of_address_to_resource(ph_args.np, addr_idx, &dcp->disp_bw_scratch_res); 609 if (ret < 0) { 610 dev_err(dcp->dev, "Failed to get 'apple,bw-scratch' resource %d from %pOF\n", 611 addr_idx, ph_args.np); 612 goto err_of_node_put; 613 } 614 if (offset > resource_size(&dcp->disp_bw_scratch_res) - 4) { 615 ret = -EINVAL; 616 goto err_of_node_put; 617 } 618 619 dcp->disp_registers[disp_idx] = &dcp->disp_bw_scratch_res; 620 dcp->disp_bw_scratch_index = disp_idx; 621 dcp->disp_bw_scratch_offset = offset; 622 ret = 0; 623 624 err_of_node_put: 625 of_node_put(ph_args.np); 626 return ret; 627 } 628 629 static int dcp_get_bw_doorbell_reg(struct apple_dcp *dcp, u32 expected) 630 { 631 struct of_phandle_args ph_args; 632 u32 addr_idx, disp_idx; 633 int ret; 634 635 ret = of_parse_phandle_with_args(dcp->dev->of_node, "apple,bw-doorbell", 636 "#apple,bw-doorbell-cells", 0, &ph_args); 637 if (ret < 0) { 638 dev_err(dcp->dev, "Failed to read 'apple,bw-doorbell': %d\n", ret); 639 return ret; 640 } 641 642 if (ph_args.args_count != 2) { 643 dev_err(dcp->dev, "Unexpected 'apple,bw-doorbell' arg count %d\n", 644 ph_args.args_count); 645 ret = -EINVAL; 646 goto err_of_node_put; 647 } 648 649 addr_idx = ph_args.args[0]; 650 disp_idx = ph_args.args[1]; 651 652 if (disp_idx != expected || disp_idx >= MAX_DISP_REGISTERS) { 653 dev_err(dcp->dev, "Unexpected disp_reg value in 'apple,bw-doorbell': %d\n", 654 disp_idx); 655 ret = -EINVAL; 656 goto err_of_node_put; 657 } 658 659 ret = of_address_to_resource(ph_args.np, addr_idx, &dcp->disp_bw_doorbell_res); 660 if (ret < 0) { 661 dev_err(dcp->dev, "Failed to get 'apple,bw-doorbell' resource %d from %pOF\n", 662 addr_idx, ph_args.np); 663 goto err_of_node_put; 664 } 665 dcp->disp_bw_doorbell_index = disp_idx; 666 dcp->disp_registers[disp_idx] = &dcp->disp_bw_doorbell_res; 667 ret = 0; 668 669 err_of_node_put: 670 of_node_put(ph_args.np); 671 return ret; 672 } 673 674 static int dcp_get_disp_regs(struct apple_dcp *dcp) 675 { 676 struct platform_device *pdev = to_platform_device(dcp->dev); 677 int count = pdev->num_resources - 1; 678 int i, ret; 679 680 if (count <= 0 || count > MAX_DISP_REGISTERS) 681 return -EINVAL; 682 683 for (i = 0; i < count; ++i) { 684 dcp->disp_registers[i] = 685 platform_get_resource(pdev, IORESOURCE_MEM, 1 + i); 686 } 687 688 /* load pmgr bandwidth scratch resource and offset */ 689 ret = dcp_get_bw_scratch_reg(dcp, count); 690 if (ret < 0) 691 return ret; 692 count += 1; 693 694 /* load pmgr bandwidth doorbell resource if present (only on t8103) */ 695 if (of_property_present(dcp->dev->of_node, "apple,bw-doorbell")) { 696 ret = dcp_get_bw_doorbell_reg(dcp, count); 697 if (ret < 0) 698 return ret; 699 count += 1; 700 } 701 702 dcp->nr_disp_registers = count; 703 return 0; 704 } 705 706 #define DCP_FW_VERSION_MIN_LEN 3 707 #define DCP_FW_VERSION_MAX_LEN 5 708 #define DCP_FW_VERSION_STR_LEN (DCP_FW_VERSION_MAX_LEN * 4) 709 710 static int dcp_read_fw_version(struct device *dev, const char *name, 711 char *version_str) 712 { 713 u32 ver[DCP_FW_VERSION_MAX_LEN]; 714 int len_str; 715 int len; 716 717 len = of_property_read_variable_u32_array(dev->of_node, name, ver, 718 DCP_FW_VERSION_MIN_LEN, 719 DCP_FW_VERSION_MAX_LEN); 720 721 switch (len) { 722 case 3: 723 len_str = scnprintf(version_str, DCP_FW_VERSION_STR_LEN, 724 "%d.%d.%d", ver[0], ver[1], ver[2]); 725 break; 726 case 4: 727 len_str = scnprintf(version_str, DCP_FW_VERSION_STR_LEN, 728 "%d.%d.%d.%d", ver[0], ver[1], ver[2], 729 ver[3]); 730 break; 731 case 5: 732 len_str = scnprintf(version_str, DCP_FW_VERSION_STR_LEN, 733 "%d.%d.%d.%d.%d", ver[0], ver[1], ver[2], 734 ver[3], ver[4]); 735 break; 736 default: 737 len_str = strscpy(version_str, "UNKNOWN", 738 DCP_FW_VERSION_STR_LEN); 739 if (len >= 0) 740 len = -EOVERFLOW; 741 break; 742 } 743 744 if (len_str >= DCP_FW_VERSION_STR_LEN) 745 dev_warn(dev, "'%s' truncated: '%s'\n", name, version_str); 746 747 return len; 748 } 749 750 static enum dcp_firmware_version dcp_check_firmware_version(struct device *dev) 751 { 752 char compat_str[DCP_FW_VERSION_STR_LEN]; 753 char fw_str[DCP_FW_VERSION_STR_LEN]; 754 int ret; 755 756 /* firmware version is just informative */ 757 dcp_read_fw_version(dev, "apple,firmware-version", fw_str); 758 759 ret = dcp_read_fw_version(dev, "apple,firmware-compat", compat_str); 760 if (ret < 0) { 761 dev_err(dev, "Could not read 'apple,firmware-compat': %d\n", ret); 762 return DCP_FIRMWARE_UNKNOWN; 763 } 764 765 if (strncmp(compat_str, "12.3.0", sizeof(compat_str)) == 0) 766 return DCP_FIRMWARE_V_12_3; 767 /* 768 * m1n1 reports firmware version 13.5 as compatible with 13.3. This is 769 * only true for the iomfb endpoint. The interface for the dptx-port 770 * endpoint changed between 13.3 and 13.5. The driver will only support 771 * firmware 13.5. Check the actual firmware version for compat version 772 * 13.3 until m1n1 reports 13.5 as "firmware-compat". 773 */ 774 else if ((strncmp(compat_str, "13.3.0", sizeof(compat_str)) == 0) && 775 (strncmp(fw_str, "13.5.0", sizeof(compat_str)) == 0)) 776 return DCP_FIRMWARE_V_13_5; 777 else if (strncmp(compat_str, "13.5.0", sizeof(compat_str)) == 0) 778 return DCP_FIRMWARE_V_13_5; 779 780 dev_err(dev, "DCP firmware-compat %s (FW: %s) is not supported\n", 781 compat_str, fw_str); 782 783 return DCP_FIRMWARE_UNKNOWN; 784 } 785 786 static int dcp_comp_bind(struct device *dev, struct device *main, void *data) 787 { 788 struct device_node *panel_np; 789 struct apple_dcp *dcp = dev_get_drvdata(dev); 790 u32 cpu_ctrl; 791 int ret; 792 793 ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(42)); 794 if (ret) 795 return ret; 796 797 dcp->coproc_reg = devm_platform_ioremap_resource_byname(to_platform_device(dev), "coproc"); 798 if (IS_ERR(dcp->coproc_reg)) 799 return PTR_ERR(dcp->coproc_reg); 800 801 of_property_read_u32(dev->of_node, "apple,dcp-index", 802 &dcp->index); 803 of_property_read_u32(dev->of_node, "apple,dptx-phy", 804 &dcp->dptx_phy); 805 of_property_read_u32(dev->of_node, "apple,dptx-die", 806 &dcp->dptx_die); 807 if (dcp->index || dcp->dptx_phy || dcp->dptx_die) 808 dev_info(dev, "DCP index:%u dptx target phy: %u dptx die: %u\n", 809 dcp->index, dcp->dptx_phy, dcp->dptx_die); 810 rw_init(&dcp->hpd_mutex, "aplhpd"); 811 812 if (!show_notch) 813 ret = of_property_read_u32(dev->of_node, "apple,notch-height", 814 &dcp->notch_height); 815 816 if (dcp->notch_height > MAX_NOTCH_HEIGHT) 817 dcp->notch_height = MAX_NOTCH_HEIGHT; 818 if (dcp->notch_height > 0) 819 dev_info(dev, "Detected display with notch of %u pixel\n", dcp->notch_height); 820 821 /* initialize brightness scale to a sensible default to avoid divide by 0*/ 822 dcp->brightness.scale = 65536; 823 panel_np = of_get_compatible_child(dev->of_node, "apple,panel-mini-led"); 824 if (panel_np) 825 dcp->panel.has_mini_led = true; 826 else 827 panel_np = of_get_compatible_child(dev->of_node, "apple,panel"); 828 829 if (panel_np) { 830 const char height_prop[2][16] = { "adj-height-mm", "height-mm" }; 831 832 if (of_device_is_available(panel_np)) { 833 ret = of_property_read_u32(panel_np, "apple,max-brightness", 834 &dcp->brightness.maximum); 835 if (ret) 836 dev_err(dev, "Missing property 'apple,max-brightness'\n"); 837 } 838 839 of_property_read_u32(panel_np, "width-mm", &dcp->panel.width_mm); 840 /* use adjusted height as long as the notch is hidden */ 841 of_property_read_u32(panel_np, height_prop[!dcp->notch_height], 842 &dcp->panel.height_mm); 843 844 of_node_put(panel_np); 845 dcp->connector_type = DRM_MODE_CONNECTOR_eDP; 846 INIT_WORK(&dcp->bl_register_wq, dcp_work_register_backlight); 847 rw_init(&dcp->bl_register_mutex, "dcpbl"); 848 INIT_WORK(&dcp->bl_update_wq, dcp_work_update_backlight); 849 } else if (of_property_match_string(dev->of_node, "apple,connector-type", "HDMI-A") >= 0) 850 dcp->connector_type = DRM_MODE_CONNECTOR_HDMIA; 851 else if (of_property_match_string(dev->of_node, "apple,connector-type", "DP") >= 0) 852 dcp->connector_type = DRM_MODE_CONNECTOR_DisplayPort; 853 else if (of_property_match_string(dev->of_node, "apple,connector-type", "USB-C") >= 0) 854 dcp->connector_type = DRM_MODE_CONNECTOR_USB; 855 else 856 dcp->connector_type = DRM_MODE_CONNECTOR_Unknown; 857 858 ret = dcp_create_piodma_iommu_dev(dcp); 859 if (ret) 860 return dev_err_probe(dev, ret, 861 "Failed to created PIODMA iommu child device"); 862 863 ret = dcp_get_disp_regs(dcp); 864 if (ret) { 865 dev_err(dev, "failed to find display registers\n"); 866 return ret; 867 } 868 869 dcp->clk = devm_clk_get(dev, NULL); 870 if (IS_ERR(dcp->clk)) 871 return dev_err_probe(dev, PTR_ERR(dcp->clk), 872 "Unable to find clock\n"); 873 874 bitmap_zero(dcp->memdesc_map, DCP_MAX_MAPPINGS); 875 // TDOD: mem_desc IDs start at 1, for simplicity just skip '0' entry 876 set_bit(0, dcp->memdesc_map); 877 878 INIT_WORK(&dcp->vblank_wq, dcp_delayed_vblank); 879 880 dcp->swapped_out_fbs = 881 (struct list_head)LIST_HEAD_INIT(dcp->swapped_out_fbs); 882 883 cpu_ctrl = 884 readl_relaxed(dcp->coproc_reg + APPLE_DCP_COPROC_CPU_CONTROL); 885 writel_relaxed(cpu_ctrl | APPLE_DCP_COPROC_CPU_CONTROL_RUN, 886 dcp->coproc_reg + APPLE_DCP_COPROC_CPU_CONTROL); 887 888 dcp->rtk = devm_apple_rtkit_init(dev, dcp, "mbox", 0, &rtkit_ops); 889 if (IS_ERR(dcp->rtk)) 890 return dev_err_probe(dev, PTR_ERR(dcp->rtk), 891 "Failed to initialize RTKit\n"); 892 893 ret = apple_rtkit_wake(dcp->rtk); 894 if (ret) 895 return dev_err_probe(dev, ret, 896 "Failed to boot RTKit: %d\n", ret); 897 return ret; 898 } 899 900 /* 901 * We need to shutdown DCP before tearing down the display subsystem. Otherwise 902 * the DCP will crash and briefly flash a green screen of death. 903 */ 904 static void dcp_comp_unbind(struct device *dev, struct device *main, void *data) 905 { 906 struct apple_dcp *dcp = dev_get_drvdata(dev); 907 908 if (dcp->hdmi_hpd_irq) 909 disable_irq(dcp->hdmi_hpd_irq); 910 911 if (dcp && dcp->shmem) 912 iomfb_shutdown(dcp); 913 914 if (dcp->piodma) { 915 iommu_detach_device(dcp->iommu_dom, &dcp->piodma->dev); 916 iommu_domain_free(dcp->iommu_dom); 917 /* TODO: the piodma platform device has to be destroyed but 918 * doing so leads to all kind of breakage. 919 */ 920 // of_platform_device_destroy(&dcp->piodma->dev, NULL); 921 dcp->piodma = NULL; 922 } 923 924 devm_clk_put(dev, dcp->clk); 925 dcp->clk = NULL; 926 } 927 928 static const struct component_ops dcp_comp_ops = { 929 .bind = dcp_comp_bind, 930 .unbind = dcp_comp_unbind, 931 }; 932 933 static int dcp_platform_probe(struct platform_device *pdev) 934 { 935 enum dcp_firmware_version fw_compat; 936 struct device *dev = &pdev->dev; 937 struct apple_dcp *dcp; 938 u32 mux_index; 939 940 fw_compat = dcp_check_firmware_version(dev); 941 if (fw_compat == DCP_FIRMWARE_UNKNOWN) 942 return -ENODEV; 943 944 /* Check for "apple,bw-scratch" to avoid probing appledrm with outdated 945 * device trees. This prevents replacing simpledrm and ending up without 946 * display. 947 */ 948 if (!of_property_present(dev->of_node, "apple,bw-scratch")) 949 return dev_err_probe(dev, -ENODEV, "Incompatible devicetree! " 950 "Use devicetree matching this kernel.\n"); 951 952 dcp = devm_kzalloc(dev, sizeof(*dcp), GFP_KERNEL); 953 if (!dcp) 954 return -ENOMEM; 955 956 dcp->fw_compat = fw_compat; 957 dcp->dev = dev; 958 dcp->hw = *(struct apple_dcp_hw_data *)of_device_get_match_data(dev); 959 960 platform_set_drvdata(pdev, dcp); 961 962 dcp->phy = devm_phy_optional_get(dev, "dp-phy"); 963 if (IS_ERR(dcp->phy)) { 964 dev_err(dev, "Failed to get dp-phy: %ld\n", PTR_ERR(dcp->phy)); 965 return PTR_ERR(dcp->phy); 966 } 967 if (dcp->phy) { 968 int ret; 969 /* 970 * Request DP2HDMI related GPIOs as optional for DP-altmode 971 * compatibility. J180D misses a dp2hdmi-pwren GPIO in the 972 * template ADT. TODO: check device ADT 973 */ 974 dcp->hdmi_hpd = devm_gpiod_get_optional(dev, "hdmi-hpd", GPIOD_IN); 975 if (IS_ERR(dcp->hdmi_hpd)) 976 return PTR_ERR(dcp->hdmi_hpd); 977 if (dcp->hdmi_hpd) { 978 int irq = gpiod_to_irq(dcp->hdmi_hpd); 979 if (irq < 0) { 980 dev_err(dev, "failed to translate HDMI hpd GPIO to IRQ\n"); 981 return irq; 982 } 983 dcp->hdmi_hpd_irq = irq; 984 985 ret = devm_request_threaded_irq(dev, dcp->hdmi_hpd_irq, 986 NULL, dcp_dp2hdmi_hpd, 987 IRQF_ONESHOT | IRQF_NO_AUTOEN | 988 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, 989 "dp2hdmi-hpd-irq", dcp); 990 if (ret < 0) { 991 dev_err(dev, "failed to request HDMI hpd irq %d: %d\n", 992 irq, ret); 993 return ret; 994 } 995 } 996 997 /* 998 * Power DP2HDMI on as it is required for the HPD irq. 999 * TODO: check if one is sufficient for the hpd to save power 1000 * on battery powered Macbooks. 1001 */ 1002 dcp->hdmi_pwren = devm_gpiod_get_optional(dev, "hdmi-pwren", GPIOD_OUT_HIGH); 1003 if (IS_ERR(dcp->hdmi_pwren)) 1004 return PTR_ERR(dcp->hdmi_pwren); 1005 1006 dcp->dp2hdmi_pwren = devm_gpiod_get_optional(dev, "dp2hdmi-pwren", GPIOD_OUT_HIGH); 1007 if (IS_ERR(dcp->dp2hdmi_pwren)) 1008 return PTR_ERR(dcp->dp2hdmi_pwren); 1009 1010 ret = of_property_read_u32(dev->of_node, "mux-index", &mux_index); 1011 if (!ret) { 1012 dcp->xbar = devm_mux_control_get(dev, "dp-xbar"); 1013 if (IS_ERR(dcp->xbar)) { 1014 dev_err(dev, "Failed to get dp-xbar: %ld\n", PTR_ERR(dcp->xbar)); 1015 return PTR_ERR(dcp->xbar); 1016 } 1017 ret = mux_control_select(dcp->xbar, mux_index); 1018 if (ret) 1019 dev_warn(dev, "mux_control_select failed: %d\n", ret); 1020 } 1021 } 1022 1023 return component_add(&pdev->dev, &dcp_comp_ops); 1024 } 1025 1026 #ifdef __linux__ 1027 1028 static int dcp_platform_remove(struct platform_device *pdev) 1029 { 1030 component_del(&pdev->dev, &dcp_comp_ops); 1031 1032 return 0; 1033 } 1034 1035 static void dcp_platform_shutdown(struct platform_device *pdev) 1036 { 1037 component_del(&pdev->dev, &dcp_comp_ops); 1038 } 1039 1040 #endif 1041 1042 static int dcp_platform_suspend(struct device *dev) 1043 { 1044 struct apple_dcp *dcp = dev_get_drvdata(dev); 1045 1046 if (dcp->hdmi_hpd_irq) { 1047 disable_irq(dcp->hdmi_hpd_irq); 1048 dcp_dptx_disconnect(dcp, 0); 1049 } 1050 /* 1051 * Set the device as a wakeup device, which forces its power 1052 * domains to stay on. We need this as we do not support full 1053 * shutdown properly yet. 1054 */ 1055 device_set_wakeup_path(dev); 1056 1057 return 0; 1058 } 1059 1060 static int dcp_platform_resume(struct device *dev) 1061 { 1062 struct apple_dcp *dcp = dev_get_drvdata(dev); 1063 1064 if (dcp->hdmi_hpd_irq) 1065 enable_irq(dcp->hdmi_hpd_irq); 1066 1067 if (dcp->hdmi_hpd) { 1068 bool connected = gpiod_get_value_cansleep(dcp->hdmi_hpd); 1069 dev_info(dcp->dev, "resume: HPD connected:%d\n", connected); 1070 if (connected) 1071 dcp_dptx_connect(dcp, 0); 1072 } 1073 1074 return 0; 1075 } 1076 1077 static DEFINE_SIMPLE_DEV_PM_OPS(dcp_platform_pm_ops, 1078 dcp_platform_suspend, dcp_platform_resume); 1079 1080 1081 static const struct apple_dcp_hw_data apple_dcp_hw_t6020 = { 1082 .num_dptx_ports = 1, 1083 }; 1084 1085 static const struct apple_dcp_hw_data apple_dcp_hw_t8112 = { 1086 .num_dptx_ports = 2, 1087 }; 1088 1089 static const struct apple_dcp_hw_data apple_dcp_hw_dcp = { 1090 .num_dptx_ports = 0, 1091 }; 1092 1093 static const struct apple_dcp_hw_data apple_dcp_hw_dcpext = { 1094 .num_dptx_ports = 2, 1095 }; 1096 1097 static const struct of_device_id of_match[] = { 1098 { .compatible = "apple,t6020-dcp", .data = &apple_dcp_hw_t6020, }, 1099 { .compatible = "apple,t8112-dcp", .data = &apple_dcp_hw_t8112, }, 1100 { .compatible = "apple,dcp", .data = &apple_dcp_hw_dcp, }, 1101 { .compatible = "apple,dcpext", .data = &apple_dcp_hw_dcpext, }, 1102 {} 1103 }; 1104 MODULE_DEVICE_TABLE(of, of_match); 1105 1106 #ifdef __linux__ 1107 1108 static struct platform_driver apple_platform_driver = { 1109 .probe = dcp_platform_probe, 1110 .remove = dcp_platform_remove, 1111 .shutdown = dcp_platform_shutdown, 1112 .driver = { 1113 .name = "apple-dcp", 1114 .of_match_table = of_match, 1115 .pm = pm_sleep_ptr(&dcp_platform_pm_ops), 1116 }, 1117 }; 1118 1119 drm_module_platform_driver(apple_platform_driver); 1120 1121 MODULE_AUTHOR("Alyssa Rosenzweig <alyssa@rosenzweig.io>"); 1122 MODULE_DESCRIPTION("Apple Display Controller DRM driver"); 1123 MODULE_LICENSE("Dual MIT/GPL"); 1124 1125 #endif 1126