1 // SPDX-License-Identifier: GPL-2.0-only OR MIT 2 /* 3 * Copyright 2021 Alyssa Rosenzweig <alyssa@rosenzweig.io> 4 * Copyright The Asahi Linux Contributors 5 */ 6 7 #include <linux/align.h> 8 #include <linux/bitmap.h> 9 #include <linux/clk.h> 10 #include <linux/completion.h> 11 #include <linux/delay.h> 12 #include <linux/dma-mapping.h> 13 #include <linux/iommu.h> 14 #include <linux/kref.h> 15 #include <linux/module.h> 16 #include <linux/of_device.h> 17 #include <linux/pm_runtime.h> 18 #include <linux/slab.h> 19 20 #include <drm/drm_fb_dma_helper.h> 21 #include <drm/drm_fourcc.h> 22 #include <drm/drm_framebuffer.h> 23 #include <drm/drm_gem_dma_helper.h> 24 #include <drm/drm_probe_helper.h> 25 #include <drm/drm_vblank.h> 26 27 #include "dcp.h" 28 #include "dcp-internal.h" 29 #include "iomfb.h" 30 #include "iomfb_internal.h" 31 #include "parser.h" 32 #include "trace.h" 33 #include "version_utils.h" 34 35 /* Register defines used in bandwidth setup structure */ 36 #define REG_DOORBELL_BIT(idx) (2 + (idx)) 37 38 struct dcp_wait_cookie { 39 struct kref refcount; 40 struct completion done; 41 }; 42 43 static void release_wait_cookie(struct kref *ref) 44 { 45 struct dcp_wait_cookie *cookie; 46 cookie = container_of(ref, struct dcp_wait_cookie, refcount); 47 48 kfree(cookie); 49 } 50 51 DCP_THUNK_OUT(iomfb_a131_pmu_service_matched, iomfbep_a131_pmu_service_matched, u32); 52 DCP_THUNK_OUT(iomfb_a132_backlight_service_matched, iomfbep_a132_backlight_service_matched, u32); 53 DCP_THUNK_OUT(iomfb_a358_vi_set_temperature_hint, iomfbep_a358_vi_set_temperature_hint, u32); 54 55 IOMFB_THUNK_INOUT(set_matrix); 56 IOMFB_THUNK_INOUT(get_color_remap_mode); 57 IOMFB_THUNK_INOUT(last_client_close); 58 IOMFB_THUNK_INOUT(abort_swaps_dcp); 59 60 DCP_THUNK_INOUT(dcp_swap_submit, dcpep_swap_submit, 61 struct DCP_FW_NAME(dcp_swap_submit_req), 62 struct DCP_FW_NAME(dcp_swap_submit_resp)); 63 64 DCP_THUNK_INOUT(dcp_swap_start, dcpep_swap_start, struct dcp_swap_start_req, 65 struct dcp_swap_start_resp); 66 67 DCP_THUNK_INOUT(dcp_set_power_state, dcpep_set_power_state, 68 struct dcp_set_power_state_req, 69 struct dcp_set_power_state_resp); 70 71 DCP_THUNK_INOUT(dcp_set_digital_out_mode, dcpep_set_digital_out_mode, 72 struct dcp_set_digital_out_mode_req, u32); 73 74 DCP_THUNK_INOUT(dcp_set_display_device, dcpep_set_display_device, u32, u32); 75 76 DCP_THUNK_OUT(dcp_set_display_refresh_properties, 77 dcpep_set_display_refresh_properties, u32); 78 79 #if DCP_FW_VER >= DCP_FW_VERSION(13, 2, 0) 80 DCP_THUNK_INOUT(dcp_late_init_signal, dcpep_late_init_signal, u32, u32); 81 #else 82 DCP_THUNK_OUT(dcp_late_init_signal, dcpep_late_init_signal, u32); 83 #endif 84 DCP_THUNK_IN(dcp_flush_supports_power, dcpep_flush_supports_power, u32); 85 DCP_THUNK_OUT(dcp_create_default_fb, dcpep_create_default_fb, u32); 86 DCP_THUNK_OUT(dcp_start_signal, dcpep_start_signal, u32); 87 DCP_THUNK_VOID(dcp_setup_video_limits, dcpep_setup_video_limits); 88 DCP_THUNK_VOID(dcp_set_create_dfb, dcpep_set_create_dfb); 89 DCP_THUNK_VOID(dcp_first_client_open, dcpep_first_client_open); 90 91 DCP_THUNK_INOUT(dcp_set_parameter_dcp, dcpep_set_parameter_dcp, 92 struct dcp_set_parameter_dcp, u32); 93 94 DCP_THUNK_INOUT(dcp_enable_disable_video_power_savings, 95 dcpep_enable_disable_video_power_savings, u32, int); 96 97 DCP_THUNK_OUT(dcp_is_main_display, dcpep_is_main_display, u32); 98 99 /* DCP callback handlers */ 100 static void dcpep_cb_nop(struct apple_dcp *dcp) 101 { 102 /* No operation */ 103 } 104 105 static u8 dcpep_cb_true(struct apple_dcp *dcp) 106 { 107 return true; 108 } 109 110 static u8 dcpep_cb_false(struct apple_dcp *dcp) 111 { 112 return false; 113 } 114 115 static u32 dcpep_cb_zero(struct apple_dcp *dcp) 116 { 117 return 0; 118 } 119 120 static void dcpep_cb_swap_complete(struct apple_dcp *dcp, 121 struct DCP_FW_NAME(dc_swap_complete_resp) *resp) 122 { 123 trace_iomfb_swap_complete(dcp, resp->swap_id); 124 dcp->last_swap_id = resp->swap_id; 125 126 dcp_drm_crtc_vblank(dcp->crtc); 127 } 128 129 /* special */ 130 static void complete_vi_set_temperature_hint(struct apple_dcp *dcp, void *out, void *cookie) 131 { 132 // ack D100 cb_match_pmu_service 133 dcp_ack(dcp, DCP_CONTEXT_CB); 134 } 135 136 static bool iomfbep_cb_match_pmu_service(struct apple_dcp *dcp, int tag, void *out, void *in) 137 { 138 trace_iomfb_callback(dcp, tag, __func__); 139 iomfb_a358_vi_set_temperature_hint(dcp, false, 140 complete_vi_set_temperature_hint, 141 NULL); 142 143 // return false for deferred ACK 144 return false; 145 } 146 147 static void complete_pmu_service_matched(struct apple_dcp *dcp, void *out, void *cookie) 148 { 149 struct dcp_channel *ch = &dcp->ch_cb; 150 u8 *succ = ch->output[ch->depth - 1]; 151 152 *succ = true; 153 154 // ack D206 cb_match_pmu_service_2 155 dcp_ack(dcp, DCP_CONTEXT_CB); 156 } 157 158 static bool iomfbep_cb_match_pmu_service_2(struct apple_dcp *dcp, int tag, void *out, void *in) 159 { 160 trace_iomfb_callback(dcp, tag, __func__); 161 162 iomfb_a131_pmu_service_matched(dcp, false, complete_pmu_service_matched, 163 out); 164 165 // return false for deferred ACK 166 return false; 167 } 168 169 static void complete_backlight_service_matched(struct apple_dcp *dcp, void *out, void *cookie) 170 { 171 struct dcp_channel *ch = &dcp->ch_cb; 172 u8 *succ = ch->output[ch->depth - 1]; 173 174 *succ = true; 175 176 // ack D206 cb_match_backlight_service 177 dcp_ack(dcp, DCP_CONTEXT_CB); 178 } 179 180 static bool iomfbep_cb_match_backlight_service(struct apple_dcp *dcp, int tag, void *out, void *in) 181 { 182 trace_iomfb_callback(dcp, tag, __func__); 183 184 if (!dcp_has_panel(dcp)) { 185 u8 *succ = out; 186 *succ = true; 187 return true; 188 } 189 190 iomfb_a132_backlight_service_matched(dcp, false, complete_backlight_service_matched, out); 191 192 // return false for deferred ACK 193 return false; 194 } 195 196 static void iomfb_cb_pr_publish(struct apple_dcp *dcp, struct iomfb_property *prop) 197 { 198 switch (prop->id) { 199 case IOMFB_PROPERTY_NITS: 200 { 201 if (dcp_has_panel(dcp)) { 202 dcp->brightness.nits = prop->value / dcp->brightness.scale; 203 /* notify backlight device of the initial brightness */ 204 if (!dcp->brightness.bl_dev && dcp->brightness.maximum > 0) 205 schedule_work(&dcp->bl_register_wq); 206 trace_iomfb_brightness(dcp, prop->value); 207 } 208 break; 209 } 210 default: 211 dev_dbg(dcp->dev, "pr_publish: id: %d = %u\n", prop->id, prop->value); 212 } 213 } 214 215 static struct dcp_get_uint_prop_resp 216 dcpep_cb_get_uint_prop(struct apple_dcp *dcp, struct dcp_get_uint_prop_req *req) 217 { 218 struct dcp_get_uint_prop_resp resp = (struct dcp_get_uint_prop_resp){ 219 .value = 0 220 }; 221 222 if (dcp->panel.has_mini_led && 223 memcmp(req->obj, "SUMP", sizeof(req->obj)) == 0) { /* "PMUS */ 224 if (strncmp(req->key, "Temperature", sizeof(req->key)) == 0) { 225 /* 226 * TODO: value from j314c, find out if it is temperature in 227 * centigrade C and which temperature sensor reports it 228 */ 229 resp.value = 3029; 230 resp.ret = true; 231 } 232 } 233 234 return resp; 235 } 236 237 static u8 iomfbep_cb_sr_set_property_int(struct apple_dcp *dcp, 238 struct iomfb_sr_set_property_int_req *req) 239 { 240 if (memcmp(req->obj, "FMOI", sizeof(req->obj)) == 0) { /* "IOMF */ 241 if (strncmp(req->key, "Brightness_Scale", sizeof(req->key)) == 0) { 242 if (!req->value_null) 243 dcp->brightness.scale = req->value; 244 } 245 } 246 247 return 1; 248 } 249 250 static void iomfbep_cb_set_fx_prop(struct apple_dcp *dcp, struct iomfb_set_fx_prop_req *req) 251 { 252 // TODO: trace this, see if there properties which needs to used later 253 } 254 255 /* 256 * Callback to map a buffer allocated with allocate_buf for PIODMA usage. 257 * PIODMA is separate from the main DCP and uses own IOVA space on a dedicated 258 * stream of the display DART, rather than the expected DCP DART. 259 */ 260 static struct dcp_map_buf_resp dcpep_cb_map_piodma(struct apple_dcp *dcp, 261 struct dcp_map_buf_req *req) 262 { 263 struct dcp_mem_descriptor *memdesc; 264 struct sg_table *map; 265 ssize_t ret; 266 267 if (req->buffer >= ARRAY_SIZE(dcp->memdesc)) 268 goto reject; 269 270 memdesc = &dcp->memdesc[req->buffer]; 271 map = &memdesc->map; 272 273 if (!map->sgl) 274 goto reject; 275 276 /* use the piodma iommu domain to map against the right IOMMU */ 277 ret = iommu_map_sgtable(dcp->iommu_dom, memdesc->dva, map, 278 IOMMU_READ | IOMMU_WRITE); 279 280 /* HACK: expect size to be 16K aligned since the iommu API only maps 281 * full pages 282 */ 283 if (ret < 0 || ret != ALIGN(memdesc->size, SZ_16K)) { 284 dev_err(dcp->dev, "iommu_map_sgtable() returned %zd instead of expected buffer size of %zu\n", ret, memdesc->size); 285 goto reject; 286 } 287 288 return (struct dcp_map_buf_resp){ .dva = memdesc->dva }; 289 290 reject: 291 dev_err(dcp->dev, "denying map of invalid buffer %llx for pidoma\n", 292 req->buffer); 293 return (struct dcp_map_buf_resp){ .ret = EINVAL }; 294 } 295 296 static void dcpep_cb_unmap_piodma(struct apple_dcp *dcp, 297 struct dcp_unmap_buf_resp *resp) 298 { 299 struct dcp_mem_descriptor *memdesc; 300 301 if (resp->buffer >= ARRAY_SIZE(dcp->memdesc)) { 302 dev_warn(dcp->dev, "unmap request for out of range buffer %llu\n", 303 resp->buffer); 304 return; 305 } 306 307 memdesc = &dcp->memdesc[resp->buffer]; 308 309 if (!memdesc->buf) { 310 dev_warn(dcp->dev, 311 "unmap for non-mapped buffer %llu iova:0x%08llx\n", 312 resp->buffer, resp->dva); 313 return; 314 } 315 316 if (memdesc->dva != resp->dva) { 317 dev_warn(dcp->dev, "unmap buffer %llu address mismatch " 318 "memdesc.dva:%llx dva:%llx\n", resp->buffer, 319 memdesc->dva, resp->dva); 320 return; 321 } 322 323 /* use the piodma iommu domain to unmap from the right IOMMU */ 324 iommu_unmap(dcp->iommu_dom, memdesc->dva, memdesc->size); 325 } 326 327 /* 328 * Allocate an IOVA contiguous buffer mapped to the DCP. The buffer need not be 329 * physically contiguous, however we should save the sgtable in case the 330 * buffer needs to be later mapped for PIODMA. 331 */ 332 static struct dcp_allocate_buffer_resp 333 dcpep_cb_allocate_buffer(struct apple_dcp *dcp, 334 struct dcp_allocate_buffer_req *req) 335 { 336 struct dcp_allocate_buffer_resp resp = { 0 }; 337 struct dcp_mem_descriptor *memdesc; 338 size_t size; 339 u32 id; 340 341 resp.dva_size = ALIGN(req->size, 4096); 342 resp.mem_desc_id = 343 find_first_zero_bit(dcp->memdesc_map, DCP_MAX_MAPPINGS); 344 345 if (resp.mem_desc_id >= DCP_MAX_MAPPINGS) { 346 dev_warn(dcp->dev, "DCP overflowed mapping table, ignoring\n"); 347 resp.dva_size = 0; 348 resp.mem_desc_id = 0; 349 return resp; 350 } 351 id = resp.mem_desc_id; 352 set_bit(id, dcp->memdesc_map); 353 354 memdesc = &dcp->memdesc[id]; 355 356 memdesc->size = resp.dva_size; 357 /* HACK: align size to 16K since the iommu API only maps full pages */ 358 size = ALIGN(resp.dva_size, SZ_16K); 359 memdesc->buf = dma_alloc_coherent(dcp->dev, size, 360 &memdesc->dva, GFP_KERNEL); 361 362 dma_get_sgtable(dcp->dev, &memdesc->map, memdesc->buf, memdesc->dva, 363 size); 364 resp.dva = memdesc->dva; 365 366 return resp; 367 } 368 369 static u8 dcpep_cb_release_mem_desc(struct apple_dcp *dcp, u32 *mem_desc_id) 370 { 371 struct dcp_mem_descriptor *memdesc; 372 u32 id = *mem_desc_id; 373 374 if (id >= DCP_MAX_MAPPINGS) { 375 dev_warn(dcp->dev, 376 "unmap request for out of range mem_desc_id %u", id); 377 return 0; 378 } 379 380 if (!test_and_clear_bit(id, dcp->memdesc_map)) { 381 dev_warn(dcp->dev, "unmap request for unused mem_desc_id %u\n", 382 id); 383 return 0; 384 } 385 386 memdesc = &dcp->memdesc[id]; 387 if (memdesc->buf) { 388 dma_free_coherent(dcp->dev, memdesc->size, memdesc->buf, 389 memdesc->dva); 390 391 memdesc->buf = NULL; 392 memset(&memdesc->map, 0, sizeof(memdesc->map)); 393 } else { 394 memdesc->reg = 0; 395 } 396 397 memdesc->size = 0; 398 399 return 1; 400 } 401 402 /* Validate that the specified region is a display register */ 403 static bool is_disp_register(struct apple_dcp *dcp, u64 start, u64 end) 404 { 405 int i; 406 407 for (i = 0; i < dcp->nr_disp_registers; ++i) { 408 struct resource *r = dcp->disp_registers[i]; 409 410 if ((start >= r->start) && (end <= r->end)) 411 return true; 412 } 413 414 return false; 415 } 416 417 /* 418 * Map contiguous physical memory into the DCP's address space. The firmware 419 * uses this to map the display registers we advertise in 420 * sr_map_device_memory_with_index, so we bounds check against that to guard 421 * safe against malicious coprocessors. 422 */ 423 static struct dcp_map_physical_resp 424 dcpep_cb_map_physical(struct apple_dcp *dcp, struct dcp_map_physical_req *req) 425 { 426 int size = ALIGN(req->size, 4096); 427 dma_addr_t dva; 428 u32 id; 429 430 if (!is_disp_register(dcp, req->paddr, req->paddr + size - 1)) { 431 dev_err(dcp->dev, "refusing to map phys address %llx size %llx\n", 432 req->paddr, req->size); 433 return (struct dcp_map_physical_resp){}; 434 } 435 436 id = find_first_zero_bit(dcp->memdesc_map, DCP_MAX_MAPPINGS); 437 set_bit(id, dcp->memdesc_map); 438 dcp->memdesc[id].size = size; 439 dcp->memdesc[id].reg = req->paddr; 440 441 dva = dma_map_resource(dcp->dev, req->paddr, size, DMA_BIDIRECTIONAL, 0); 442 WARN_ON(dva == DMA_MAPPING_ERROR); 443 444 return (struct dcp_map_physical_resp){ 445 .dva_size = size, 446 .mem_desc_id = id, 447 .dva = dva, 448 }; 449 } 450 451 static u64 dcpep_cb_get_frequency(struct apple_dcp *dcp) 452 { 453 return clk_get_rate(dcp->clk); 454 } 455 456 static struct DCP_FW_NAME(dcp_map_reg_resp) dcpep_cb_map_reg(struct apple_dcp *dcp, 457 struct DCP_FW_NAME(dcp_map_reg_req) *req) 458 { 459 if (req->index >= dcp->nr_disp_registers) { 460 dev_warn(dcp->dev, "attempted to read invalid reg index %u\n", 461 req->index); 462 463 return (struct DCP_FW_NAME(dcp_map_reg_resp)){ .ret = 1 }; 464 } else { 465 struct resource *rsrc = dcp->disp_registers[req->index]; 466 #if DCP_FW_VER >= DCP_FW_VERSION(13, 2, 0) 467 dma_addr_t dva = dma_map_resource(dcp->dev, rsrc->start, resource_size(rsrc), 468 DMA_BIDIRECTIONAL, 0); 469 WARN_ON(dva == DMA_MAPPING_ERROR); 470 #endif 471 472 return (struct DCP_FW_NAME(dcp_map_reg_resp)){ 473 .addr = rsrc->start, 474 .length = resource_size(rsrc), 475 #if DCP_FW_VER >= DCP_FW_VERSION(13, 2, 0) 476 .dva = dva, 477 #endif 478 }; 479 } 480 } 481 482 static struct dcp_read_edt_data_resp 483 dcpep_cb_read_edt_data(struct apple_dcp *dcp, struct dcp_read_edt_data_req *req) 484 { 485 return (struct dcp_read_edt_data_resp){ 486 .value[0] = req->value[0], 487 .ret = 0, 488 }; 489 } 490 491 static void iomfbep_cb_enable_backlight_message_ap_gated(struct apple_dcp *dcp, 492 u8 *enabled) 493 { 494 /* 495 * update backlight brightness on next swap, on non mini-LED displays 496 * DCP seems to set an invalid iDAC value after coming out of DPMS. 497 * syslog: "[BrightnessLCD.cpp:743][AFK]nitsToDBV: iDAC out of range" 498 */ 499 dcp->brightness.update = true; 500 schedule_work(&dcp->bl_update_wq); 501 } 502 503 /* Chunked data transfer for property dictionaries */ 504 static u8 dcpep_cb_prop_start(struct apple_dcp *dcp, u32 *length) 505 { 506 if (dcp->chunks.data != NULL) { 507 dev_warn(dcp->dev, "ignoring spurious transfer start\n"); 508 return false; 509 } 510 511 dcp->chunks.length = *length; 512 dcp->chunks.data = devm_kzalloc(dcp->dev, *length, GFP_KERNEL); 513 514 if (!dcp->chunks.data) { 515 dev_warn(dcp->dev, "failed to allocate chunks\n"); 516 return false; 517 } 518 519 return true; 520 } 521 522 static u8 dcpep_cb_prop_chunk(struct apple_dcp *dcp, 523 struct dcp_set_dcpav_prop_chunk_req *req) 524 { 525 if (!dcp->chunks.data) { 526 dev_warn(dcp->dev, "ignoring spurious chunk\n"); 527 return false; 528 } 529 530 if (req->offset + req->length > dcp->chunks.length) { 531 dev_warn(dcp->dev, "ignoring overflowing chunk\n"); 532 return false; 533 } 534 535 memcpy(dcp->chunks.data + req->offset, req->data, req->length); 536 return true; 537 } 538 539 static bool dcpep_process_chunks(struct apple_dcp *dcp, 540 struct dcp_set_dcpav_prop_end_req *req) 541 { 542 struct dcp_parse_ctx ctx; 543 int ret; 544 545 if (!dcp->chunks.data) { 546 dev_warn(dcp->dev, "ignoring spurious end\n"); 547 return false; 548 } 549 550 /* used just as opaque pointer for tracing */ 551 ctx.dcp = dcp; 552 553 ret = parse(dcp->chunks.data, dcp->chunks.length, &ctx); 554 555 if (ret) { 556 dev_warn(dcp->dev, "bad header on dcpav props\n"); 557 return false; 558 } 559 560 if (!strcmp(req->key, "TimingElements")) { 561 dcp->modes = enumerate_modes(&ctx, &dcp->nr_modes, 562 dcp->width_mm, dcp->height_mm, 563 dcp->notch_height); 564 565 if (IS_ERR(dcp->modes)) { 566 dev_warn(dcp->dev, "failed to parse modes\n"); 567 dcp->modes = NULL; 568 dcp->nr_modes = 0; 569 return false; 570 } 571 if (dcp->nr_modes == 0) 572 dev_warn(dcp->dev, "TimingElements without valid modes!\n"); 573 } else if (!strcmp(req->key, "DisplayAttributes")) { 574 ret = parse_display_attributes(&ctx, &dcp->width_mm, 575 &dcp->height_mm); 576 577 if (ret) { 578 dev_warn(dcp->dev, "failed to parse display attribs\n"); 579 return false; 580 } 581 582 dcp_set_dimensions(dcp); 583 } 584 585 return true; 586 } 587 588 static u8 dcpep_cb_prop_end(struct apple_dcp *dcp, 589 struct dcp_set_dcpav_prop_end_req *req) 590 { 591 u8 resp = dcpep_process_chunks(dcp, req); 592 593 /* Reset for the next transfer */ 594 devm_kfree(dcp->dev, dcp->chunks.data); 595 dcp->chunks.data = NULL; 596 597 return resp; 598 } 599 600 /* Boot sequence */ 601 static void boot_done(struct apple_dcp *dcp, void *out, void *cookie) 602 { 603 struct dcp_channel *ch = &dcp->ch_cb; 604 u8 *succ = ch->output[ch->depth - 1]; 605 dev_dbg(dcp->dev, "boot done\n"); 606 607 *succ = true; 608 dcp_ack(dcp, DCP_CONTEXT_CB); 609 } 610 611 static void boot_5(struct apple_dcp *dcp, void *out, void *cookie) 612 { 613 dcp_set_display_refresh_properties(dcp, false, boot_done, NULL); 614 } 615 616 static void boot_4(struct apple_dcp *dcp, void *out, void *cookie) 617 { 618 #if DCP_FW_VER >= DCP_FW_VERSION(13, 2, 0) 619 u32 v_true = 1; 620 dcp_late_init_signal(dcp, false, &v_true, boot_5, NULL); 621 #else 622 dcp_late_init_signal(dcp, false, boot_5, NULL); 623 #endif 624 } 625 626 static void boot_3(struct apple_dcp *dcp, void *out, void *cookie) 627 { 628 u32 v_true = true; 629 630 dcp_flush_supports_power(dcp, false, &v_true, boot_4, NULL); 631 } 632 633 static void boot_2(struct apple_dcp *dcp, void *out, void *cookie) 634 { 635 dcp_setup_video_limits(dcp, false, boot_3, NULL); 636 } 637 638 static void boot_1_5(struct apple_dcp *dcp, void *out, void *cookie) 639 { 640 dcp_create_default_fb(dcp, false, boot_2, NULL); 641 } 642 643 /* Use special function signature to defer the ACK */ 644 static bool dcpep_cb_boot_1(struct apple_dcp *dcp, int tag, void *out, void *in) 645 { 646 trace_iomfb_callback(dcp, tag, __func__); 647 dcp_set_create_dfb(dcp, false, boot_1_5, NULL); 648 return false; 649 } 650 651 static struct dcp_allocate_bandwidth_resp dcpep_cb_allocate_bandwidth(struct apple_dcp *dcp, 652 struct dcp_allocate_bandwidth_req *req) 653 { 654 return (struct dcp_allocate_bandwidth_resp){ 655 .unk1 = req->unk1, 656 .unk2 = req->unk2, 657 .ret = 1, 658 }; 659 } 660 661 static struct dcp_rt_bandwidth dcpep_cb_rt_bandwidth(struct apple_dcp *dcp) 662 { 663 struct dcp_rt_bandwidth rt_bw = (struct dcp_rt_bandwidth){ 664 .reg_scratch = 0, 665 .reg_doorbell = 0, 666 .doorbell_bit = 0, 667 }; 668 669 if (dcp->disp_bw_scratch_index) { 670 u32 offset = dcp->disp_bw_scratch_offset; 671 u32 index = dcp->disp_bw_scratch_index; 672 rt_bw.reg_scratch = dcp->disp_registers[index]->start + offset; 673 } 674 675 if (dcp->disp_bw_doorbell_index) { 676 u32 index = dcp->disp_bw_doorbell_index; 677 rt_bw.reg_doorbell = dcp->disp_registers[index]->start; 678 rt_bw.doorbell_bit = REG_DOORBELL_BIT(dcp->index); 679 /* 680 * This is most certainly not padding. t8103-dcp crashes without 681 * setting this immediately during modeset on 12.3 and 13.5 682 * firmware. 683 */ 684 rt_bw.padding[3] = 0x4; 685 } 686 687 return rt_bw; 688 } 689 690 static struct dcp_set_frame_sync_props_resp 691 dcpep_cb_set_frame_sync_props(struct apple_dcp *dcp, 692 struct dcp_set_frame_sync_props_req *req) 693 { 694 return (struct dcp_set_frame_sync_props_resp){}; 695 } 696 697 /* Callback to get the current time as milliseconds since the UNIX epoch */ 698 static u64 dcpep_cb_get_time(struct apple_dcp *dcp) 699 { 700 return ktime_to_ms(ktime_get_real()); 701 } 702 703 struct dcp_swap_cookie { 704 struct kref refcount; 705 struct completion done; 706 u32 swap_id; 707 }; 708 709 static void release_swap_cookie(struct kref *ref) 710 { 711 struct dcp_swap_cookie *cookie; 712 cookie = container_of(ref, struct dcp_swap_cookie, refcount); 713 714 kfree(cookie); 715 } 716 717 static void dcp_swap_cleared(struct apple_dcp *dcp, void *data, void *cookie) 718 { 719 struct DCP_FW_NAME(dcp_swap_submit_resp) *resp = data; 720 721 if (cookie) { 722 struct dcp_swap_cookie *info = cookie; 723 complete(&info->done); 724 kref_put(&info->refcount, release_swap_cookie); 725 } 726 727 if (resp->ret) { 728 dev_err(dcp->dev, "swap_clear failed! status %u\n", resp->ret); 729 dcp_drm_crtc_vblank(dcp->crtc); 730 return; 731 } 732 733 while (!list_empty(&dcp->swapped_out_fbs)) { 734 struct dcp_fb_reference *entry; 735 entry = list_first_entry(&dcp->swapped_out_fbs, 736 struct dcp_fb_reference, head); 737 if (entry->swap_id == dcp->last_swap_id) 738 break; 739 if (entry->fb) 740 drm_framebuffer_put(entry->fb); 741 list_del(&entry->head); 742 kfree(entry); 743 } 744 } 745 746 static void dcp_swap_clear_started(struct apple_dcp *dcp, void *data, 747 void *cookie) 748 { 749 struct dcp_swap_start_resp *resp = data; 750 DCP_FW_UNION(dcp->swap).swap.swap_id = resp->swap_id; 751 752 if (cookie) { 753 struct dcp_swap_cookie *info = cookie; 754 info->swap_id = resp->swap_id; 755 } 756 757 dcp_swap_submit(dcp, false, &DCP_FW_UNION(dcp->swap), dcp_swap_cleared, cookie); 758 } 759 760 static void dcp_on_final(struct apple_dcp *dcp, void *out, void *cookie) 761 { 762 struct dcp_wait_cookie *wait = cookie; 763 764 if (wait) { 765 complete(&wait->done); 766 kref_put(&wait->refcount, release_wait_cookie); 767 } 768 } 769 770 static void dcp_on_set_power_state(struct apple_dcp *dcp, void *out, void *cookie) 771 { 772 struct dcp_set_power_state_req req = { 773 .unklong = 1, 774 }; 775 776 dcp_set_power_state(dcp, false, &req, dcp_on_final, cookie); 777 } 778 779 static void dcp_on_set_parameter(struct apple_dcp *dcp, void *out, void *cookie) 780 { 781 struct dcp_set_parameter_dcp param = { 782 .param = 14, 783 .value = { 0 }, 784 #if DCP_FW_VER >= DCP_FW_VERSION(13, 2, 0) 785 .count = 3, 786 #else 787 .count = 1, 788 #endif 789 }; 790 791 dcp_set_parameter_dcp(dcp, false, ¶m, dcp_on_set_power_state, cookie); 792 } 793 794 void DCP_FW_NAME(iomfb_poweron)(struct apple_dcp *dcp) 795 { 796 struct dcp_wait_cookie *cookie; 797 int ret; 798 u32 handle; 799 dev_err(dcp->dev, "dcp_poweron() starting\n"); 800 801 cookie = kzalloc(sizeof(*cookie), GFP_KERNEL); 802 if (!cookie) 803 return; 804 805 init_completion(&cookie->done); 806 kref_init(&cookie->refcount); 807 /* increase refcount to ensure the receiver has a reference */ 808 kref_get(&cookie->refcount); 809 810 if (dcp->main_display) { 811 handle = 0; 812 dcp_set_display_device(dcp, false, &handle, dcp_on_set_power_state, 813 cookie); 814 } else { 815 handle = 2; 816 dcp_set_display_device(dcp, false, &handle, 817 dcp_on_set_parameter, cookie); 818 } 819 ret = wait_for_completion_timeout(&cookie->done, msecs_to_jiffies(500)); 820 821 if (ret == 0) 822 dev_warn(dcp->dev, "wait for power timed out\n"); 823 824 kref_put(&cookie->refcount, release_wait_cookie);; 825 826 /* Force a brightness update after poweron, to restore the brightness */ 827 dcp->brightness.update = true; 828 } 829 830 static void complete_set_powerstate(struct apple_dcp *dcp, void *out, 831 void *cookie) 832 { 833 struct dcp_wait_cookie *wait = cookie; 834 835 if (wait) { 836 complete(&wait->done); 837 kref_put(&wait->refcount, release_wait_cookie); 838 } 839 } 840 841 static void last_client_closed_poff(struct apple_dcp *dcp, void *out, void *cookie) 842 { 843 struct dcp_set_power_state_req power_req = { 844 .unklong = 0, 845 }; 846 dcp_set_power_state(dcp, false, &power_req, complete_set_powerstate, 847 cookie); 848 } 849 850 static void aborted_swaps_dcp_poff(struct apple_dcp *dcp, void *out, void *cookie) 851 { 852 struct iomfb_last_client_close_req last_client_req = {}; 853 iomfb_last_client_close(dcp, false, &last_client_req, 854 last_client_closed_poff, cookie); 855 } 856 857 void DCP_FW_NAME(iomfb_poweroff)(struct apple_dcp *dcp) 858 { 859 int ret, swap_id; 860 struct iomfb_abort_swaps_dcp_req abort_req = { 861 .client = { 862 .flag2 = 1, 863 }, 864 }; 865 struct dcp_swap_cookie *cookie; 866 struct dcp_wait_cookie *poff_cookie; 867 struct dcp_swap_start_req swap_req = { 0 }; 868 struct DCP_FW_NAME(dcp_swap_submit_req) *swap = &DCP_FW_UNION(dcp->swap); 869 870 cookie = kzalloc(sizeof(*cookie), GFP_KERNEL); 871 if (!cookie) 872 return; 873 init_completion(&cookie->done); 874 kref_init(&cookie->refcount); 875 /* increase refcount to ensure the receiver has a reference */ 876 kref_get(&cookie->refcount); 877 878 // clear surfaces 879 memset(swap, 0, sizeof(*swap)); 880 881 swap->swap.swap_enabled = 882 swap->swap.swap_completed = IOMFB_SET_BACKGROUND | 0x7; 883 swap->swap.bg_color = 0xFF000000; 884 885 /* 886 * Turn off the backlight. This matters because the DCP's idea of 887 * backlight brightness gets desynced after a power change, and it 888 * needs to be told it's going to turn off so it will consider the 889 * subsequent update on poweron an actual change and restore the 890 * brightness. 891 */ 892 if (dcp_has_panel(dcp)) { 893 swap->swap.bl_unk = 1; 894 swap->swap.bl_value = 0; 895 swap->swap.bl_power = 0; 896 } 897 898 for (int l = 0; l < SWAP_SURFACES; l++) 899 swap->surf_null[l] = true; 900 #if DCP_FW_VER >= DCP_FW_VERSION(13, 2, 0) 901 for (int l = 0; l < 5; l++) 902 swap->surf2_null[l] = true; 903 swap->unkU32Ptr_null = true; 904 swap->unkU32out_null = true; 905 #endif 906 907 dcp_swap_start(dcp, false, &swap_req, dcp_swap_clear_started, cookie); 908 909 ret = wait_for_completion_timeout(&cookie->done, msecs_to_jiffies(50)); 910 swap_id = cookie->swap_id; 911 kref_put(&cookie->refcount, release_swap_cookie); 912 if (ret <= 0) { 913 dcp->crashed = true; 914 return; 915 } 916 917 dev_dbg(dcp->dev, "%s: clear swap submitted: %u\n", __func__, swap_id); 918 919 poff_cookie = kzalloc(sizeof(*poff_cookie), GFP_KERNEL); 920 if (!poff_cookie) 921 return; 922 init_completion(&poff_cookie->done); 923 kref_init(&poff_cookie->refcount); 924 /* increase refcount to ensure the receiver has a reference */ 925 kref_get(&poff_cookie->refcount); 926 927 iomfb_abort_swaps_dcp(dcp, false, &abort_req, 928 aborted_swaps_dcp_poff, poff_cookie); 929 ret = wait_for_completion_timeout(&poff_cookie->done, 930 msecs_to_jiffies(1000)); 931 932 if (ret == 0) 933 dev_warn(dcp->dev, "setPowerState(0) timeout %u ms\n", 1000); 934 else if (ret > 0) 935 dev_dbg(dcp->dev, 936 "setPowerState(0) finished with %d ms to spare", 937 jiffies_to_msecs(ret)); 938 939 kref_put(&poff_cookie->refcount, release_wait_cookie); 940 941 dev_err(dcp->dev, "dcp_poweroff() done\n"); 942 } 943 944 static void last_client_closed_sleep(struct apple_dcp *dcp, void *out, void *cookie) 945 { 946 struct dcp_set_power_state_req power_req = { 947 .unklong = 0, 948 }; 949 dcp_set_power_state(dcp, false, &power_req, complete_set_powerstate, cookie); 950 } 951 952 static void aborted_swaps_dcp_sleep(struct apple_dcp *dcp, void *out, void *cookie) 953 { 954 struct iomfb_last_client_close_req req = { 0 }; 955 iomfb_last_client_close(dcp, false, &req, last_client_closed_sleep, cookie); 956 } 957 958 void DCP_FW_NAME(iomfb_sleep)(struct apple_dcp *dcp) 959 { 960 int ret; 961 struct iomfb_abort_swaps_dcp_req req = { 962 .client = { 963 .flag2 = 1, 964 }, 965 }; 966 967 struct dcp_wait_cookie *cookie; 968 969 cookie = kzalloc(sizeof(*cookie), GFP_KERNEL); 970 if (!cookie) 971 return; 972 init_completion(&cookie->done); 973 kref_init(&cookie->refcount); 974 /* increase refcount to ensure the receiver has a reference */ 975 kref_get(&cookie->refcount); 976 977 iomfb_abort_swaps_dcp(dcp, false, &req, aborted_swaps_dcp_sleep, 978 cookie); 979 ret = wait_for_completion_timeout(&cookie->done, 980 msecs_to_jiffies(1000)); 981 982 if (ret == 0) 983 dev_warn(dcp->dev, "setDCPPower(0) timeout %u ms\n", 1000); 984 985 kref_put(&cookie->refcount, release_wait_cookie); 986 dev_err(dcp->dev, "dcp_sleep() done\n"); 987 } 988 989 static void dcpep_cb_hotplug(struct apple_dcp *dcp, u64 *connected) 990 { 991 struct apple_connector *connector = dcp->connector; 992 993 /* DCP issues hotplug_gated callbacks after SetPowerState() calls on 994 * devices with display (macbooks, imacs). This must not result in 995 * connector state changes on DRM side. Some applications won't enable 996 * a CRTC with a connector in disconnected state. Weston after DPMS off 997 * is one example. dcp_is_main_display() returns true on devices with 998 * integrated display. Ignore the hotplug_gated() callbacks there. 999 */ 1000 if (dcp->main_display) 1001 return; 1002 1003 if (dcp->during_modeset) { 1004 dev_info(dcp->dev, 1005 "cb_hotplug() ignored during modeset connected:%llu\n", 1006 *connected); 1007 return; 1008 } 1009 1010 dev_info(dcp->dev, "cb_hotplug() connected:%llu, valid_mode:%d\n", 1011 *connected, dcp->valid_mode); 1012 1013 /* Hotplug invalidates mode. DRM doesn't always handle this. */ 1014 if (!(*connected)) { 1015 dcp->valid_mode = false; 1016 /* after unplug swap will not complete until the next 1017 * set_digital_out_mode */ 1018 schedule_work(&dcp->vblank_wq); 1019 } 1020 1021 if (connector && connector->connected != !!(*connected)) { 1022 connector->connected = !!(*connected); 1023 dcp->valid_mode = false; 1024 schedule_work(&connector->hotplug_wq); 1025 } 1026 } 1027 1028 static void 1029 dcpep_cb_swap_complete_intent_gated(struct apple_dcp *dcp, 1030 struct dcp_swap_complete_intent_gated *info) 1031 { 1032 trace_iomfb_swap_complete_intent_gated(dcp, info->swap_id, 1033 info->width, info->height); 1034 } 1035 1036 static void 1037 dcpep_cb_abort_swap_ap_gated(struct apple_dcp *dcp, u32 *swap_id) 1038 { 1039 trace_iomfb_abort_swap_ap_gated(dcp, *swap_id); 1040 } 1041 1042 static struct dcpep_get_tiling_state_resp 1043 dcpep_cb_get_tiling_state(struct apple_dcp *dcp, 1044 struct dcpep_get_tiling_state_req *req) 1045 { 1046 return (struct dcpep_get_tiling_state_resp){ 1047 .value = 0, 1048 .ret = 1, 1049 }; 1050 } 1051 1052 static u8 dcpep_cb_create_backlight_service(struct apple_dcp *dcp) 1053 { 1054 return dcp_has_panel(dcp); 1055 } 1056 1057 TRAMPOLINE_VOID(trampoline_nop, dcpep_cb_nop); 1058 TRAMPOLINE_OUT(trampoline_true, dcpep_cb_true, u8); 1059 TRAMPOLINE_OUT(trampoline_false, dcpep_cb_false, u8); 1060 TRAMPOLINE_OUT(trampoline_zero, dcpep_cb_zero, u32); 1061 TRAMPOLINE_IN(trampoline_swap_complete, dcpep_cb_swap_complete, 1062 struct DCP_FW_NAME(dc_swap_complete_resp)); 1063 TRAMPOLINE_INOUT(trampoline_get_uint_prop, dcpep_cb_get_uint_prop, 1064 struct dcp_get_uint_prop_req, struct dcp_get_uint_prop_resp); 1065 TRAMPOLINE_IN(trampoline_set_fx_prop, iomfbep_cb_set_fx_prop, 1066 struct iomfb_set_fx_prop_req) 1067 TRAMPOLINE_INOUT(trampoline_map_piodma, dcpep_cb_map_piodma, 1068 struct dcp_map_buf_req, struct dcp_map_buf_resp); 1069 TRAMPOLINE_IN(trampoline_unmap_piodma, dcpep_cb_unmap_piodma, 1070 struct dcp_unmap_buf_resp); 1071 TRAMPOLINE_INOUT(trampoline_sr_set_property_int, iomfbep_cb_sr_set_property_int, 1072 struct iomfb_sr_set_property_int_req, u8); 1073 TRAMPOLINE_INOUT(trampoline_allocate_buffer, dcpep_cb_allocate_buffer, 1074 struct dcp_allocate_buffer_req, 1075 struct dcp_allocate_buffer_resp); 1076 TRAMPOLINE_INOUT(trampoline_map_physical, dcpep_cb_map_physical, 1077 struct dcp_map_physical_req, struct dcp_map_physical_resp); 1078 TRAMPOLINE_INOUT(trampoline_release_mem_desc, dcpep_cb_release_mem_desc, u32, 1079 u8); 1080 TRAMPOLINE_INOUT(trampoline_map_reg, dcpep_cb_map_reg, 1081 struct DCP_FW_NAME(dcp_map_reg_req), 1082 struct DCP_FW_NAME(dcp_map_reg_resp)); 1083 TRAMPOLINE_INOUT(trampoline_read_edt_data, dcpep_cb_read_edt_data, 1084 struct dcp_read_edt_data_req, struct dcp_read_edt_data_resp); 1085 TRAMPOLINE_INOUT(trampoline_prop_start, dcpep_cb_prop_start, u32, u8); 1086 TRAMPOLINE_INOUT(trampoline_prop_chunk, dcpep_cb_prop_chunk, 1087 struct dcp_set_dcpav_prop_chunk_req, u8); 1088 TRAMPOLINE_INOUT(trampoline_prop_end, dcpep_cb_prop_end, 1089 struct dcp_set_dcpav_prop_end_req, u8); 1090 TRAMPOLINE_INOUT(trampoline_allocate_bandwidth, dcpep_cb_allocate_bandwidth, 1091 struct dcp_allocate_bandwidth_req, struct dcp_allocate_bandwidth_resp); 1092 TRAMPOLINE_OUT(trampoline_rt_bandwidth, dcpep_cb_rt_bandwidth, 1093 struct dcp_rt_bandwidth); 1094 TRAMPOLINE_INOUT(trampoline_set_frame_sync_props, dcpep_cb_set_frame_sync_props, 1095 struct dcp_set_frame_sync_props_req, 1096 struct dcp_set_frame_sync_props_resp); 1097 TRAMPOLINE_OUT(trampoline_get_frequency, dcpep_cb_get_frequency, u64); 1098 TRAMPOLINE_OUT(trampoline_get_time, dcpep_cb_get_time, u64); 1099 TRAMPOLINE_IN(trampoline_hotplug, dcpep_cb_hotplug, u64); 1100 TRAMPOLINE_IN(trampoline_swap_complete_intent_gated, 1101 dcpep_cb_swap_complete_intent_gated, 1102 struct dcp_swap_complete_intent_gated); 1103 TRAMPOLINE_IN(trampoline_abort_swap_ap_gated, dcpep_cb_abort_swap_ap_gated, u32); 1104 TRAMPOLINE_IN(trampoline_enable_backlight_message_ap_gated, 1105 iomfbep_cb_enable_backlight_message_ap_gated, u8); 1106 TRAMPOLINE_IN(trampoline_pr_publish, iomfb_cb_pr_publish, 1107 struct iomfb_property); 1108 TRAMPOLINE_INOUT(trampoline_get_tiling_state, dcpep_cb_get_tiling_state, 1109 struct dcpep_get_tiling_state_req, struct dcpep_get_tiling_state_resp); 1110 TRAMPOLINE_OUT(trampoline_create_backlight_service, dcpep_cb_create_backlight_service, u8); 1111 1112 /* 1113 * Callback for swap requests. If a swap failed, we'll never get a swap 1114 * complete event so we need to fake a vblank event early to avoid a hang. 1115 */ 1116 1117 static void dcp_swapped(struct apple_dcp *dcp, void *data, void *cookie) 1118 { 1119 struct DCP_FW_NAME(dcp_swap_submit_resp) *resp = data; 1120 1121 if (resp->ret) { 1122 dev_err(dcp->dev, "swap failed! status %u\n", resp->ret); 1123 dcp_drm_crtc_vblank(dcp->crtc); 1124 return; 1125 } 1126 1127 while (!list_empty(&dcp->swapped_out_fbs)) { 1128 struct dcp_fb_reference *entry; 1129 entry = list_first_entry(&dcp->swapped_out_fbs, 1130 struct dcp_fb_reference, head); 1131 if (entry->swap_id == dcp->last_swap_id) 1132 break; 1133 if (entry->fb) 1134 drm_framebuffer_put(entry->fb); 1135 list_del(&entry->head); 1136 kfree(entry); 1137 } 1138 } 1139 1140 static void dcp_swap_started(struct apple_dcp *dcp, void *data, void *cookie) 1141 { 1142 struct dcp_swap_start_resp *resp = data; 1143 1144 DCP_FW_UNION(dcp->swap).swap.swap_id = resp->swap_id; 1145 1146 trace_iomfb_swap_submit(dcp, resp->swap_id); 1147 dcp_swap_submit(dcp, false, &DCP_FW_UNION(dcp->swap), dcp_swapped, NULL); 1148 } 1149 1150 /* Helpers to modeset and swap, used to flush */ 1151 static void do_swap(struct apple_dcp *dcp, void *data, void *cookie) 1152 { 1153 struct dcp_swap_start_req start_req = { 0 }; 1154 1155 if (dcp->connector && dcp->connector->connected) 1156 dcp_swap_start(dcp, false, &start_req, dcp_swap_started, NULL); 1157 else 1158 dcp_drm_crtc_vblank(dcp->crtc); 1159 } 1160 1161 static void complete_set_digital_out_mode(struct apple_dcp *dcp, void *data, 1162 void *cookie) 1163 { 1164 struct dcp_wait_cookie *wait = cookie; 1165 1166 if (wait) { 1167 complete(&wait->done); 1168 kref_put(&wait->refcount, release_wait_cookie); 1169 } 1170 } 1171 1172 int DCP_FW_NAME(iomfb_modeset)(struct apple_dcp *dcp, 1173 struct drm_crtc_state *crtc_state) 1174 { 1175 struct dcp_display_mode *mode; 1176 struct dcp_wait_cookie *cookie; 1177 struct dcp_color_mode *cmode = NULL; 1178 int ret; 1179 1180 mode = lookup_mode(dcp, &crtc_state->mode); 1181 if (!mode) { 1182 dev_err(dcp->dev, "no match for " DRM_MODE_FMT "\n", 1183 DRM_MODE_ARG(&crtc_state->mode)); 1184 return -EIO; 1185 } 1186 1187 dev_info(dcp->dev, 1188 "set_digital_out_mode(color:%d timing:%d) " DRM_MODE_FMT "\n", 1189 mode->color_mode_id, mode->timing_mode_id, 1190 DRM_MODE_ARG(&crtc_state->mode)); 1191 if (mode->color_mode_id == mode->sdr_rgb.id) 1192 cmode = &mode->sdr_rgb; 1193 else if (mode->color_mode_id == mode->sdr_444.id) 1194 cmode = &mode->sdr_444; 1195 else if (mode->color_mode_id == mode->sdr.id) 1196 cmode = &mode->sdr; 1197 else if (mode->color_mode_id == mode->best.id) 1198 cmode = &mode->best; 1199 if (cmode) 1200 dev_info(dcp->dev, 1201 "set_digital_out_mode() color mode depth:%hhu format:%u " 1202 "colorimetry:%u eotf:%u range:%u\n", cmode->depth, 1203 cmode->format, cmode->colorimetry, cmode->eotf, 1204 cmode->range); 1205 1206 dcp->mode = (struct dcp_set_digital_out_mode_req){ 1207 .color_mode_id = mode->color_mode_id, 1208 .timing_mode_id = mode->timing_mode_id 1209 }; 1210 1211 cookie = kzalloc(sizeof(*cookie), GFP_KERNEL); 1212 if (!cookie) { 1213 return -ENOMEM; 1214 } 1215 1216 init_completion(&cookie->done); 1217 kref_init(&cookie->refcount); 1218 /* increase refcount to ensure the receiver has a reference */ 1219 kref_get(&cookie->refcount); 1220 1221 dcp->during_modeset = true; 1222 1223 dcp_set_digital_out_mode(dcp, false, &dcp->mode, 1224 complete_set_digital_out_mode, cookie); 1225 1226 /* 1227 * The DCP firmware has an internal timeout of ~8 seconds for 1228 * modesets. Add an extra 500ms to safe side that the modeset 1229 * call has returned. 1230 */ 1231 ret = wait_for_completion_timeout(&cookie->done, 1232 msecs_to_jiffies(8500)); 1233 1234 kref_put(&cookie->refcount, release_wait_cookie); 1235 dcp->during_modeset = false; 1236 dev_info(dcp->dev, "set_digital_out_mode finished:%d\n", ret); 1237 1238 if (ret == 0) { 1239 dev_info(dcp->dev, "set_digital_out_mode timed out\n"); 1240 return -EIO; 1241 } else if (ret < 0) { 1242 dev_info(dcp->dev, 1243 "waiting on set_digital_out_mode failed:%d\n", ret); 1244 return -EIO; 1245 1246 } else if (ret > 0) { 1247 dev_dbg(dcp->dev, 1248 "set_digital_out_mode finished with %d to spare\n", 1249 jiffies_to_msecs(ret)); 1250 } 1251 dcp->valid_mode = true; 1252 1253 return 0; 1254 } 1255 1256 void DCP_FW_NAME(iomfb_flush)(struct apple_dcp *dcp, struct drm_crtc *crtc, struct drm_atomic_state *state) 1257 { 1258 struct drm_plane *plane; 1259 struct drm_plane_state *new_state, *old_state; 1260 struct drm_crtc_state *crtc_state; 1261 struct DCP_FW_NAME(dcp_swap_submit_req) *req = &DCP_FW_UNION(dcp->swap); 1262 int plane_idx, l; 1263 int has_surface = 0; 1264 1265 crtc_state = drm_atomic_get_new_crtc_state(state, crtc); 1266 1267 /* Reset to defaults */ 1268 memset(req, 0, sizeof(*req)); 1269 for (l = 0; l < SWAP_SURFACES; l++) 1270 req->surf_null[l] = true; 1271 #if DCP_FW_VER >= DCP_FW_VERSION(13, 2, 0) 1272 for (l = 0; l < 5; l++) 1273 req->surf2_null[l] = true; 1274 req->unkU32Ptr_null = true; 1275 req->unkU32out_null = true; 1276 #endif 1277 1278 /* 1279 * Clear all surfaces on startup. The boot framebuffer in surface 0 1280 * sticks around. 1281 */ 1282 if (!dcp->surfaces_cleared) { 1283 req->swap.swap_enabled = IOMFB_SET_BACKGROUND | 0x7; 1284 req->swap.bg_color = 0xFF000000; 1285 dcp->surfaces_cleared = true; 1286 } 1287 1288 // Surface 0 has limitations at least on t600x. 1289 l = 1; 1290 for_each_oldnew_plane_in_state(state, plane, old_state, new_state, plane_idx) { 1291 struct drm_framebuffer *fb = new_state->fb; 1292 struct drm_gem_dma_object *obj; 1293 struct drm_rect src_rect; 1294 bool is_premultiplied = false; 1295 1296 /* skip planes not for this crtc */ 1297 if (old_state->crtc != crtc && new_state->crtc != crtc) 1298 continue; 1299 1300 WARN_ON(l >= SWAP_SURFACES); 1301 1302 req->swap.swap_enabled |= BIT(l); 1303 1304 if (old_state->fb && fb != old_state->fb) { 1305 /* 1306 * Race condition between a framebuffer unbind getting 1307 * swapped out and GEM unreferencing a framebuffer. If 1308 * we lose the race, the display gets IOVA faults and 1309 * the DCP crashes. We need to extend the lifetime of 1310 * the drm_framebuffer (and hence the GEM object) until 1311 * after we get a swap complete for the swap unbinding 1312 * it. 1313 */ 1314 struct dcp_fb_reference *entry = 1315 kzalloc(sizeof(*entry), GFP_KERNEL); 1316 if (entry) { 1317 entry->fb = old_state->fb; 1318 entry->swap_id = dcp->last_swap_id; 1319 list_add_tail(&entry->head, 1320 &dcp->swapped_out_fbs); 1321 } 1322 drm_framebuffer_get(old_state->fb); 1323 } 1324 1325 if (!new_state->fb) { 1326 l += 1; 1327 continue; 1328 } 1329 req->surf_null[l] = false; 1330 has_surface = 1; 1331 1332 /* 1333 * DCP doesn't support XBGR8 / XRGB8 natively. Blending as 1334 * pre-multiplied alpha with a black background can be used as 1335 * workaround for the bottommost plane. 1336 */ 1337 if (fb->format->format == DRM_FORMAT_XRGB8888 || 1338 fb->format->format == DRM_FORMAT_XBGR8888) 1339 is_premultiplied = true; 1340 1341 drm_rect_fp_to_int(&src_rect, &new_state->src); 1342 1343 req->swap.src_rect[l] = drm_to_dcp_rect(&src_rect); 1344 req->swap.dst_rect[l] = drm_to_dcp_rect(&new_state->dst); 1345 1346 if (dcp->notch_height > 0) 1347 req->swap.dst_rect[l].y += dcp->notch_height; 1348 1349 /* the obvious helper call drm_fb_dma_get_gem_addr() adjusts 1350 * the address for source x/y offsets. Since IOMFB has a direct 1351 * support source position prefer that. 1352 */ 1353 obj = drm_fb_dma_get_gem_obj(fb, 0); 1354 if (obj) 1355 req->surf_iova[l] = obj->dma_addr + fb->offsets[0]; 1356 1357 req->surf[l] = (struct DCP_FW_NAME(dcp_surface)){ 1358 .is_premultiplied = is_premultiplied, 1359 .format = drm_format_to_dcp(fb->format->format), 1360 .xfer_func = DCP_XFER_FUNC_SDR, 1361 .colorspace = DCP_COLORSPACE_NATIVE, 1362 .stride = fb->pitches[0], 1363 .width = fb->width, 1364 .height = fb->height, 1365 .buf_size = fb->height * fb->pitches[0], 1366 .surface_id = req->swap.surf_ids[l], 1367 1368 /* Only used for compressed or multiplanar surfaces */ 1369 .pix_size = 1, 1370 .pel_w = 1, 1371 .pel_h = 1, 1372 .has_comp = 1, 1373 .has_planes = 1, 1374 }; 1375 1376 l += 1; 1377 } 1378 1379 if (!has_surface && !crtc_state->color_mgmt_changed) { 1380 if (crtc_state->enable && crtc_state->active && 1381 !crtc_state->planes_changed) { 1382 schedule_work(&dcp->vblank_wq); 1383 return; 1384 } 1385 1386 /* Set black background */ 1387 req->swap.swap_enabled |= IOMFB_SET_BACKGROUND; 1388 req->swap.bg_color = 0xFF000000; 1389 req->clear = 1; 1390 } 1391 1392 /* These fields should be set together */ 1393 req->swap.swap_completed = req->swap.swap_enabled; 1394 1395 /* update brightness if changed */ 1396 if (dcp_has_panel(dcp) && dcp->brightness.update) { 1397 req->swap.bl_unk = 1; 1398 req->swap.bl_value = dcp->brightness.dac; 1399 req->swap.bl_power = 0x40; 1400 dcp->brightness.update = false; 1401 } 1402 1403 if (crtc_state->color_mgmt_changed && crtc_state->ctm) { 1404 struct iomfb_set_matrix_req mat; 1405 struct drm_color_ctm *ctm = (struct drm_color_ctm *)crtc_state->ctm->data; 1406 1407 mat.unk_u32 = 9; 1408 mat.r[0] = ctm->matrix[0]; 1409 mat.r[1] = ctm->matrix[1]; 1410 mat.r[2] = ctm->matrix[2]; 1411 mat.g[0] = ctm->matrix[3]; 1412 mat.g[1] = ctm->matrix[4]; 1413 mat.g[2] = ctm->matrix[5]; 1414 mat.b[0] = ctm->matrix[6]; 1415 mat.b[1] = ctm->matrix[7]; 1416 mat.b[2] = ctm->matrix[8]; 1417 1418 iomfb_set_matrix(dcp, false, &mat, do_swap, NULL); 1419 } else 1420 do_swap(dcp, NULL, NULL); 1421 } 1422 1423 static void res_is_main_display(struct apple_dcp *dcp, void *out, void *cookie) 1424 { 1425 struct apple_connector *connector; 1426 int result = *(int *)out; 1427 dev_info(dcp->dev, "DCP is_main_display: %d\n", result); 1428 1429 dcp->main_display = result != 0; 1430 1431 connector = dcp->connector; 1432 if (connector) { 1433 connector->connected = dcp->nr_modes > 0; 1434 schedule_work(&connector->hotplug_wq); 1435 } 1436 1437 dcp->active = true; 1438 complete(&dcp->start_done); 1439 } 1440 1441 static void init_3(struct apple_dcp *dcp, void *out, void *cookie) 1442 { 1443 dcp_is_main_display(dcp, false, res_is_main_display, NULL); 1444 } 1445 1446 static void init_2(struct apple_dcp *dcp, void *out, void *cookie) 1447 { 1448 dcp_first_client_open(dcp, false, init_3, NULL); 1449 } 1450 1451 static void init_1(struct apple_dcp *dcp, void *out, void *cookie) 1452 { 1453 u32 val = 0; 1454 dcp_enable_disable_video_power_savings(dcp, false, &val, init_2, NULL); 1455 } 1456 1457 static void dcp_started(struct apple_dcp *dcp, void *data, void *cookie) 1458 { 1459 struct iomfb_get_color_remap_mode_req color_remap = 1460 (struct iomfb_get_color_remap_mode_req){ 1461 .mode = 6, 1462 }; 1463 1464 dev_info(dcp->dev, "DCP booted\n"); 1465 1466 iomfb_get_color_remap_mode(dcp, false, &color_remap, init_1, cookie); 1467 } 1468 1469 void DCP_FW_NAME(iomfb_shutdown)(struct apple_dcp *dcp) 1470 { 1471 struct dcp_set_power_state_req req = { 1472 /* defaults are ok */ 1473 }; 1474 1475 dcp_set_power_state(dcp, false, &req, NULL, NULL); 1476 } 1477