Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'drm-misc-next-2026-01-08' of https://gitlab.freedesktop.org/drm/misc/kernel into drm-next

drm-misc-next for 6.20:

UAPI Changes:

Cross-subsystem Changes:

Core Changes:
- draw: Add API to check if a format conversion can be done
- panic: Rename draw_panic_static_* to draw_panic_screen_*, Add kunit
tests
- shmem: Improve tests

Driver Changes:
- ast: Big endian fixes
- etnaviv: Add PPU flop reset support
- panfrost: Add GPU_PM_RT support for RZ/G3E SoC
- panthor: multiple fixes around VM termination, huge page support
- pl111: Fix build regression
- v3d: Fix DMA segment size

- bridge:
- Add connector argument to .hpd_notify
- Plenty of patches to convert existing drivers to refcounting
- Convert Rockchip's inno hdmi support to a proper bridge
- lontium-lt9611uxc: Switch to HDMI audio helpers

- panel:
- New panel: BOE NV140WUM-T08

Signed-off-by: Dave Airlie <airlied@redhat.com>

From: Maxime Ripard <mripard@redhat.com>
Link: https://patch.msgid.link/20260108-literate-nyala-of-courtesy-de501a@houat

+1590 -716
+16
Documentation/gpu/todo.rst
··· 506 506 507 507 Level: Intermediate 508 508 509 + Convert users of of_drm_find_bridge() to of_drm_find_and_get_bridge() 510 + --------------------------------------------------------------------- 511 + 512 + Taking a struct drm_bridge pointer requires getting a reference and putting 513 + it after disposing of the pointer. Most functions returning a struct 514 + drm_bridge pointer already call drm_bridge_get() to increment the refcount 515 + and their users have been updated to call drm_bridge_put() when 516 + appropriate. of_drm_find_bridge() does not get a reference and it has been 517 + deprecated in favor of of_drm_find_and_get_bridge() which does, but some 518 + users still need to be converted. 519 + 520 + Contact: Maxime Ripard <mripard@kernel.org>, 521 + Luca Ceresoli <luca.ceresoli@bootlin.com> 522 + 523 + Level: Intermediate 524 + 509 525 Core refactorings 510 526 ================= 511 527
+9
MAINTAINERS
··· 8749 8749 F: drivers/gpu/drm/drm_draw.c 8750 8750 F: drivers/gpu/drm/drm_draw_internal.h 8751 8751 F: drivers/gpu/drm/drm_panic*.c 8752 + F: drivers/gpu/drm/tests/drm_panic_test.c 8752 8753 F: include/drm/drm_panic* 8753 8754 8754 8755 DRM PANIC QR CODE ··· 12457 12456 M: Samuel Holland <samuel@sholland.org> 12458 12457 S: Maintained 12459 12458 F: drivers/power/supply/ip5xxx_power.c 12459 + 12460 + INNOSILICON HDMI BRIDGE DRIVER 12461 + M: Andy Yan <andy.yan@rock-chips.com> 12462 + L: dri-devel@lists.freedesktop.org 12463 + S: Maintained 12464 + T: git https://gitlab.freedesktop.org/drm/misc/kernel.git 12465 + F: drivers/gpu/drm/bridge/inno-hdmi.c 12466 + F: include/drm/bridge/inno_hdmi.h 12460 12467 12461 12468 INOTIFY 12462 12469 M: Jan Kara <jack@suse.cz>
+3
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
··· 23 23 * Authors: AMD 24 24 * 25 25 */ 26 + 27 + #include <drm/drm_colorop.h> 28 + 26 29 #include "amdgpu.h" 27 30 #include "amdgpu_mode.h" 28 31 #include "amdgpu_dm.h"
+8 -3
drivers/gpu/drm/ast/ast_cursor.c
··· 93 93 unsigned int width, unsigned int height) 94 94 { 95 95 u8 __iomem *dst = ast_plane_vaddr(&ast->cursor_plane.base); 96 - u32 csum; 97 - 98 - csum = ast_cursor_calculate_checksum(src, width, height); 96 + u32 csum = ast_cursor_calculate_checksum(src, width, height); 99 97 100 98 /* write pixel data */ 99 + #if defined(__BIG_ENDIAN) 100 + unsigned int i; 101 + 102 + for (i = 0; i < AST_HWC_SIZE; i += 2) 103 + writew(swab16(*(const __u16 *)&src[i]), &dst[i]); 104 + #else 101 105 memcpy_toio(dst, src, AST_HWC_SIZE); 106 + #endif 102 107 103 108 /* write checksum + signature */ 104 109 dst += AST_HWC_SIZE;
+9 -2
drivers/gpu/drm/ast/ast_mode.c
··· 526 526 527 527 static void ast_handle_damage(struct ast_plane *ast_plane, struct iosys_map *src, 528 528 struct drm_framebuffer *fb, 529 - const struct drm_rect *clip) 529 + const struct drm_rect *clip, 530 + struct drm_format_conv_state *fmtcnv_state) 530 531 { 531 532 struct iosys_map dst = IOSYS_MAP_INIT_VADDR_IOMEM(ast_plane_vaddr(ast_plane)); 532 533 533 534 iosys_map_incr(&dst, drm_fb_clip_offset(fb->pitches[0], fb->format, clip)); 535 + 536 + #if defined(__BIG_ENDIAN) 537 + drm_fb_swab(&dst, fb->pitches, src, fb, clip, !src[0].is_iomem, fmtcnv_state); 538 + #else 534 539 drm_fb_memcpy(&dst, fb->pitches, src, fb, clip); 540 + #endif 535 541 } 536 542 537 543 static void ast_primary_plane_helper_atomic_update(struct drm_plane *plane, ··· 567 561 if (drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE) == 0) { 568 562 drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state); 569 563 drm_atomic_for_each_plane_damage(&iter, &damage) { 570 - ast_handle_damage(ast_plane, shadow_plane_state->data, fb, &damage); 564 + ast_handle_damage(ast_plane, shadow_plane_state->data, fb, &damage, 565 + &shadow_plane_state->fmtcnv_state); 571 566 } 572 567 573 568 drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE);
+7
drivers/gpu/drm/bridge/Kconfig
··· 100 100 help 101 101 Support for NXP Semiconductors TDA998X HDMI encoders. 102 102 103 + config DRM_INNO_HDMI 104 + tristate 105 + select DRM_BRIDGE_CONNECTOR 106 + select DRM_DISPLAY_HDMI_HELPER 107 + select DRM_DISPLAY_HELPER 108 + select DRM_KMS_HELPER 109 + 103 110 config DRM_ITE_IT6263 104 111 tristate "ITE IT6263 LVDS/HDMI bridge" 105 112 depends on OF
+1
drivers/gpu/drm/bridge/Makefile
··· 10 10 tda998x-y := tda998x_drv.o 11 11 obj-$(CONFIG_DRM_I2C_NXP_TDA998X) += tda998x.o 12 12 13 + obj-$(CONFIG_DRM_INNO_HDMI) += inno-hdmi.o 13 14 obj-$(CONFIG_DRM_ITE_IT6263) += ite-it6263.o 14 15 obj-$(CONFIG_DRM_ITE_IT6505) += ite-it6505.o 15 16 obj-$(CONFIG_DRM_LONTIUM_LT8912B) += lontium-lt8912b.o
+4 -5
drivers/gpu/drm/bridge/imx/imx8qxp-pixel-combiner.c
··· 60 60 61 61 struct imx8qxp_pc_channel { 62 62 struct drm_bridge bridge; 63 - struct drm_bridge *next_bridge; 64 63 struct imx8qxp_pc *pc; 65 64 unsigned int stream_id; 66 65 }; ··· 119 120 } 120 121 121 122 return drm_bridge_attach(encoder, 122 - ch->next_bridge, bridge, 123 + ch->bridge.next_bridge, bridge, 123 124 DRM_BRIDGE_ATTACH_NO_CONNECTOR); 124 125 } 125 126 ··· 325 326 goto free_child; 326 327 } 327 328 328 - ch->next_bridge = of_drm_find_bridge(remote); 329 - if (!ch->next_bridge) { 329 + ch->bridge.next_bridge = of_drm_find_and_get_bridge(remote); 330 + if (!ch->bridge.next_bridge) { 330 331 of_node_put(remote); 331 332 ret = -EPROBE_DEFER; 332 333 DRM_DEV_DEBUG_DRIVER(dev, ··· 348 349 free_child: 349 350 of_node_put(child); 350 351 351 - if (i == 1 && pc->ch[0]->next_bridge) 352 + if (i == 1 && pc->ch[0]->bridge.next_bridge) 352 353 drm_bridge_remove(&pc->ch[0]->bridge); 353 354 354 355 pm_runtime_disable(dev);
+2 -7
drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c
··· 374 374 return ret; 375 375 376 376 pl->next_bridge = imx8qxp_pixel_link_find_next_bridge(pl); 377 - if (IS_ERR(pl->next_bridge)) { 378 - ret = PTR_ERR(pl->next_bridge); 379 - if (ret != -EPROBE_DEFER) 380 - DRM_DEV_ERROR(dev, "failed to find next bridge: %d\n", 381 - ret); 382 - return ret; 383 - } 377 + if (IS_ERR(pl->next_bridge)) 378 + return PTR_ERR(pl->next_bridge); 384 379 385 380 platform_set_drvdata(pdev, pl); 386 381
+26 -37
drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c
··· 35 35 struct imx8qxp_pxl2dpi { 36 36 struct regmap *regmap; 37 37 struct drm_bridge bridge; 38 - struct drm_bridge *next_bridge; 39 38 struct drm_bridge *companion; 40 39 struct device *dev; 41 40 struct imx_sc_ipc *ipc_handle; ··· 59 60 } 60 61 61 62 return drm_bridge_attach(encoder, 62 - p2d->next_bridge, bridge, 63 + p2d->bridge.next_bridge, bridge, 63 64 DRM_BRIDGE_ATTACH_NO_CONNECTOR); 65 + } 66 + 67 + static void imx8qxp_pxl2dpi_bridge_destroy(struct drm_bridge *bridge) 68 + { 69 + struct imx8qxp_pxl2dpi *p2d = bridge->driver_private; 70 + 71 + drm_bridge_put(p2d->companion); 64 72 } 65 73 66 74 static int ··· 212 206 .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, 213 207 .atomic_reset = drm_atomic_helper_bridge_reset, 214 208 .attach = imx8qxp_pxl2dpi_bridge_attach, 209 + .destroy = imx8qxp_pxl2dpi_bridge_destroy, 215 210 .atomic_check = imx8qxp_pxl2dpi_bridge_atomic_check, 216 211 .mode_set = imx8qxp_pxl2dpi_bridge_mode_set, 217 212 .atomic_disable = imx8qxp_pxl2dpi_bridge_atomic_disable, ··· 262 255 return ep; 263 256 } 264 257 265 - static struct drm_bridge * 266 - imx8qxp_pxl2dpi_find_next_bridge(struct imx8qxp_pxl2dpi *p2d) 258 + static int imx8qxp_pxl2dpi_find_next_bridge(struct imx8qxp_pxl2dpi *p2d) 267 259 { 268 - struct device_node *ep, *remote; 269 - struct drm_bridge *next_bridge; 270 - int ret; 260 + struct device_node *ep __free(device_node) = 261 + imx8qxp_pxl2dpi_get_available_ep_from_port(p2d, 1); 262 + if (IS_ERR(ep)) 263 + return PTR_ERR(ep); 271 264 272 - ep = imx8qxp_pxl2dpi_get_available_ep_from_port(p2d, 1); 273 - if (IS_ERR(ep)) { 274 - ret = PTR_ERR(ep); 275 - return ERR_PTR(ret); 276 - } 277 - 278 - remote = of_graph_get_remote_port_parent(ep); 265 + struct device_node *remote __free(device_node) = of_graph_get_remote_port_parent(ep); 279 266 if (!remote || !of_device_is_available(remote)) { 280 267 DRM_DEV_ERROR(p2d->dev, "no available remote\n"); 281 - next_bridge = ERR_PTR(-ENODEV); 282 - goto out; 268 + return -ENODEV; 283 269 } else if (!of_device_is_available(remote->parent)) { 284 270 DRM_DEV_ERROR(p2d->dev, "remote parent is not available\n"); 285 - next_bridge = ERR_PTR(-ENODEV); 286 - goto out; 271 + return -ENODEV; 287 272 } 288 273 289 - next_bridge = of_drm_find_bridge(remote); 290 - if (!next_bridge) { 291 - next_bridge = ERR_PTR(-EPROBE_DEFER); 292 - goto out; 293 - } 294 - out: 295 - of_node_put(remote); 296 - of_node_put(ep); 274 + p2d->bridge.next_bridge = of_drm_find_and_get_bridge(remote); 275 + if (!p2d->bridge.next_bridge) 276 + return -EPROBE_DEFER; 297 277 298 - return next_bridge; 278 + return 0; 299 279 } 300 280 301 281 static int imx8qxp_pxl2dpi_set_pixel_link_sel(struct imx8qxp_pxl2dpi *p2d) ··· 341 347 goto out; 342 348 } 343 349 344 - p2d->companion = of_drm_find_bridge(companion); 350 + p2d->companion = of_drm_find_and_get_bridge(companion); 345 351 if (!p2d->companion) { 346 352 ret = -EPROBE_DEFER; 347 353 DRM_DEV_DEBUG_DRIVER(p2d->dev, ··· 358 364 * the next bridges are connected to. If they are marked as expecting 359 365 * even pixels and odd pixels than we need to use the companion PXL2DPI. 360 366 */ 361 - port1 = of_graph_get_port_by_id(p2d->next_bridge->of_node, 1); 362 - port2 = of_graph_get_port_by_id(companion_p2d->next_bridge->of_node, 1); 367 + port1 = of_graph_get_port_by_id(p2d->bridge.next_bridge->of_node, 1); 368 + port2 = of_graph_get_port_by_id(companion_p2d->bridge.next_bridge->of_node, 1); 363 369 dual_link = drm_of_lvds_get_dual_link_pixel_order(port1, port2); 364 370 of_node_put(port1); 365 371 of_node_put(port2); ··· 415 421 return ret; 416 422 } 417 423 418 - p2d->next_bridge = imx8qxp_pxl2dpi_find_next_bridge(p2d); 419 - if (IS_ERR(p2d->next_bridge)) { 420 - ret = PTR_ERR(p2d->next_bridge); 421 - if (ret != -EPROBE_DEFER) 422 - DRM_DEV_ERROR(dev, "failed to find next bridge: %d\n", 423 - ret); 424 + ret = imx8qxp_pxl2dpi_find_next_bridge(p2d); 425 + if (ret) 424 426 return ret; 425 - } 426 427 427 428 ret = imx8qxp_pxl2dpi_set_pixel_link_sel(p2d); 428 429 if (ret)
+3 -4
drivers/gpu/drm/bridge/ite-it66121.c
··· 298 298 struct it66121_ctx { 299 299 struct regmap *regmap; 300 300 struct drm_bridge bridge; 301 - struct drm_bridge *next_bridge; 302 301 struct drm_connector *connector; 303 302 struct device *dev; 304 303 struct gpio_desc *gpio_reset; ··· 595 596 if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) 596 597 return -EINVAL; 597 598 598 - ret = drm_bridge_attach(encoder, ctx->next_bridge, bridge, flags); 599 + ret = drm_bridge_attach(encoder, ctx->bridge.next_bridge, bridge, flags); 599 600 if (ret) 600 601 return ret; 601 602 ··· 1542 1543 return -EINVAL; 1543 1544 } 1544 1545 1545 - ctx->next_bridge = of_drm_find_bridge(ep); 1546 + ctx->bridge.next_bridge = of_drm_find_and_get_bridge(ep); 1546 1547 of_node_put(ep); 1547 - if (!ctx->next_bridge) { 1548 + if (!ctx->bridge.next_bridge) { 1548 1549 dev_dbg(ctx->dev, "Next bridge not found, deferring probe\n"); 1549 1550 return -EPROBE_DEFER; 1550 1551 }
+49 -76
drivers/gpu/drm/bridge/lontium-lt9611uxc.c
··· 17 17 #include <linux/wait.h> 18 18 #include <linux/workqueue.h> 19 19 20 - #include <sound/hdmi-codec.h> 21 - 22 20 #include <drm/drm_atomic_helper.h> 23 21 #include <drm/drm_bridge.h> 24 22 #include <drm/drm_edid.h> ··· 24 26 #include <drm/drm_of.h> 25 27 #include <drm/drm_print.h> 26 28 #include <drm/drm_probe_helper.h> 29 + 30 + #include <drm/display/drm_hdmi_audio_helper.h> 27 31 28 32 #define EDID_BLOCK_SIZE 128 29 33 #define EDID_NUM_BLOCKS 2 ··· 48 48 struct device_node *dsi1_node; 49 49 struct mipi_dsi_device *dsi0; 50 50 struct mipi_dsi_device *dsi1; 51 - struct platform_device *audio_pdev; 52 51 53 52 struct gpio_desc *reset_gpio; 54 53 struct gpio_desc *enable_gpio; ··· 428 429 return drm_edid_read_custom(connector, lt9611uxc_get_edid_block, lt9611uxc); 429 430 } 430 431 432 + static void lt9611uxc_bridge_hpd_notify(struct drm_bridge *bridge, 433 + struct drm_connector *connector, 434 + enum drm_connector_status status) 435 + { 436 + const struct drm_edid *drm_edid; 437 + 438 + if (status == connector_status_disconnected) { 439 + drm_connector_hdmi_audio_plugged_notify(connector, false); 440 + drm_edid_connector_update(connector, NULL); 441 + return; 442 + } 443 + 444 + drm_edid = lt9611uxc_bridge_edid_read(bridge, connector); 445 + drm_edid_connector_update(connector, drm_edid); 446 + drm_edid_free(drm_edid); 447 + 448 + if (status == connector_status_connected) 449 + drm_connector_hdmi_audio_plugged_notify(connector, true); 450 + } 451 + 452 + static int lt9611uxc_hdmi_audio_prepare(struct drm_bridge *bridge, 453 + struct drm_connector *connector, 454 + struct hdmi_codec_daifmt *fmt, 455 + struct hdmi_codec_params *hparms) 456 + { 457 + /* 458 + * LT9611UXC will automatically detect rate and sample size, so no need 459 + * to setup anything here. 460 + */ 461 + return 0; 462 + } 463 + 464 + static void lt9611uxc_hdmi_audio_shutdown(struct drm_bridge *bridge, 465 + struct drm_connector *connector) 466 + { 467 + } 468 + 431 469 static const struct drm_bridge_funcs lt9611uxc_bridge_funcs = { 432 470 .attach = lt9611uxc_bridge_attach, 433 471 .mode_valid = lt9611uxc_bridge_mode_valid, 434 472 .mode_set = lt9611uxc_bridge_mode_set, 435 473 .detect = lt9611uxc_bridge_detect, 436 474 .edid_read = lt9611uxc_bridge_edid_read, 475 + .hpd_notify = lt9611uxc_bridge_hpd_notify, 476 + .hdmi_audio_prepare = lt9611uxc_hdmi_audio_prepare, 477 + .hdmi_audio_shutdown = lt9611uxc_hdmi_audio_shutdown, 437 478 }; 438 479 439 480 static int lt9611uxc_parse_dt(struct device *dev, ··· 545 506 lt9611uxc_unlock(lt9611uxc); 546 507 547 508 return ret < 0 ? ret : rev; 548 - } 549 - 550 - static int lt9611uxc_hdmi_hw_params(struct device *dev, void *data, 551 - struct hdmi_codec_daifmt *fmt, 552 - struct hdmi_codec_params *hparms) 553 - { 554 - /* 555 - * LT9611UXC will automatically detect rate and sample size, so no need 556 - * to setup anything here. 557 - */ 558 - return 0; 559 - } 560 - 561 - static void lt9611uxc_audio_shutdown(struct device *dev, void *data) 562 - { 563 - } 564 - 565 - static int lt9611uxc_hdmi_i2s_get_dai_id(struct snd_soc_component *component, 566 - struct device_node *endpoint, 567 - void *data) 568 - { 569 - struct of_endpoint of_ep; 570 - int ret; 571 - 572 - ret = of_graph_parse_endpoint(endpoint, &of_ep); 573 - if (ret < 0) 574 - return ret; 575 - 576 - /* 577 - * HDMI sound should be located as reg = <2> 578 - * Then, it is sound port 0 579 - */ 580 - if (of_ep.port == 2) 581 - return 0; 582 - 583 - return -EINVAL; 584 - } 585 - 586 - static const struct hdmi_codec_ops lt9611uxc_codec_ops = { 587 - .hw_params = lt9611uxc_hdmi_hw_params, 588 - .audio_shutdown = lt9611uxc_audio_shutdown, 589 - .get_dai_id = lt9611uxc_hdmi_i2s_get_dai_id, 590 - }; 591 - 592 - static int lt9611uxc_audio_init(struct device *dev, struct lt9611uxc *lt9611uxc) 593 - { 594 - struct hdmi_codec_pdata codec_data = { 595 - .ops = &lt9611uxc_codec_ops, 596 - .max_i2s_channels = 2, 597 - .i2s = 1, 598 - .data = lt9611uxc, 599 - }; 600 - 601 - lt9611uxc->audio_pdev = 602 - platform_device_register_data(dev, HDMI_CODEC_DRV_NAME, 603 - PLATFORM_DEVID_AUTO, 604 - &codec_data, sizeof(codec_data)); 605 - 606 - return PTR_ERR_OR_ZERO(lt9611uxc->audio_pdev); 607 - } 608 - 609 - static void lt9611uxc_audio_exit(struct lt9611uxc *lt9611uxc) 610 - { 611 - if (lt9611uxc->audio_pdev) { 612 - platform_device_unregister(lt9611uxc->audio_pdev); 613 - lt9611uxc->audio_pdev = NULL; 614 - } 615 509 } 616 510 617 511 #define LT9611UXC_FW_PAGE_SIZE 32 ··· 830 858 i2c_set_clientdata(client, lt9611uxc); 831 859 832 860 lt9611uxc->bridge.of_node = client->dev.of_node; 833 - lt9611uxc->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID; 861 + lt9611uxc->bridge.ops = DRM_BRIDGE_OP_DETECT | 862 + DRM_BRIDGE_OP_EDID | 863 + DRM_BRIDGE_OP_HDMI_AUDIO; 834 864 if (lt9611uxc->hpd_supported) 835 865 lt9611uxc->bridge.ops |= DRM_BRIDGE_OP_HPD; 836 866 lt9611uxc->bridge.type = DRM_MODE_CONNECTOR_HDMIA; 867 + 868 + lt9611uxc->bridge.hdmi_audio_dev = dev; 869 + lt9611uxc->bridge.hdmi_audio_max_i2s_playback_channels = 2; 870 + lt9611uxc->bridge.hdmi_audio_dai_port = 2; 837 871 838 872 drm_bridge_add(&lt9611uxc->bridge); 839 873 ··· 858 880 goto err_remove_bridge; 859 881 } 860 882 } 861 - 862 - ret = lt9611uxc_audio_init(dev, lt9611uxc); 863 - if (ret) 864 - goto err_remove_bridge; 865 883 866 884 return 0; 867 885 ··· 882 908 883 909 free_irq(client->irq, lt9611uxc); 884 910 cancel_work_sync(&lt9611uxc->work); 885 - lt9611uxc_audio_exit(lt9611uxc); 886 911 drm_bridge_remove(&lt9611uxc->bridge); 887 912 888 913 mutex_destroy(&lt9611uxc->ocm_lock);
+7 -8
drivers/gpu/drm/bridge/simple-bridge.c
··· 31 31 32 32 const struct simple_bridge_info *info; 33 33 34 - struct drm_bridge *next_bridge; 35 34 struct regulator *vdd; 36 35 struct gpio_desc *enable; 37 36 }; ··· 53 54 const struct drm_edid *drm_edid; 54 55 int ret; 55 56 56 - if (sbridge->next_bridge->ops & DRM_BRIDGE_OP_EDID) { 57 - drm_edid = drm_bridge_edid_read(sbridge->next_bridge, connector); 57 + if (sbridge->bridge.next_bridge->ops & DRM_BRIDGE_OP_EDID) { 58 + drm_edid = drm_bridge_edid_read(sbridge->bridge.next_bridge, connector); 58 59 if (!drm_edid) 59 60 DRM_INFO("EDID read failed. Fallback to standard modes\n"); 60 61 } else { ··· 89 90 { 90 91 struct simple_bridge *sbridge = drm_connector_to_simple_bridge(connector); 91 92 92 - return drm_bridge_detect(sbridge->next_bridge, connector); 93 + return drm_bridge_detect(sbridge->bridge.next_bridge, connector); 93 94 } 94 95 95 96 static const struct drm_connector_funcs simple_bridge_con_funcs = { ··· 108 109 struct simple_bridge *sbridge = drm_bridge_to_simple_bridge(bridge); 109 110 int ret; 110 111 111 - ret = drm_bridge_attach(encoder, sbridge->next_bridge, bridge, 112 + ret = drm_bridge_attach(encoder, sbridge->bridge.next_bridge, bridge, 112 113 DRM_BRIDGE_ATTACH_NO_CONNECTOR); 113 114 if (ret < 0) 114 115 return ret; ··· 121 122 ret = drm_connector_init_with_ddc(bridge->dev, &sbridge->connector, 122 123 &simple_bridge_con_funcs, 123 124 sbridge->info->connector_type, 124 - sbridge->next_bridge->ddc); 125 + sbridge->bridge.next_bridge->ddc); 125 126 if (ret) { 126 127 DRM_ERROR("Failed to initialize connector\n"); 127 128 return ret; ··· 179 180 if (!remote) 180 181 return -EINVAL; 181 182 182 - sbridge->next_bridge = of_drm_find_bridge(remote); 183 + sbridge->bridge.next_bridge = of_drm_find_and_get_bridge(remote); 183 184 of_node_put(remote); 184 185 185 - if (!sbridge->next_bridge) { 186 + if (!sbridge->bridge.next_bridge) { 186 187 dev_dbg(&pdev->dev, "Next bridge not found, deferring probe\n"); 187 188 return -EPROBE_DEFER; 188 189 }
+1 -1
drivers/gpu/drm/clients/drm_log.c
··· 182 182 int i; 183 183 184 184 for (i = 0; i < plane->format_count; i++) 185 - if (drm_draw_color_from_xrgb8888(0xffffff, plane->format_types[i]) != 0) 185 + if (drm_draw_can_convert_from_xrgb8888(plane->format_types[i])) 186 186 return plane->format_types[i]; 187 187 return DRM_FORMAT_INVALID; 188 188 }
+1 -1
drivers/gpu/drm/display/drm_bridge_connector.c
··· 141 141 /* Notify all bridges in the pipeline of hotplug events. */ 142 142 drm_for_each_bridge_in_chain_scoped(bridge_connector->encoder, bridge) { 143 143 if (bridge->funcs->hpd_notify) 144 - bridge->funcs->hpd_notify(bridge, status); 144 + bridge->funcs->hpd_notify(bridge, connector, status); 145 145 } 146 146 } 147 147
+32
drivers/gpu/drm/drm_atomic.c
··· 641 641 } 642 642 EXPORT_SYMBOL(drm_atomic_get_colorop_state); 643 643 644 + /** 645 + * drm_atomic_get_old_colorop_state - get colorop state, if it exists 646 + * @state: global atomic state object 647 + * @colorop: colorop to grab 648 + * 649 + * This function returns the old colorop state for the given colorop, or 650 + * NULL if the colorop is not part of the global atomic state. 651 + */ 652 + struct drm_colorop_state * 653 + drm_atomic_get_old_colorop_state(struct drm_atomic_state *state, 654 + struct drm_colorop *colorop) 655 + { 656 + return state->colorops[drm_colorop_index(colorop)].old_state; 657 + } 658 + EXPORT_SYMBOL(drm_atomic_get_old_colorop_state); 659 + 660 + /** 661 + * drm_atomic_get_new_colorop_state - get colorop state, if it exists 662 + * @state: global atomic state object 663 + * @colorop: colorop to grab 664 + * 665 + * This function returns the new colorop state for the given colorop, or 666 + * NULL if the colorop is not part of the global atomic state. 667 + */ 668 + struct drm_colorop_state * 669 + drm_atomic_get_new_colorop_state(struct drm_atomic_state *state, 670 + struct drm_colorop *colorop) 671 + { 672 + return state->colorops[drm_colorop_index(colorop)].new_state; 673 + } 674 + EXPORT_SYMBOL(drm_atomic_get_new_colorop_state); 675 + 644 676 static bool 645 677 plane_switching_crtc(const struct drm_plane_state *old_plane_state, 646 678 const struct drm_plane_state *new_plane_state)
+1
drivers/gpu/drm/drm_atomic_helper.c
··· 34 34 #include <drm/drm_atomic_uapi.h> 35 35 #include <drm/drm_blend.h> 36 36 #include <drm/drm_bridge.h> 37 + #include <drm/drm_colorop.h> 37 38 #include <drm/drm_damage_helper.h> 38 39 #include <drm/drm_device.h> 39 40 #include <drm/drm_drv.h>
+54 -15
drivers/gpu/drm/drm_bridge.c
··· 275 275 if (bridge->funcs->destroy) 276 276 bridge->funcs->destroy(bridge); 277 277 278 + drm_bridge_put(bridge->next_bridge); 279 + 278 280 kfree(bridge->container); 279 281 } 280 282 ··· 363 361 * @bridge: bridge control structure 364 362 * 365 363 * Add the given bridge to the global list of bridges, where they can be 366 - * found by users via of_drm_find_bridge(). 364 + * found by users via of_drm_find_and_get_bridge(). 367 365 * 368 366 * The bridge to be added must have been allocated by 369 367 * devm_drm_bridge_alloc(). ··· 424 422 * @bridge: bridge control structure 425 423 * 426 424 * Remove the given bridge from the global list of registered bridges, so 427 - * it won't be found by users via of_drm_find_bridge(), and add it to the 428 - * lingering bridge list, to keep track of it until its allocated memory is 429 - * eventually freed. 425 + * it won't be found by users via of_drm_find_and_get_bridge(), and add it 426 + * to the lingering bridge list, to keep track of it until its allocated 427 + * memory is eventually freed. 430 428 */ 431 429 void drm_bridge_remove(struct drm_bridge *bridge) 432 430 { ··· 1482 1480 1483 1481 #ifdef CONFIG_OF 1484 1482 /** 1483 + * of_drm_find_and_get_bridge - find the bridge corresponding to the device 1484 + * node in the global bridge list 1485 + * @np: device node 1486 + * 1487 + * The refcount of the returned bridge is incremented. Use drm_bridge_put() 1488 + * when done with it. 1489 + * 1490 + * RETURNS: 1491 + * drm_bridge control struct on success, NULL on failure 1492 + */ 1493 + struct drm_bridge *of_drm_find_and_get_bridge(struct device_node *np) 1494 + { 1495 + struct drm_bridge *bridge; 1496 + 1497 + scoped_guard(mutex, &bridge_lock) { 1498 + list_for_each_entry(bridge, &bridge_list, list) 1499 + if (bridge->of_node == np) 1500 + return drm_bridge_get(bridge); 1501 + } 1502 + 1503 + return NULL; 1504 + } 1505 + EXPORT_SYMBOL(of_drm_find_and_get_bridge); 1506 + 1507 + /** 1485 1508 * of_drm_find_bridge - find the bridge corresponding to the device node in 1486 1509 * the global bridge list 1487 1510 * 1488 1511 * @np: device node 1512 + * 1513 + * This function is deprecated. Convert to of_drm_find_and_get_bridge() 1514 + * instead for proper refcounting. 1515 + * 1516 + * The bridge returned by this function is not refcounted. This is 1517 + * dangerous because the bridge might be deallocated even before the caller 1518 + * has a chance to use it. To use this function you have to do one of: 1519 + * - get a reference with drm_bridge_get() as soon as possible to 1520 + * minimize the race window, and then drm_bridge_put() when no longer 1521 + * using the pointer 1522 + * - not call drm_bridge_get() or drm_bridge_put() at all, which used to 1523 + * be the correct practice before dynamic bridge lifetime was introduced 1524 + * - again, convert to of_drm_find_and_get_bridge(), which is the only safe 1525 + * thing to do 1489 1526 * 1490 1527 * RETURNS: 1491 1528 * drm_bridge control struct on success, NULL on failure 1492 1529 */ 1493 1530 struct drm_bridge *of_drm_find_bridge(struct device_node *np) 1494 1531 { 1495 - struct drm_bridge *bridge; 1532 + struct drm_bridge *bridge = of_drm_find_and_get_bridge(np); 1496 1533 1497 - mutex_lock(&bridge_lock); 1534 + /* 1535 + * We need to emulate the original semantics of 1536 + * of_drm_find_bridge(), which was not getting any bridge 1537 + * reference. Being now based on of_drm_find_and_get_bridge() which 1538 + * gets a reference, put it before returning. 1539 + */ 1540 + drm_bridge_put(bridge); 1498 1541 1499 - list_for_each_entry(bridge, &bridge_list, list) { 1500 - if (bridge->of_node == np) { 1501 - mutex_unlock(&bridge_lock); 1502 - return bridge; 1503 - } 1504 - } 1505 - 1506 - mutex_unlock(&bridge_lock); 1507 - return NULL; 1542 + return bridge; 1508 1543 } 1509 1544 EXPORT_SYMBOL(of_drm_find_bridge); 1510 1545 #endif
+29
drivers/gpu/drm/drm_draw.c
··· 16 16 #include "drm_format_internal.h" 17 17 18 18 /** 19 + * drm_draw_can_convert_from_xrgb8888 - check if xrgb8888 can be converted to the desired format 20 + * @format: format 21 + * 22 + * Returns: 23 + * True if XRGB8888 can be converted to the specified format, false otherwise. 24 + */ 25 + bool drm_draw_can_convert_from_xrgb8888(u32 format) 26 + { 27 + switch (format) { 28 + case DRM_FORMAT_RGB565: 29 + case DRM_FORMAT_RGBA5551: 30 + case DRM_FORMAT_XRGB1555: 31 + case DRM_FORMAT_ARGB1555: 32 + case DRM_FORMAT_RGB888: 33 + case DRM_FORMAT_XRGB8888: 34 + case DRM_FORMAT_ARGB8888: 35 + case DRM_FORMAT_XBGR8888: 36 + case DRM_FORMAT_ABGR8888: 37 + case DRM_FORMAT_XRGB2101010: 38 + case DRM_FORMAT_ARGB2101010: 39 + case DRM_FORMAT_ABGR2101010: 40 + return true; 41 + default: 42 + return false; 43 + } 44 + } 45 + EXPORT_SYMBOL(drm_draw_can_convert_from_xrgb8888); 46 + 47 + /** 19 48 * drm_draw_color_from_xrgb8888 - convert one pixel from xrgb8888 to the desired format 20 49 * @color: input color, in xrgb8888 format 21 50 * @format: output format
+2
drivers/gpu/drm/drm_draw_internal.h
··· 24 24 return font->data + (c * font->height) * font_pitch; 25 25 } 26 26 27 + bool drm_draw_can_convert_from_xrgb8888(u32 format); 28 + 27 29 u32 drm_draw_color_from_xrgb8888(u32 color, u32 format); 28 30 29 31 void drm_draw_blit16(struct iosys_map *dmap, unsigned int dpitch,
+63
drivers/gpu/drm/drm_gem_shmem_helper.c
··· 15 15 #include <asm/set_memory.h> 16 16 #endif 17 17 18 + #include <kunit/visibility.h> 19 + 18 20 #include <drm/drm.h> 19 21 #include <drm/drm_device.h> 20 22 #include <drm/drm_drv.h> ··· 902 900 return ERR_PTR(ret); 903 901 } 904 902 EXPORT_SYMBOL_GPL(drm_gem_shmem_prime_import_no_map); 903 + 904 + /* 905 + * Kunit helpers 906 + */ 907 + 908 + #if IS_ENABLED(CONFIG_KUNIT) 909 + int drm_gem_shmem_vmap(struct drm_gem_shmem_object *shmem, struct iosys_map *map) 910 + { 911 + struct drm_gem_object *obj = &shmem->base; 912 + int ret; 913 + 914 + ret = dma_resv_lock_interruptible(obj->resv, NULL); 915 + if (ret) 916 + return ret; 917 + ret = drm_gem_shmem_vmap_locked(shmem, map); 918 + dma_resv_unlock(obj->resv); 919 + 920 + return ret; 921 + } 922 + EXPORT_SYMBOL_IF_KUNIT(drm_gem_shmem_vmap); 923 + 924 + void drm_gem_shmem_vunmap(struct drm_gem_shmem_object *shmem, struct iosys_map *map) 925 + { 926 + struct drm_gem_object *obj = &shmem->base; 927 + 928 + dma_resv_lock_interruptible(obj->resv, NULL); 929 + drm_gem_shmem_vunmap_locked(shmem, map); 930 + dma_resv_unlock(obj->resv); 931 + } 932 + EXPORT_SYMBOL_IF_KUNIT(drm_gem_shmem_vunmap); 933 + 934 + int drm_gem_shmem_madvise(struct drm_gem_shmem_object *shmem, int madv) 935 + { 936 + struct drm_gem_object *obj = &shmem->base; 937 + int ret; 938 + 939 + ret = dma_resv_lock_interruptible(obj->resv, NULL); 940 + if (ret) 941 + return ret; 942 + ret = drm_gem_shmem_madvise_locked(shmem, madv); 943 + dma_resv_unlock(obj->resv); 944 + 945 + return ret; 946 + } 947 + EXPORT_SYMBOL_IF_KUNIT(drm_gem_shmem_madvise); 948 + 949 + int drm_gem_shmem_purge(struct drm_gem_shmem_object *shmem) 950 + { 951 + struct drm_gem_object *obj = &shmem->base; 952 + int ret; 953 + 954 + ret = dma_resv_lock_interruptible(obj->resv, NULL); 955 + if (ret) 956 + return ret; 957 + drm_gem_shmem_purge_locked(shmem); 958 + dma_resv_unlock(obj->resv); 959 + 960 + return 0; 961 + } 962 + EXPORT_SYMBOL_IF_KUNIT(drm_gem_shmem_purge); 963 + #endif 905 964 906 965 MODULE_DESCRIPTION("DRM SHMEM memory-management helpers"); 907 966 MODULE_IMPORT_NS("DMA_BUF");
+14 -10
drivers/gpu/drm/drm_panic.c
··· 476 476 fg_color); 477 477 } 478 478 479 - static void draw_panic_static_user(struct drm_scanout_buffer *sb) 479 + static void draw_panic_screen_user(struct drm_scanout_buffer *sb) 480 480 { 481 481 u32 fg_color = drm_draw_color_from_xrgb8888(CONFIG_DRM_PANIC_FOREGROUND_COLOR, 482 482 sb->format->format); ··· 545 545 * Draw the kmsg buffer to the screen, starting from the youngest message at the bottom, 546 546 * and going up until reaching the top of the screen. 547 547 */ 548 - static void draw_panic_static_kmsg(struct drm_scanout_buffer *sb) 548 + static void draw_panic_screen_kmsg(struct drm_scanout_buffer *sb) 549 549 { 550 550 u32 fg_color = drm_draw_color_from_xrgb8888(CONFIG_DRM_PANIC_FOREGROUND_COLOR, 551 551 sb->format->format); ··· 733 733 /* 734 734 * Draw the panic message at the center of the screen, with a QR Code 735 735 */ 736 - static int _draw_panic_static_qr_code(struct drm_scanout_buffer *sb) 736 + static int _draw_panic_screen_qr_code(struct drm_scanout_buffer *sb) 737 737 { 738 738 u32 fg_color = drm_draw_color_from_xrgb8888(CONFIG_DRM_PANIC_FOREGROUND_COLOR, 739 739 sb->format->format); ··· 801 801 return 0; 802 802 } 803 803 804 - static void draw_panic_static_qr_code(struct drm_scanout_buffer *sb) 804 + static void draw_panic_screen_qr_code(struct drm_scanout_buffer *sb) 805 805 { 806 - if (_draw_panic_static_qr_code(sb)) 807 - draw_panic_static_user(sb); 806 + if (_draw_panic_screen_qr_code(sb)) 807 + draw_panic_screen_user(sb); 808 808 } 809 809 #else 810 810 static void drm_panic_qr_init(void) {}; ··· 872 872 { 873 873 if (format->num_planes != 1) 874 874 return false; 875 - return drm_draw_color_from_xrgb8888(0xffffff, format->format) != 0; 875 + return drm_draw_can_convert_from_xrgb8888(format->format); 876 876 } 877 877 878 878 static void draw_panic_dispatch(struct drm_scanout_buffer *sb) 879 879 { 880 880 switch (drm_panic_type) { 881 881 case DRM_PANIC_TYPE_KMSG: 882 - draw_panic_static_kmsg(sb); 882 + draw_panic_screen_kmsg(sb); 883 883 break; 884 884 885 885 #if IS_ENABLED(CONFIG_DRM_PANIC_SCREEN_QR_CODE) 886 886 case DRM_PANIC_TYPE_QR: 887 - draw_panic_static_qr_code(sb); 887 + draw_panic_screen_qr_code(sb); 888 888 break; 889 889 #endif 890 890 891 891 case DRM_PANIC_TYPE_USER: 892 892 default: 893 - draw_panic_static_user(sb); 893 + draw_panic_screen_user(sb); 894 894 } 895 895 } 896 896 ··· 1084 1084 { 1085 1085 drm_panic_qr_exit(); 1086 1086 } 1087 + 1088 + #ifdef CONFIG_DRM_KUNIT_TEST 1089 + #include "tests/drm_panic_test.c" 1090 + #endif
+1
drivers/gpu/drm/etnaviv/Makefile
··· 14 14 etnaviv_iommu.o \ 15 15 etnaviv_mmu.o \ 16 16 etnaviv_perfmon.o \ 17 + etnaviv_flop_reset.o \ 17 18 etnaviv_sched.o 18 19 19 20 obj-$(CONFIG_DRM_ETNAVIV) += etnaviv.o
+6 -69
drivers/gpu/drm/etnaviv/etnaviv_buffer.c
··· 10 10 #include "etnaviv_gpu.h" 11 11 #include "etnaviv_gem.h" 12 12 #include "etnaviv_mmu.h" 13 + #include "etnaviv_buffer.h" 13 14 14 15 #include "common.xml.h" 15 16 #include "state.xml.h" ··· 19 18 #include "state_3d.xml.h" 20 19 #include "cmdstream.xml.h" 21 20 22 - /* 23 - * Command Buffer helper: 24 - */ 25 - 26 - 27 - static inline void OUT(struct etnaviv_cmdbuf *buffer, u32 data) 28 - { 29 - u32 *vaddr = (u32 *)buffer->vaddr; 30 - 31 - BUG_ON(buffer->user_size >= buffer->size); 32 - 33 - vaddr[buffer->user_size / 4] = data; 34 - buffer->user_size += 4; 35 - } 36 - 37 - static inline void CMD_LOAD_STATE(struct etnaviv_cmdbuf *buffer, 38 - u32 reg, u32 value) 39 - { 40 - u32 index = reg >> VIV_FE_LOAD_STATE_HEADER_OFFSET__SHR; 41 - 42 - buffer->user_size = ALIGN(buffer->user_size, 8); 43 - 44 - /* write a register via cmd stream */ 45 - OUT(buffer, VIV_FE_LOAD_STATE_HEADER_OP_LOAD_STATE | 46 - VIV_FE_LOAD_STATE_HEADER_COUNT(1) | 47 - VIV_FE_LOAD_STATE_HEADER_OFFSET(index)); 48 - OUT(buffer, value); 49 - } 50 - 51 - static inline void CMD_END(struct etnaviv_cmdbuf *buffer) 52 - { 53 - buffer->user_size = ALIGN(buffer->user_size, 8); 54 - 55 - OUT(buffer, VIV_FE_END_HEADER_OP_END); 56 - } 57 - 58 - static inline void CMD_WAIT(struct etnaviv_cmdbuf *buffer, 59 - unsigned int waitcycles) 60 - { 61 - buffer->user_size = ALIGN(buffer->user_size, 8); 62 - 63 - OUT(buffer, VIV_FE_WAIT_HEADER_OP_WAIT | waitcycles); 64 - } 65 - 66 - static inline void CMD_LINK(struct etnaviv_cmdbuf *buffer, 67 - u16 prefetch, u32 address) 68 - { 69 - buffer->user_size = ALIGN(buffer->user_size, 8); 70 - 71 - OUT(buffer, VIV_FE_LINK_HEADER_OP_LINK | 72 - VIV_FE_LINK_HEADER_PREFETCH(prefetch)); 73 - OUT(buffer, address); 74 - } 75 - 76 - static inline void CMD_STALL(struct etnaviv_cmdbuf *buffer, 77 - u32 from, u32 to) 78 - { 79 - buffer->user_size = ALIGN(buffer->user_size, 8); 80 - 81 - OUT(buffer, VIV_FE_STALL_HEADER_OP_STALL); 82 - OUT(buffer, VIV_FE_STALL_TOKEN_FROM(from) | VIV_FE_STALL_TOKEN_TO(to)); 83 - } 84 - 85 - static inline void CMD_SEM(struct etnaviv_cmdbuf *buffer, u32 from, u32 to) 86 - { 87 - CMD_LOAD_STATE(buffer, VIVS_GL_SEMAPHORE_TOKEN, 88 - VIVS_GL_SEMAPHORE_TOKEN_FROM(from) | 89 - VIVS_GL_SEMAPHORE_TOKEN_TO(to)); 90 - } 21 + #include "etnaviv_flop_reset.h" 91 22 92 23 static void etnaviv_cmd_select_pipe(struct etnaviv_gpu *gpu, 93 24 struct etnaviv_cmdbuf *buffer, u8 pipe) ··· 102 169 103 170 /* initialize buffer */ 104 171 buffer->user_size = 0; 172 + 173 + /* Queue in PPU flop reset */ 174 + if (etnaviv_flop_reset_ppu_require(&gpu->identity)) 175 + etnaviv_flop_reset_ppu_run(gpu); 105 176 106 177 CMD_WAIT(buffer, gpu->fe_waitcycles); 107 178 CMD_LINK(buffer, 2,
+99
drivers/gpu/drm/etnaviv/etnaviv_buffer.h
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (C) 2014-2025 Etnaviv Project 4 + */ 5 + 6 + #ifndef __ETNAVIV_BUFFER_H__ 7 + #define __ETNAVIV_BUFFER_H__ 8 + 9 + #include "etnaviv_cmdbuf.h" 10 + #include "etnaviv_gpu.h" 11 + #include "etnaviv_gem.h" 12 + #include "etnaviv_mmu.h" 13 + 14 + #include "common.xml.h" 15 + #include "linux/printk.h" 16 + #include "state.xml.h" 17 + #include "state_blt.xml.h" 18 + #include "state_hi.xml.h" 19 + #include "state_3d.xml.h" 20 + #include "cmdstream.xml.h" 21 + 22 + static inline void OUT(struct etnaviv_cmdbuf *buffer, u32 data) 23 + { 24 + u32 *vaddr = (u32 *)buffer->vaddr; 25 + 26 + BUG_ON(buffer->user_size >= buffer->size); 27 + 28 + vaddr[buffer->user_size / 4] = data; 29 + buffer->user_size += 4; 30 + } 31 + 32 + static inline void CMD_LOAD_STATE(struct etnaviv_cmdbuf *buffer, u32 reg, 33 + u32 value) 34 + { 35 + u32 index = reg >> VIV_FE_LOAD_STATE_HEADER_OFFSET__SHR; 36 + 37 + buffer->user_size = ALIGN(buffer->user_size, 8); 38 + 39 + /* write a register via cmd stream */ 40 + OUT(buffer, VIV_FE_LOAD_STATE_HEADER_OP_LOAD_STATE | 41 + VIV_FE_LOAD_STATE_HEADER_COUNT(1) | 42 + VIV_FE_LOAD_STATE_HEADER_OFFSET(index)); 43 + OUT(buffer, value); 44 + } 45 + 46 + static inline void CMD_LOAD_STATES_START(struct etnaviv_cmdbuf *buffer, u32 reg, 47 + u32 nvalues) 48 + { 49 + u32 index = reg >> VIV_FE_LOAD_STATE_HEADER_OFFSET__SHR; 50 + 51 + buffer->user_size = ALIGN(buffer->user_size, 8); 52 + 53 + /* write a register via cmd stream */ 54 + OUT(buffer, VIV_FE_LOAD_STATE_HEADER_OP_LOAD_STATE | 55 + VIV_FE_LOAD_STATE_HEADER_OFFSET(index) | 56 + VIV_FE_LOAD_STATE_HEADER_COUNT(nvalues)); 57 + } 58 + 59 + static inline void CMD_END(struct etnaviv_cmdbuf *buffer) 60 + { 61 + buffer->user_size = ALIGN(buffer->user_size, 8); 62 + 63 + OUT(buffer, VIV_FE_END_HEADER_OP_END); 64 + } 65 + 66 + static inline void CMD_WAIT(struct etnaviv_cmdbuf *buffer, 67 + unsigned int waitcycles) 68 + { 69 + buffer->user_size = ALIGN(buffer->user_size, 8); 70 + 71 + OUT(buffer, VIV_FE_WAIT_HEADER_OP_WAIT | waitcycles); 72 + } 73 + 74 + static inline void CMD_LINK(struct etnaviv_cmdbuf *buffer, u16 prefetch, 75 + u32 address) 76 + { 77 + buffer->user_size = ALIGN(buffer->user_size, 8); 78 + 79 + OUT(buffer, 80 + VIV_FE_LINK_HEADER_OP_LINK | VIV_FE_LINK_HEADER_PREFETCH(prefetch)); 81 + OUT(buffer, address); 82 + } 83 + 84 + static inline void CMD_STALL(struct etnaviv_cmdbuf *buffer, u32 from, u32 to) 85 + { 86 + buffer->user_size = ALIGN(buffer->user_size, 8); 87 + 88 + OUT(buffer, VIV_FE_STALL_HEADER_OP_STALL); 89 + OUT(buffer, VIV_FE_STALL_TOKEN_FROM(from) | VIV_FE_STALL_TOKEN_TO(to)); 90 + } 91 + 92 + static inline void CMD_SEM(struct etnaviv_cmdbuf *buffer, u32 from, u32 to) 93 + { 94 + CMD_LOAD_STATE(buffer, VIVS_GL_SEMAPHORE_TOKEN, 95 + VIVS_GL_SEMAPHORE_TOKEN_FROM(from) | 96 + VIVS_GL_SEMAPHORE_TOKEN_TO(to)); 97 + } 98 + 99 + #endif /* __ETNAVIV_BUFFER_H__ */
+3
drivers/gpu/drm/etnaviv/etnaviv_drv.c
··· 601 601 602 602 component_unbind_all(dev, drm); 603 603 604 + etnaviv_cmdbuf_free(priv->flop_reset_data_ppu); 605 + kfree(priv->flop_reset_data_ppu); 606 + 604 607 etnaviv_cmdbuf_suballoc_destroy(priv->cmdbuf_suballoc); 605 608 606 609 xa_destroy(&priv->active_contexts);
+3
drivers/gpu/drm/etnaviv/etnaviv_drv.h
··· 48 48 /* list of GEM objects: */ 49 49 struct mutex gem_lock; 50 50 struct list_head gem_list; 51 + 52 + /* ppu flop reset data */ 53 + struct etnaviv_cmdbuf *flop_reset_data_ppu; 51 54 }; 52 55 53 56 int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,
+224
drivers/gpu/drm/etnaviv/etnaviv_flop_reset.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (C) 2025 Etnaviv Project 4 + */ 5 + 6 + #include <linux/errno.h> 7 + #include <linux/dev_printk.h> 8 + #include <linux/string.h> 9 + #include <linux/types.h> 10 + 11 + #include "etnaviv_buffer.h" 12 + #include "etnaviv_cmdbuf.h" 13 + #include "etnaviv_gpu.h" 14 + #include "state_3d.xml.h" 15 + 16 + #include "etnaviv_flop_reset.h" 17 + 18 + static int etnaviv_force_flop_reset; 19 + module_param_named(force_flop_reset, etnaviv_force_flop_reset, int, 0); 20 + 21 + #define PPU_IMAGE_STRIDE 64 22 + #define PPU_IMAGE_XSIZE 64 23 + #define PPU_IMAGE_YSIZE 6 24 + 25 + #define PPU_FLOP_RESET_INSTR_DWORD_COUNT 16 26 + 27 + static void etnaviv_emit_flop_reset_state_ppu(struct etnaviv_cmdbuf *cmdbuf, 28 + u32 buffer_base, u32 input_offset, 29 + u32 output_offset, 30 + u32 shader_offset, 31 + u32 shader_size, 32 + u32 shader_register_count) 33 + { 34 + CMD_LOAD_STATE(cmdbuf, VIVS_GL_API_MODE, VIVS_GL_API_MODE_OPENCL); 35 + CMD_SEM(cmdbuf, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_PE); 36 + CMD_STALL(cmdbuf, SYNC_RECIPIENT_FE, SYNC_RECIPIENT_PE); 37 + 38 + CMD_LOAD_STATES_START(cmdbuf, VIVS_SH_HALTI5_UNIFORMS(0), 4); 39 + 40 + OUT(cmdbuf, buffer_base + input_offset); 41 + OUT(cmdbuf, PPU_IMAGE_STRIDE); 42 + OUT(cmdbuf, PPU_IMAGE_XSIZE | (PPU_IMAGE_YSIZE << 16)); 43 + OUT(cmdbuf, 0x444051f0); 44 + OUT(cmdbuf, 0xffffffff); 45 + 46 + CMD_LOAD_STATES_START(cmdbuf, VIVS_SH_HALTI5_UNIFORMS(4), 4); 47 + OUT(cmdbuf, buffer_base + output_offset); 48 + OUT(cmdbuf, PPU_IMAGE_STRIDE); 49 + OUT(cmdbuf, PPU_IMAGE_XSIZE | (PPU_IMAGE_YSIZE << 16)); 50 + OUT(cmdbuf, 0x444051f0); 51 + OUT(cmdbuf, 0xffffffff); 52 + 53 + CMD_LOAD_STATE(cmdbuf, VIVS_CL_CONFIG, 54 + VIVS_CL_CONFIG_DIMENSIONS(2) | 55 + VIVS_CL_CONFIG_VALUE_ORDER(3)); 56 + CMD_LOAD_STATE(cmdbuf, VIVS_VS_ICACHE_INVALIDATE, 0x1f); 57 + CMD_LOAD_STATE(cmdbuf, VIVS_PS_VARYING_NUM_COMPONENTS(0), 0); 58 + CMD_LOAD_STATE(cmdbuf, VIVS_PS_TEMP_REGISTER_CONTROL, 59 + shader_register_count); 60 + CMD_LOAD_STATE(cmdbuf, VIVS_PS_SAMPLER_BASE, 0x0); 61 + CMD_LOAD_STATE(cmdbuf, VIVS_PS_UNIFORM_BASE, 0x0); 62 + CMD_LOAD_STATE(cmdbuf, VIVS_PS_NEWRANGE_LOW, 0x0); 63 + CMD_LOAD_STATE(cmdbuf, VIVS_PS_NEWRANGE_HIGH, shader_size / 16); 64 + CMD_LOAD_STATE(cmdbuf, VIVS_PS_INST_ADDR, buffer_base + shader_offset); 65 + CMD_LOAD_STATE(cmdbuf, VIVS_SH_CONFIG, VIVS_SH_CONFIG_RTNE_ROUNDING); 66 + CMD_LOAD_STATE(cmdbuf, VIVS_VS_ICACHE_CONTROL, 67 + VIVS_VS_ICACHE_CONTROL_ENABLE); 68 + CMD_LOAD_STATE(cmdbuf, VIVS_PS_ICACHE_COUNT, shader_size / 16 - 1); 69 + CMD_LOAD_STATE(cmdbuf, VIVS_PS_INPUT_COUNT, 0x1f01); 70 + CMD_LOAD_STATE(cmdbuf, VIVS_VS_HALTI5_UNK008A0, 0x0); 71 + CMD_LOAD_STATE(cmdbuf, VIVS_PA_VS_OUTPUT_COUNT, 0x0); 72 + CMD_LOAD_STATE(cmdbuf, VIVS_GL_VARYING_TOTAL_COMPONENTS, 0x0); 73 + CMD_LOAD_STATE(cmdbuf, VIVS_PS_CONTROL_EXT, 0x0); 74 + CMD_LOAD_STATE(cmdbuf, VIVS_VS_OUTPUT_COUNT, 0x1); 75 + CMD_LOAD_STATE(cmdbuf, VIVS_GL_HALTI5_SH_SPECIALS, 0x0); 76 + CMD_LOAD_STATE(cmdbuf, VIVS_PS_ICACHE_PREFETCH, 0x0); 77 + CMD_LOAD_STATE(cmdbuf, VIVS_CL_UNK00924, 0x0); 78 + CMD_LOAD_STATE(cmdbuf, VIVS_CL_THREAD_ALLOCATION, 0x1); 79 + 80 + CMD_LOAD_STATE(cmdbuf, VIVS_CL_GLOBAL_WORK_OFFSET_X, 0x0); 81 + CMD_LOAD_STATE(cmdbuf, VIVS_CL_GLOBAL_WORK_OFFSET_Y, 0x0); 82 + CMD_LOAD_STATE(cmdbuf, VIVS_CL_GLOBAL_WORK_OFFSET_Z, 0x0); 83 + 84 + CMD_LOAD_STATES_START(cmdbuf, VIVS_CL_WORKGROUP_COUNT_X, 9); 85 + OUT(cmdbuf, 0xf); 86 + OUT(cmdbuf, 0x5); 87 + OUT(cmdbuf, 0xffffffff); 88 + OUT(cmdbuf, 0x0); 89 + OUT(cmdbuf, 0x0); 90 + OUT(cmdbuf, 0x3ff); 91 + OUT(cmdbuf, 0x0); 92 + OUT(cmdbuf, 0x4); 93 + OUT(cmdbuf, 0x1); 94 + OUT(cmdbuf, 0x0); 95 + 96 + CMD_LOAD_STATE(cmdbuf, VIVS_CL_KICKER, 0xbadabeeb); 97 + CMD_LOAD_STATE(cmdbuf, VIVS_GL_FLUSH_CACHE, 98 + VIVS_GL_FLUSH_CACHE_SHADER_L1 | 99 + VIVS_GL_FLUSH_CACHE_UNK10 | 100 + VIVS_GL_FLUSH_CACHE_UNK11); 101 + } 102 + 103 + static void etnaviv_flop_reset_ppu_fill_input(u32 *buffer, u32 size) 104 + { 105 + memset32(buffer, 0x01010101, size / 4); 106 + } 107 + 108 + static void etnaviv_flop_reset_ppu_set_shader(u8 *dest) 109 + { 110 + static const u32 inst[PPU_FLOP_RESET_INSTR_DWORD_COUNT] = { 111 + /* img_load.u8 r1, c0, r0.xy */ 112 + 0x78011779, 113 + 0x39000804, 114 + 0x00A90050, 115 + 0x00000000, 116 + /* img_load.u8 r2, c0, r0.xy */ 117 + 0x78021779, 118 + 0x39000804, 119 + 0x00A90050, 120 + 0x00000000, 121 + /* dp2x8 r1, r1, r2, c3_512 */ 122 + 0xB8017145, 123 + 0x390018FC, 124 + 0x01C90140, 125 + 0x40390028, 126 + /* img_store.u8 r1, c2, r0.xy, r1 */ 127 + 0x380007BA, 128 + 0x39001804, 129 + 0x00A90050, 130 + 0x00390018, 131 + }; 132 + memcpy(dest, inst, sizeof(inst)); 133 + } 134 + 135 + static const struct etnaviv_flop_reset_entry { 136 + u16 chip_model; 137 + u16 revision; 138 + u32 flags; 139 + } etnaviv_flop_reset_db[] = { 140 + { 141 + .chip_model = 0x8000, 142 + .revision = 0x6205, 143 + }, 144 + }; 145 + 146 + bool etnaviv_flop_reset_ppu_require(const struct etnaviv_chip_identity *chip_id) 147 + { 148 + const struct etnaviv_flop_reset_entry *e = etnaviv_flop_reset_db; 149 + 150 + for (int i = 0; i < ARRAY_SIZE(etnaviv_flop_reset_db); ++i, ++e) { 151 + if (chip_id->model == e->chip_model && 152 + chip_id->revision == e->revision) 153 + return true; 154 + } 155 + 156 + if (etnaviv_force_flop_reset) { 157 + if (!(chip_id->features & chipFeatures_PIPE_3D)) { 158 + pr_warn("Etnaviv: model: 0x%04x, revision: 0x%04x does not support PIPE_3D\n", 159 + chip_id->model, chip_id->revision); 160 + pr_warn("Request to force PPU flop reset ignored.\n"); 161 + return false; 162 + } 163 + 164 + pr_info("Force PPU flop reset for model: 0x%04x, revision: 0x%04x\n", 165 + chip_id->model, chip_id->revision); 166 + return true; 167 + } 168 + 169 + return false; 170 + } 171 + 172 + static const u32 image_data_size = PPU_IMAGE_STRIDE * PPU_IMAGE_YSIZE; 173 + static const u32 output_offset = ALIGN(image_data_size, 64); 174 + static const u32 shader_offset = ALIGN(output_offset + image_data_size, 64); 175 + static const u32 shader_size = PPU_FLOP_RESET_INSTR_DWORD_COUNT * sizeof(u32); 176 + static const u32 shader_register_count = 3; 177 + static const u32 buffer_size = shader_offset + shader_size; 178 + 179 + int etnaviv_flop_reset_ppu_init(struct etnaviv_drm_private *priv) 180 + { 181 + /* Get some space from the ring buffer to put the payload 182 + * (input and output image, and shader), we keep this buffer 183 + * for the whole life time the driver is bound 184 + */ 185 + priv->flop_reset_data_ppu = 186 + kzalloc(sizeof(*priv->flop_reset_data_ppu), GFP_KERNEL); 187 + 188 + if (!priv->flop_reset_data_ppu) 189 + return -ENOMEM; 190 + 191 + int ret = etnaviv_cmdbuf_init(priv->cmdbuf_suballoc, 192 + priv->flop_reset_data_ppu, buffer_size); 193 + if (ret) { 194 + kfree(priv->flop_reset_data_ppu); 195 + return ret; 196 + } 197 + 198 + void *buffer_base = priv->flop_reset_data_ppu->vaddr; 199 + u32 *input_data = (u32 *)buffer_base; 200 + u8 *shader_data = (u8 *)buffer_base + shader_offset; 201 + 202 + etnaviv_flop_reset_ppu_fill_input(input_data, image_data_size); 203 + etnaviv_flop_reset_ppu_set_shader(shader_data); 204 + 205 + return 0; 206 + } 207 + 208 + void etnaviv_flop_reset_ppu_run(struct etnaviv_gpu *gpu) 209 + { 210 + struct etnaviv_drm_private *priv = gpu->drm->dev_private; 211 + 212 + if (!priv->flop_reset_data_ppu) { 213 + dev_err(gpu->dev, 214 + "Oops: Flop reset data was not initialized, skipping\n"); 215 + return; 216 + } 217 + 218 + u32 buffer_base = etnaviv_cmdbuf_get_va(priv->flop_reset_data_ppu, 219 + &gpu->mmu_context->cmdbuf_mapping); 220 + 221 + etnaviv_emit_flop_reset_state_ppu(&gpu->buffer, buffer_base, 0, 222 + output_offset, shader_offset, 223 + shader_size, shader_register_count); 224 + }
+21
drivers/gpu/drm/etnaviv/etnaviv_flop_reset.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 2 + * 3 + * Copyright (C) 2025 Etnaviv Project 4 + */ 5 + 6 + #ifndef _ETNAVIV_FLOP_RESET_H_ 7 + #define _ETNAVIV_FLOP_RESET_H_ 8 + 9 + #include <linux/types.h> 10 + 11 + struct etnaviv_chip_identity; 12 + struct etnaviv_drm_private; 13 + struct etnaviv_gpu; 14 + 15 + bool etnaviv_flop_reset_ppu_require(const struct etnaviv_chip_identity *chip_id); 16 + 17 + int etnaviv_flop_reset_ppu_init(struct etnaviv_drm_private *priv); 18 + 19 + void etnaviv_flop_reset_ppu_run(struct etnaviv_gpu *gpu); 20 + 21 + #endif
+11
drivers/gpu/drm/etnaviv/etnaviv_gpu.c
··· 20 20 21 21 #include "etnaviv_cmdbuf.h" 22 22 #include "etnaviv_dump.h" 23 + #include "etnaviv_flop_reset.h" 23 24 #include "etnaviv_gpu.h" 24 25 #include "etnaviv_gem.h" 25 26 #include "etnaviv_mmu.h" ··· 838 837 dev_err(gpu->dev, "Unknown GPU model\n"); 839 838 ret = -ENXIO; 840 839 goto fail; 840 + } 841 + 842 + if (etnaviv_flop_reset_ppu_require(&gpu->identity) && 843 + !priv->flop_reset_data_ppu) { 844 + ret = etnaviv_flop_reset_ppu_init(priv); 845 + if (ret) { 846 + dev_err(gpu->dev, 847 + "Unable to initialize PPU flop reset data\n"); 848 + goto fail; 849 + } 841 850 } 842 851 843 852 if (gpu->identity.nn_core_count > 0)
+95
drivers/gpu/drm/etnaviv/state_3d.xml.h
··· 4 4 5 5 /* This is a cut-down version of the state_3d.xml.h file */ 6 6 7 + #define VIVS_CL_CONFIG 0x00000900 8 + #define VIVS_CL_CONFIG_DIMENSIONS__MASK 0x00000003 9 + #define VIVS_CL_CONFIG_DIMENSIONS__SHIFT 0 10 + #define VIVS_CL_CONFIG_DIMENSIONS(x) (((x) << VIVS_CL_CONFIG_DIMENSIONS__SHIFT) & VIVS_CL_CONFIG_DIMENSIONS__MASK) 11 + #define VIVS_CL_CONFIG_TRAVERSE_ORDER__MASK 0x00000070 12 + #define VIVS_CL_CONFIG_TRAVERSE_ORDER__SHIFT 4 13 + #define VIVS_CL_CONFIG_TRAVERSE_ORDER(x) (((x) << VIVS_CL_CONFIG_TRAVERSE_ORDER__SHIFT) & VIVS_CL_CONFIG_TRAVERSE_ORDER__MASK) 14 + #define VIVS_CL_CONFIG_ENABLE_SWATH_X 0x00000100 15 + #define VIVS_CL_CONFIG_ENABLE_SWATH_Y 0x00000200 16 + #define VIVS_CL_CONFIG_ENABLE_SWATH_Z 0x00000400 17 + #define VIVS_CL_CONFIG_SWATH_SIZE_X__MASK 0x0000f000 18 + #define VIVS_CL_CONFIG_SWATH_SIZE_X__SHIFT 12 19 + #define VIVS_CL_CONFIG_SWATH_SIZE_X(x) (((x) << VIVS_CL_CONFIG_SWATH_SIZE_X__SHIFT) & VIVS_CL_CONFIG_SWATH_SIZE_X__MASK) 20 + #define VIVS_CL_CONFIG_SWATH_SIZE_Y__MASK 0x000f0000 21 + #define VIVS_CL_CONFIG_SWATH_SIZE_Y__SHIFT 16 22 + #define VIVS_CL_CONFIG_SWATH_SIZE_Y(x) (((x) << VIVS_CL_CONFIG_SWATH_SIZE_Y__SHIFT) & VIVS_CL_CONFIG_SWATH_SIZE_Y__MASK) 23 + #define VIVS_CL_CONFIG_SWATH_SIZE_Z__MASK 0x00f00000 24 + #define VIVS_CL_CONFIG_SWATH_SIZE_Z__SHIFT 20 25 + #define VIVS_CL_CONFIG_SWATH_SIZE_Z(x) (((x) << VIVS_CL_CONFIG_SWATH_SIZE_Z__SHIFT) & VIVS_CL_CONFIG_SWATH_SIZE_Z__MASK) 26 + 27 + #define VIVS_CL_CONFIG_DIMENSIONS__MASK 0x00000003 28 + #define VIVS_CL_CONFIG_DIMENSIONS__SHIFT 0 29 + #define VIVS_CL_CONFIG_DIMENSIONS(x) (((x) << VIVS_CL_CONFIG_DIMENSIONS__SHIFT) & VIVS_CL_CONFIG_DIMENSIONS__MASK) 30 + 31 + #define VIVS_CL_CONFIG_VALUE_ORDER__MASK 0x07000000 32 + #define VIVS_CL_CONFIG_VALUE_ORDER__SHIFT 24 33 + #define VIVS_CL_CONFIG_VALUE_ORDER(x) (((x) << VIVS_CL_CONFIG_VALUE_ORDER__SHIFT) & VIVS_CL_CONFIG_VALUE_ORDER__MASK) 34 + 35 + #define VIVS_CL_GLOBAL_WORK_OFFSET_X 0x0000092c 36 + #define VIVS_CL_GLOBAL_WORK_OFFSET_Y 0x00000934 37 + #define VIVS_CL_GLOBAL_WORK_OFFSET_Z 0x0000093c 38 + 39 + #define VIVS_CL_KICKER 0x00000920 40 + #define VIVS_CL_THREAD_ALLOCATION 0x0000091c 41 + #define VIVS_CL_UNK00924 0x00000924 42 + 43 + #define VIVS_CL_WORKGROUP_COUNT_X 0x00000940 44 + #define VIVS_CL_WORKGROUP_COUNT_Y 0x00000944 45 + #define VIVS_CL_WORKGROUP_COUNT_Z 0x00000948 46 + #define VIVS_CL_WORKGROUP_SIZE_X 0x0000094c 47 + #define VIVS_CL_WORKGROUP_SIZE_Y 0x00000950 48 + #define VIVS_CL_WORKGROUP_SIZE_Z 0x00000954 49 + 50 + #define VIVS_CL_GLOBAL_SCALE_X 0x00000958 51 + #define VIVS_CL_GLOBAL_SCALE_Y 0x0000095c 52 + #define VIVS_CL_GLOBAL_SCALE_Z 0x00000960 53 + 54 + #define VIVS_PA_VS_OUTPUT_COUNT 0x00000aa8 55 + #define VIVS_PS_CONTROL_EXT 0x00001030 56 + #define VIVS_PS_ICACHE_COUNT 0x00001094 57 + #define VIVS_PS_ICACHE_PREFETCH 0x00001048 58 + 59 + #define VIVS_PS_INPUT_COUNT 0x00001008 60 + #define VIVS_PS_INPUT_COUNT_COUNT__MASK 0x0000001f 61 + #define VIVS_PS_INPUT_COUNT_COUNT__SHIFT 0 62 + #define VIVS_PS_INPUT_COUNT_COUNT(x) (((x) << VIVS_PS_INPUT_COUNT_COUNT__SHIFT) & VIVS_PS_INPUT_COUNT_COUNT__MASK) 63 + 64 + #define VIVS_PS_NEWRANGE_LOW 0x0000087c 65 + #define VIVS_PS_NEWRANGE_HIGH 0x00001090 66 + #define VIVS_PS_SAMPLER_BASE 0x00001058 67 + 68 + #define VIVS_PS_UNIFORM_BASE 0x00001024 69 + #define VIVS_PS_INST_ADDR 0x00001028 70 + 71 + #define VIVS_PS_TEMP_REGISTER_CONTROL 0x0000100c 72 + #define VIVS_PS_TEMP_REGISTER_CONTROL_NUM_TEMPS__MASK 0x0000003f 73 + #define VIVS_PS_TEMP_REGISTER_CONTROL_NUM_TEMPS__SHIFT 0 74 + #define VIVS_PS_TEMP_REGISTER_CONTROL_NUM_TEMPS(x) (((x) << VIVS_PS_TEMP_REGISTER_CONTROL_NUM_TEMPS__SHIFT) & VIVS_PS_TEMP_REGISTER_CONTROL_NUM_TEMPS__MASK) 75 + 76 + #define VIVS_PS_VARYING_NUM_COMPONENTS(i0) (0x00001080 + 0x4*(i0)) 77 + #define VIVS_PS_VARYING_NUM_COMPONENTS__ESIZE 0x00000004 78 + #define VIVS_PS_VARYING_NUM_COMPONENTS__LEN 0x00000004 79 + 80 + #define VIVS_SH_CONFIG 0x00015600 81 + #define VIVS_SH_CONFIG_RTNE_ROUNDING 0x00000002 82 + 83 + #define VIVS_SH_HALTI5_UNIFORMS(i0) (0x00036000 + 0x4*(i0)) 84 + #define VIVS_SH_HALTI5_UNIFORMS__ESIZE 0x00000004 85 + #define VIVS_SH_HALTI5_UNIFORMS__LEN 0x00000800 86 + 87 + #define VIVS_VS_HALTI5_UNK008A0 0x000008a0 88 + #define VIVS_VS_HALTI5_UNK008A0_A__MASK 0x0000003f 89 + #define VIVS_VS_HALTI5_UNK008A0_A__SHIFT 0 90 + #define VIVS_VS_HALTI5_UNK008A0_A(x) (((x) << VIVS_VS_HALTI5_UNK008A0_A__SHIFT) & VIVS_VS_HALTI5_UNK008A0_A__MASK) 91 + 92 + #define VIVS_VS_ICACHE_CONTROL 0x00000868 93 + #define VIVS_VS_ICACHE_CONTROL_ENABLE 0x00000001 94 + 95 + #define VIVS_VS_ICACHE_INVALIDATE 0x000008b0 96 + 97 + #define VIVS_VS_OUTPUT_COUNT 0x00000804 98 + #define VIVS_VS_OUTPUT_COUNT_COUNT__MASK 0x000000ff 99 + #define VIVS_VS_OUTPUT_COUNT_COUNT__SHIFT 0 100 + #define VIVS_VS_OUTPUT_COUNT_COUNT(x) (((x) << VIVS_VS_OUTPUT_COUNT_COUNT__SHIFT) & VIVS_VS_OUTPUT_COUNT_COUNT__MASK) 101 + 7 102 #define VIVS_TS_FLUSH_CACHE 0x00001650 8 103 #define VIVS_TS_FLUSH_CACHE_FLUSH 0x00000001 9 104
+1
drivers/gpu/drm/i915/display/intel_display_types.h
··· 34 34 #include <drm/display/drm_dp_tunnel.h> 35 35 #include <drm/display/drm_dsc.h> 36 36 #include <drm/drm_atomic.h> 37 + #include <drm/drm_colorop.h> 37 38 #include <drm/drm_crtc.h> 38 39 #include <drm/drm_encoder.h> 39 40 #include <drm/drm_framebuffer.h>
+3 -4
drivers/gpu/drm/meson/meson_encoder_cvbs.c
··· 33 33 struct meson_encoder_cvbs { 34 34 struct drm_encoder encoder; 35 35 struct drm_bridge bridge; 36 - struct drm_bridge *next_bridge; 37 36 struct meson_drm *priv; 38 37 }; 39 38 ··· 88 89 struct meson_encoder_cvbs *meson_encoder_cvbs = 89 90 bridge_to_meson_encoder_cvbs(bridge); 90 91 91 - return drm_bridge_attach(encoder, meson_encoder_cvbs->next_bridge, 92 + return drm_bridge_attach(encoder, meson_encoder_cvbs->bridge.next_bridge, 92 93 &meson_encoder_cvbs->bridge, flags); 93 94 } 94 95 ··· 240 241 return 0; 241 242 } 242 243 243 - meson_encoder_cvbs->next_bridge = of_drm_find_bridge(remote); 244 + meson_encoder_cvbs->bridge.next_bridge = of_drm_find_and_get_bridge(remote); 244 245 of_node_put(remote); 245 - if (!meson_encoder_cvbs->next_bridge) 246 + if (!meson_encoder_cvbs->bridge.next_bridge) 246 247 return dev_err_probe(priv->dev, -EPROBE_DEFER, 247 248 "Failed to find CVBS Connector bridge\n"); 248 249
+3 -4
drivers/gpu/drm/meson/meson_encoder_dsi.c
··· 25 25 struct meson_encoder_dsi { 26 26 struct drm_encoder encoder; 27 27 struct drm_bridge bridge; 28 - struct drm_bridge *next_bridge; 29 28 struct meson_drm *priv; 30 29 }; 31 30 ··· 37 38 { 38 39 struct meson_encoder_dsi *encoder_dsi = bridge_to_meson_encoder_dsi(bridge); 39 40 40 - return drm_bridge_attach(encoder, encoder_dsi->next_bridge, 41 + return drm_bridge_attach(encoder, encoder_dsi->bridge.next_bridge, 41 42 &encoder_dsi->bridge, flags); 42 43 } 43 44 ··· 119 120 return 0; 120 121 } 121 122 122 - meson_encoder_dsi->next_bridge = of_drm_find_bridge(remote); 123 - if (!meson_encoder_dsi->next_bridge) 123 + meson_encoder_dsi->bridge.next_bridge = of_drm_find_and_get_bridge(remote); 124 + if (!meson_encoder_dsi->bridge.next_bridge) 124 125 return dev_err_probe(priv->dev, -EPROBE_DEFER, 125 126 "Failed to find DSI transceiver bridge\n"); 126 127
+5 -5
drivers/gpu/drm/meson/meson_encoder_hdmi.c
··· 38 38 struct meson_encoder_hdmi { 39 39 struct drm_encoder encoder; 40 40 struct drm_bridge bridge; 41 - struct drm_bridge *next_bridge; 42 41 struct drm_connector *connector; 43 42 struct meson_drm *priv; 44 43 unsigned long output_bus_fmt; ··· 53 54 { 54 55 struct meson_encoder_hdmi *encoder_hdmi = bridge_to_meson_encoder_hdmi(bridge); 55 56 56 - return drm_bridge_attach(encoder, encoder_hdmi->next_bridge, 57 + return drm_bridge_attach(encoder, encoder_hdmi->bridge.next_bridge, 57 58 &encoder_hdmi->bridge, flags); 58 59 } 59 60 ··· 322 323 } 323 324 324 325 static void meson_encoder_hdmi_hpd_notify(struct drm_bridge *bridge, 326 + struct drm_connector *connector, 325 327 enum drm_connector_status status) 326 328 { 327 329 struct meson_encoder_hdmi *encoder_hdmi = bridge_to_meson_encoder_hdmi(bridge); ··· 334 334 const struct drm_edid *drm_edid; 335 335 const struct edid *edid; 336 336 337 - drm_edid = drm_bridge_edid_read(encoder_hdmi->next_bridge, 337 + drm_edid = drm_bridge_edid_read(encoder_hdmi->bridge.next_bridge, 338 338 encoder_hdmi->connector); 339 339 if (!drm_edid) 340 340 return; ··· 390 390 return 0; 391 391 } 392 392 393 - meson_encoder_hdmi->next_bridge = of_drm_find_bridge(remote); 394 - if (!meson_encoder_hdmi->next_bridge) { 393 + meson_encoder_hdmi->bridge.next_bridge = of_drm_find_and_get_bridge(remote); 394 + if (!meson_encoder_hdmi->bridge.next_bridge) { 395 395 ret = dev_err_probe(priv->dev, -EPROBE_DEFER, 396 396 "Failed to find HDMI transceiver bridge\n"); 397 397 goto err_put_node;
+2 -2
drivers/gpu/drm/meson/meson_venc.c
··· 868 868 DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_NVSYNC)) 869 869 return MODE_BAD; 870 870 871 - if (mode->hdisplay < 400 || mode->hdisplay > 1920) 871 + if (mode->hdisplay < 400 || mode->hdisplay > 3840) 872 872 return MODE_BAD_HVALUE; 873 873 874 - if (mode->vdisplay < 480 || mode->vdisplay > 1920) 874 + if (mode->vdisplay < 480 || mode->vdisplay > 2160) 875 875 return MODE_BAD_VVALUE; 876 876 877 877 return MODE_OK;
+2 -1
drivers/gpu/drm/msm/dp/dp_display.c
··· 1783 1783 } 1784 1784 1785 1785 void msm_dp_bridge_hpd_notify(struct drm_bridge *bridge, 1786 - enum drm_connector_status status) 1786 + struct drm_connector *connector, 1787 + enum drm_connector_status status) 1787 1788 { 1788 1789 struct msm_dp_bridge *msm_dp_bridge = to_dp_bridge(bridge); 1789 1790 struct msm_dp *msm_dp_display = msm_dp_bridge->msm_dp_display;
+2 -1
drivers/gpu/drm/msm/dp/dp_drm.h
··· 40 40 void msm_dp_bridge_hpd_enable(struct drm_bridge *bridge); 41 41 void msm_dp_bridge_hpd_disable(struct drm_bridge *bridge); 42 42 void msm_dp_bridge_hpd_notify(struct drm_bridge *bridge, 43 - enum drm_connector_status status); 43 + struct drm_connector *connector, 44 + enum drm_connector_status status); 44 45 45 46 #endif /* _DP_DRM_H_ */
+1
drivers/gpu/drm/omapdrm/dss/hdmi4.c
··· 428 428 } 429 429 430 430 static void hdmi4_bridge_hpd_notify(struct drm_bridge *bridge, 431 + struct drm_connector *connector, 431 432 enum drm_connector_status status) 432 433 { 433 434 struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge);
+7
drivers/gpu/drm/panel/panel-edp.c
··· 1730 1730 .prepare_to_enable = 100, 1731 1731 }; 1732 1732 1733 + static const struct panel_delay delay_200_500_p2e200 = { 1734 + .hpd_absent = 200, 1735 + .unprepare = 500, 1736 + .prepare_to_enable = 200, 1737 + }; 1738 + 1733 1739 static const struct panel_delay delay_200_500_e50 = { 1734 1740 .hpd_absent = 200, 1735 1741 .unprepare = 500, ··· 1983 1977 EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b56, &delay_200_500_e80, "NT140FHM-N47"), 1984 1978 EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b66, &delay_200_500_e80, "NE140WUM-N6G"), 1985 1979 EDP_PANEL_ENTRY('B', 'O', 'E', 0x0c20, &delay_200_500_e80, "NT140FHM-N47"), 1980 + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0c26, &delay_200_500_p2e200, "NV140WUM-T08"), 1986 1981 EDP_PANEL_ENTRY('B', 'O', 'E', 0x0c93, &delay_200_500_e200, "Unknown"), 1987 1982 EDP_PANEL_ENTRY('B', 'O', 'E', 0x0cb6, &delay_200_500_e200, "NT116WHM-N44"), 1988 1983 EDP_PANEL_ENTRY('B', 'O', 'E', 0x0cf2, &delay_200_500_e200, "NV156FHM-N4S"),
+3 -2
drivers/gpu/drm/panfrost/panfrost_drv.c
··· 1077 1077 .pm_domain_names = NULL, 1078 1078 }; 1079 1079 1080 - static const struct panfrost_compatible allwinner_h616_data = { 1080 + static const struct panfrost_compatible default_pm_rt_data = { 1081 1081 .num_supplies = ARRAY_SIZE(default_supplies) - 1, 1082 1082 .supply_names = default_supplies, 1083 1083 .num_pm_domains = 1, ··· 1157 1157 .data = &amlogic_data, }, 1158 1158 { .compatible = "amlogic,meson-g12a-mali", 1159 1159 .data = &amlogic_data, }, 1160 + { .compatible = "renesas,r9a09g047-mali", .data = &default_pm_rt_data }, 1160 1161 { .compatible = "arm,mali-t604", .data = &default_data, }, 1161 1162 { .compatible = "arm,mali-t624", .data = &default_data, }, 1162 1163 { .compatible = "arm,mali-t628", .data = &default_data, }, ··· 1175 1174 { .compatible = "mediatek,mt8188-mali", .data = &mediatek_mt8188_data }, 1176 1175 { .compatible = "mediatek,mt8192-mali", .data = &mediatek_mt8192_data }, 1177 1176 { .compatible = "mediatek,mt8370-mali", .data = &mediatek_mt8370_data }, 1178 - { .compatible = "allwinner,sun50i-h616-mali", .data = &allwinner_h616_data }, 1177 + { .compatible = "allwinner,sun50i-h616-mali", .data = &default_pm_rt_data }, 1179 1178 {} 1180 1179 }; 1181 1180 MODULE_DEVICE_TABLE(of, dt_match);
+96 -8
drivers/gpu/drm/panthor/panthor_mmu.c
··· 533 533 return status; 534 534 } 535 535 536 - static u64 pack_region_range(struct panthor_device *ptdev, u64 region_start, u64 size) 536 + static u64 pack_region_range(struct panthor_device *ptdev, u64 *region_start, u64 *size) 537 537 { 538 538 u8 region_width; 539 - u64 region_end = region_start + size; 539 + u64 region_end = *region_start + *size; 540 540 541 - if (drm_WARN_ON_ONCE(&ptdev->base, !size)) 541 + if (drm_WARN_ON_ONCE(&ptdev->base, !*size)) 542 542 return 0; 543 543 544 544 /* ··· 549 549 * change, the desired region starts with this bit (and subsequent bits) 550 550 * zeroed and ends with the bit (and subsequent bits) set to one. 551 551 */ 552 - region_width = max(fls64(region_start ^ (region_end - 1)), 552 + region_width = max(fls64(*region_start ^ (region_end - 1)), 553 553 const_ilog2(AS_LOCK_REGION_MIN_SIZE)) - 1; 554 554 555 555 /* 556 556 * Mask off the low bits of region_start (which would be ignored by 557 557 * the hardware anyway) 558 558 */ 559 - region_start &= GENMASK_ULL(63, region_width); 559 + *region_start &= GENMASK_ULL(63, region_width); 560 + *size = 1ull << (region_width + 1); 560 561 561 - return region_width | region_start; 562 + return region_width | *region_start; 562 563 } 563 564 564 565 static int panthor_mmu_as_enable(struct panthor_device *ptdev, u32 as_nr, ··· 1505 1504 1506 1505 vm->destroyed = true; 1507 1506 1507 + /* Tell scheduler to stop all GPU work related to this VM */ 1508 + if (refcount_read(&vm->as.active_cnt) > 0) 1509 + panthor_sched_prepare_for_vm_destruction(vm->ptdev); 1510 + 1508 1511 mutex_lock(&vm->heaps.lock); 1509 1512 panthor_heap_pool_destroy(vm->heaps.pool); 1510 1513 vm->heaps.pool = NULL; ··· 1642 1637 struct panthor_device *ptdev = vm->ptdev; 1643 1638 int ret = 0; 1644 1639 1640 + /* sm_step_remap() can call panthor_vm_lock_region() to account for 1641 + * the wider unmap needed when doing a partial huge page unamp. We 1642 + * need to ignore the lock if it's already part of the locked region. 1643 + */ 1644 + if (start >= vm->locked_region.start && 1645 + start + size <= vm->locked_region.start + vm->locked_region.size) 1646 + return 0; 1647 + 1645 1648 mutex_lock(&ptdev->mmu->as.slots_lock); 1646 - drm_WARN_ON(&ptdev->base, vm->locked_region.start || vm->locked_region.size); 1647 1649 if (vm->as.id >= 0 && size) { 1648 1650 /* Lock the region that needs to be updated */ 1649 1651 gpu_write64(ptdev, AS_LOCKADDR(vm->as.id), 1650 - pack_region_range(ptdev, start, size)); 1652 + pack_region_range(ptdev, &start, &size)); 1651 1653 1652 1654 /* If the lock succeeded, update the locked_region info. */ 1653 1655 ret = as_send_cmd_and_wait(ptdev, vm->as.id, AS_COMMAND_LOCK); ··· 2114 2102 return 0; 2115 2103 } 2116 2104 2105 + static bool 2106 + iova_mapped_as_huge_page(struct drm_gpuva_op_map *op, u64 addr) 2107 + { 2108 + const struct page *pg; 2109 + pgoff_t bo_offset; 2110 + 2111 + bo_offset = addr - op->va.addr + op->gem.offset; 2112 + pg = to_panthor_bo(op->gem.obj)->base.pages[bo_offset >> PAGE_SHIFT]; 2113 + 2114 + return folio_size(page_folio(pg)) >= SZ_2M; 2115 + } 2116 + 2117 + static void 2118 + unmap_hugepage_align(const struct drm_gpuva_op_remap *op, 2119 + u64 *unmap_start, u64 *unmap_range) 2120 + { 2121 + u64 aligned_unmap_start, aligned_unmap_end, unmap_end; 2122 + 2123 + unmap_end = *unmap_start + *unmap_range; 2124 + aligned_unmap_start = ALIGN_DOWN(*unmap_start, SZ_2M); 2125 + aligned_unmap_end = ALIGN(unmap_end, SZ_2M); 2126 + 2127 + /* If we're dealing with a huge page, make sure the unmap region is 2128 + * aligned on the start of the page. 2129 + */ 2130 + if (op->prev && aligned_unmap_start < *unmap_start && 2131 + op->prev->va.addr <= aligned_unmap_start && 2132 + iova_mapped_as_huge_page(op->prev, *unmap_start)) { 2133 + *unmap_range += *unmap_start - aligned_unmap_start; 2134 + *unmap_start = aligned_unmap_start; 2135 + } 2136 + 2137 + /* If we're dealing with a huge page, make sure the unmap region is 2138 + * aligned on the end of the page. 2139 + */ 2140 + if (op->next && aligned_unmap_end > unmap_end && 2141 + op->next->va.addr + op->next->va.range >= aligned_unmap_end && 2142 + iova_mapped_as_huge_page(op->next, unmap_end - 1)) { 2143 + *unmap_range += aligned_unmap_end - unmap_end; 2144 + } 2145 + } 2146 + 2117 2147 static int panthor_gpuva_sm_step_remap(struct drm_gpuva_op *op, 2118 2148 void *priv) 2119 2149 { ··· 2164 2110 struct panthor_vm_op_ctx *op_ctx = vm->op_ctx; 2165 2111 struct panthor_vma *prev_vma = NULL, *next_vma = NULL; 2166 2112 u64 unmap_start, unmap_range; 2113 + int ret; 2167 2114 2168 2115 drm_gpuva_op_remap_to_unmap_range(&op->remap, &unmap_start, &unmap_range); 2116 + 2117 + /* 2118 + * ARM IOMMU page table management code disallows partial unmaps of huge pages, 2119 + * so when a partial unmap is requested, we must first unmap the entire huge 2120 + * page and then remap the difference between the huge page minus the requested 2121 + * unmap region. Calculating the right start address and range for the expanded 2122 + * unmap operation is the responsibility of the following function. 2123 + */ 2124 + unmap_hugepage_align(&op->remap, &unmap_start, &unmap_range); 2125 + 2126 + /* If the range changed, we might have to lock a wider region to guarantee 2127 + * atomicity. panthor_vm_lock_region() bails out early if the new region 2128 + * is already part of the locked region, so no need to do this check here. 2129 + */ 2130 + panthor_vm_lock_region(vm, unmap_start, unmap_range); 2169 2131 panthor_vm_unmap_pages(vm, unmap_start, unmap_range); 2170 2132 2171 2133 if (op->remap.prev) { 2134 + struct panthor_gem_object *bo = to_panthor_bo(op->remap.prev->gem.obj); 2135 + u64 offset = op->remap.prev->gem.offset + unmap_start - op->remap.prev->va.addr; 2136 + u64 size = op->remap.prev->va.addr + op->remap.prev->va.range - unmap_start; 2137 + 2138 + ret = panthor_vm_map_pages(vm, unmap_start, flags_to_prot(unmap_vma->flags), 2139 + bo->base.sgt, offset, size); 2140 + if (ret) 2141 + return ret; 2142 + 2172 2143 prev_vma = panthor_vm_op_ctx_get_vma(op_ctx); 2173 2144 panthor_vma_init(prev_vma, unmap_vma->flags); 2174 2145 } 2175 2146 2176 2147 if (op->remap.next) { 2148 + struct panthor_gem_object *bo = to_panthor_bo(op->remap.next->gem.obj); 2149 + u64 addr = op->remap.next->va.addr; 2150 + u64 size = unmap_start + unmap_range - op->remap.next->va.addr; 2151 + 2152 + ret = panthor_vm_map_pages(vm, addr, flags_to_prot(unmap_vma->flags), 2153 + bo->base.sgt, op->remap.next->gem.offset, size); 2154 + if (ret) 2155 + return ret; 2156 + 2177 2157 next_vma = panthor_vm_op_ctx_get_vma(op_ctx); 2178 2158 panthor_vma_init(next_vma, unmap_vma->flags); 2179 2159 }
+14
drivers/gpu/drm/panthor/panthor_sched.c
··· 2786 2786 sched_queue_delayed_work(ptdev->scheduler, tick, 0); 2787 2787 } 2788 2788 2789 + void panthor_sched_prepare_for_vm_destruction(struct panthor_device *ptdev) 2790 + { 2791 + /* FW can write out internal state, like the heap context, during CSG 2792 + * suspend. It is therefore important that the scheduler has fully 2793 + * evicted any pending and related groups before VM destruction can 2794 + * safely continue. Failure to do so can lead to GPU page faults. 2795 + * A controlled termination of a Panthor instance involves destroying 2796 + * the group(s) before the VM. This means any relevant group eviction 2797 + * has already been initiated by this point, and we just need to 2798 + * ensure that any pending tick_work() has been completed. 2799 + */ 2800 + flush_work(&ptdev->scheduler->tick_work.work); 2801 + } 2802 + 2789 2803 void panthor_sched_resume(struct panthor_device *ptdev) 2790 2804 { 2791 2805 /* Force a tick to re-evaluate after a resume. */
+1
drivers/gpu/drm/panthor/panthor_sched.h
··· 50 50 void panthor_sched_resume(struct panthor_device *ptdev); 51 51 52 52 void panthor_sched_report_mmu_fault(struct panthor_device *ptdev); 53 + void panthor_sched_prepare_for_vm_destruction(struct panthor_device *ptdev); 53 54 void panthor_sched_report_fw_events(struct panthor_device *ptdev, u32 events); 54 55 55 56 void panthor_fdinfo_gather_group_samples(struct panthor_file *pfile);
+1
drivers/gpu/drm/pl111/pl111_nomadik.c
··· 4 4 #include <linux/mfd/syscon.h> 5 5 #include <linux/bitops.h> 6 6 #include <linux/module.h> 7 + #include <drm/drm_print.h> 7 8 #include "pl111_nomadik.h" 8 9 9 10 #define PMU_CTRL_OFFSET 0x0000
+1
drivers/gpu/drm/rockchip/Kconfig
··· 15 15 select DRM_DW_HDMI_QP if ROCKCHIP_DW_HDMI_QP 16 16 select DRM_DW_MIPI_DSI if ROCKCHIP_DW_MIPI_DSI 17 17 select DRM_DW_MIPI_DSI2 if ROCKCHIP_DW_MIPI_DSI2 18 + select DRM_INNO_HDMI if ROCKCHIP_INNO_HDMI 18 19 select GENERIC_PHY if ROCKCHIP_DW_MIPI_DSI 19 20 select GENERIC_PHY_MIPI_DPHY if ROCKCHIP_DW_MIPI_DSI 20 21 select SND_SOC_HDMI_CODEC if ROCKCHIP_CDN_DP && SND_SOC
+1 -1
drivers/gpu/drm/rockchip/Makefile
··· 15 15 rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi-rockchip.o 16 16 rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI2) += dw-mipi-dsi2-rockchip.o 17 17 rockchipdrm-$(CONFIG_ROCKCHIP_DW_DP) += dw_dp-rockchip.o 18 - rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o 18 + rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi-rockchip.o 19 19 rockchipdrm-$(CONFIG_ROCKCHIP_LVDS) += rockchip_lvds.o 20 20 rockchipdrm-$(CONFIG_ROCKCHIP_RGB) += rockchip_rgb.o 21 21 rockchipdrm-$(CONFIG_ROCKCHIP_RK3066_HDMI) += rk3066_hdmi.o
+189
drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Copyright (C) Rockchip Electronics Co., Ltd. 4 + * Zheng Yang <zhengyang@rock-chips.com> 5 + * Andy Yan <andy.yan@rock-chips.com> 6 + */ 7 + #include <linux/err.h> 8 + #include <linux/hw_bitfield.h> 9 + #include <linux/mfd/syscon.h> 10 + #include <linux/mod_devicetable.h> 11 + #include <linux/module.h> 12 + #include <linux/platform_device.h> 13 + #include <linux/regmap.h> 14 + 15 + #include <drm/bridge/inno_hdmi.h> 16 + #include <drm/drm_bridge_connector.h> 17 + #include <drm/drm_of.h> 18 + 19 + #include "rockchip_drm_drv.h" 20 + 21 + #define HIWORD_UPDATE(val, mask) ((val) | (mask) << 16) 22 + 23 + #define RK3036_GRF_SOC_CON2 0x148 24 + #define RK3036_HDMI_PHSYNC BIT(4) 25 + #define RK3036_HDMI_PVSYNC BIT(5) 26 + 27 + enum inno_hdmi_dev_type { 28 + RK3036_HDMI, 29 + RK3128_HDMI, 30 + }; 31 + 32 + struct inno_hdmi_connector_state { 33 + struct drm_connector_state base; 34 + unsigned int colorimetry; 35 + }; 36 + 37 + struct rockchip_inno_hdmi { 38 + struct inno_hdmi *base; 39 + struct device *dev; 40 + struct regmap *grf; 41 + struct rockchip_encoder encoder; 42 + }; 43 + 44 + static struct inno_hdmi_phy_config rk3036_hdmi_phy_configs[] = { 45 + { 74250000, 0x3f, 0xbb }, 46 + { 165000000, 0x6f, 0xbb }, 47 + { ~0UL, 0x00, 0x00 } 48 + }; 49 + 50 + static struct inno_hdmi_phy_config rk3128_hdmi_phy_configs[] = { 51 + { 74250000, 0x3f, 0xaa }, 52 + { 165000000, 0x5f, 0xaa }, 53 + { ~0UL, 0x00, 0x00 } 54 + }; 55 + 56 + static void inno_hdmi_rk3036_enable(struct device *dev, struct drm_display_mode *mode) 57 + { 58 + struct rockchip_inno_hdmi *hdmi = dev_get_drvdata(dev); 59 + int value, psync; 60 + 61 + psync = mode->flags & DRM_MODE_FLAG_PHSYNC ? 1 : 0; 62 + value = FIELD_PREP_WM16(RK3036_HDMI_PHSYNC, psync); 63 + psync = mode->flags & DRM_MODE_FLAG_PVSYNC ? 1 : 0; 64 + value |= FIELD_PREP_WM16(RK3036_HDMI_PVSYNC, psync); 65 + regmap_write(hdmi->grf, RK3036_GRF_SOC_CON2, value); 66 + } 67 + 68 + static int inno_hdmi_encoder_atomic_check(struct drm_encoder *encoder, 69 + struct drm_crtc_state *crtc_state, 70 + struct drm_connector_state *conn_state) 71 + { 72 + struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); 73 + 74 + s->output_mode = ROCKCHIP_OUT_MODE_P888; 75 + s->output_type = DRM_MODE_CONNECTOR_HDMIA; 76 + 77 + return 0; 78 + } 79 + 80 + static const struct drm_encoder_helper_funcs inno_hdmi_rockchip_encoder_helper_funcs = { 81 + .atomic_check = inno_hdmi_encoder_atomic_check, 82 + }; 83 + 84 + static int inno_hdmi_rockchip_bind(struct device *dev, struct device *master, void *data) 85 + { 86 + struct drm_device *drm = data; 87 + struct drm_connector *connector; 88 + struct drm_encoder *encoder; 89 + struct rockchip_inno_hdmi *hdmi; 90 + const struct inno_hdmi_plat_data *plat_data; 91 + int ret; 92 + 93 + hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL); 94 + if (!hdmi) 95 + return -ENOMEM; 96 + 97 + hdmi->dev = dev; 98 + 99 + plat_data = of_device_get_match_data(hdmi->dev); 100 + if (!plat_data) 101 + return -EINVAL; 102 + 103 + if (of_device_is_compatible(dev->of_node, "rockchip,rk3036-inno-hdmi")) { 104 + hdmi->grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,grf"); 105 + if (IS_ERR(hdmi->grf)) 106 + return dev_err_probe(dev, 107 + PTR_ERR(hdmi->grf), "Unable to get rockchip,grf\n"); 108 + } 109 + 110 + encoder = &hdmi->encoder.encoder; 111 + encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node); 112 + 113 + /* 114 + * If we failed to find the CRTC(s) which this encoder is 115 + * supposed to be connected to, it's because the CRTC has 116 + * not been registered yet. Defer probing, and hope that 117 + * the required CRTC is added later. 118 + */ 119 + if (encoder->possible_crtcs == 0) 120 + return -EPROBE_DEFER; 121 + 122 + ret = drmm_encoder_init(drm, encoder, NULL, DRM_MODE_ENCODER_TMDS, NULL); 123 + if (ret) 124 + return ret; 125 + 126 + drm_encoder_helper_add(encoder, &inno_hdmi_rockchip_encoder_helper_funcs); 127 + 128 + dev_set_drvdata(dev, hdmi); 129 + 130 + hdmi->base = inno_hdmi_bind(dev, encoder, plat_data); 131 + 132 + connector = drm_bridge_connector_init(drm, encoder); 133 + if (IS_ERR(connector)) { 134 + ret = PTR_ERR(connector); 135 + dev_err(hdmi->dev, "failed to init bridge connector: %d\n", ret); 136 + return ret; 137 + } 138 + 139 + return drm_connector_attach_encoder(connector, encoder); 140 + } 141 + 142 + static const struct component_ops inno_hdmi_rockchip_ops = { 143 + .bind = inno_hdmi_rockchip_bind, 144 + }; 145 + 146 + static int inno_hdmi_rockchip_probe(struct platform_device *pdev) 147 + { 148 + return component_add(&pdev->dev, &inno_hdmi_rockchip_ops); 149 + } 150 + 151 + static void inno_hdmi_rockchip_remove(struct platform_device *pdev) 152 + { 153 + component_del(&pdev->dev, &inno_hdmi_rockchip_ops); 154 + } 155 + 156 + static const struct inno_hdmi_plat_ops rk3036_inno_hdmi_plat_ops = { 157 + .enable = inno_hdmi_rk3036_enable, 158 + }; 159 + 160 + static const struct inno_hdmi_plat_data rk3036_inno_hdmi_plat_data = { 161 + .ops = &rk3036_inno_hdmi_plat_ops, 162 + .phy_configs = rk3036_hdmi_phy_configs, 163 + .default_phy_config = &rk3036_hdmi_phy_configs[1], 164 + }; 165 + 166 + static const struct inno_hdmi_plat_data rk3128_inno_hdmi_plat_data = { 167 + .phy_configs = rk3128_hdmi_phy_configs, 168 + .default_phy_config = &rk3128_hdmi_phy_configs[1], 169 + }; 170 + 171 + static const struct of_device_id inno_hdmi_rockchip_dt_ids[] = { 172 + { .compatible = "rockchip,rk3036-inno-hdmi", 173 + .data = &rk3036_inno_hdmi_plat_data, 174 + }, 175 + { .compatible = "rockchip,rk3128-inno-hdmi", 176 + .data = &rk3128_inno_hdmi_plat_data, 177 + }, 178 + {}, 179 + }; 180 + MODULE_DEVICE_TABLE(of, inno_hdmi_rockchip_dt_ids); 181 + 182 + struct platform_driver inno_hdmi_driver = { 183 + .probe = inno_hdmi_rockchip_probe, 184 + .remove = inno_hdmi_rockchip_remove, 185 + .driver = { 186 + .name = "innohdmi-rockchip", 187 + .of_match_table = inno_hdmi_rockchip_dt_ids, 188 + }, 189 + };
+136 -368
drivers/gpu/drm/rockchip/inno_hdmi.c drivers/gpu/drm/bridge/inno-hdmi.c
··· 3 3 * Copyright (C) Rockchip Electronics Co., Ltd. 4 4 * Zheng Yang <zhengyang@rock-chips.com> 5 5 * Yakir Yang <ykk@rock-chips.com> 6 + * Andy Yan <andyshrk@163.com> 6 7 */ 7 8 8 9 #include <linux/irq.h> 9 10 #include <linux/clk.h> 10 11 #include <linux/delay.h> 11 12 #include <linux/err.h> 13 + #include <linux/i2c.h> 12 14 #include <linux/hdmi.h> 13 - #include <linux/hw_bitfield.h> 14 15 #include <linux/mfd/syscon.h> 15 16 #include <linux/mod_devicetable.h> 16 17 #include <linux/module.h> ··· 19 18 #include <linux/platform_device.h> 20 19 #include <linux/regmap.h> 21 20 21 + #include <drm/bridge/inno_hdmi.h> 22 22 #include <drm/drm_atomic.h> 23 23 #include <drm/drm_atomic_helper.h> 24 24 #include <drm/drm_edid.h> ··· 30 28 31 29 #include <drm/display/drm_hdmi_helper.h> 32 30 #include <drm/display/drm_hdmi_state_helper.h> 33 - 34 - #include "rockchip_drm_drv.h" 35 31 36 32 #define INNO_HDMI_MIN_TMDS_CLOCK 25000000U 37 33 ··· 384 384 #define HDMI_CEC_BUSFREETIME_H 0xdd 385 385 #define HDMI_CEC_LOGICADDR 0xde 386 386 387 - #define RK3036_GRF_SOC_CON2 0x148 388 - #define RK3036_HDMI_PHSYNC BIT(4) 389 - #define RK3036_HDMI_PVSYNC BIT(5) 390 - 391 - enum inno_hdmi_dev_type { 392 - RK3036_HDMI, 393 - RK3128_HDMI, 394 - }; 395 - 396 - struct inno_hdmi_phy_config { 397 - unsigned long pixelclock; 398 - u8 pre_emphasis; 399 - u8 voltage_level_control; 400 - }; 401 - 402 - struct inno_hdmi_variant { 403 - enum inno_hdmi_dev_type dev_type; 404 - struct inno_hdmi_phy_config *phy_configs; 405 - struct inno_hdmi_phy_config *default_phy_config; 406 - }; 407 - 408 387 struct inno_hdmi_i2c { 409 388 struct i2c_adapter adap; 410 389 ··· 396 417 397 418 struct inno_hdmi { 398 419 struct device *dev; 399 - 420 + struct drm_bridge bridge; 400 421 struct clk *pclk; 401 422 struct clk *refclk; 402 423 void __iomem *regs; 403 424 struct regmap *grf; 404 425 405 - struct drm_connector connector; 406 - struct rockchip_encoder encoder; 407 - 408 426 struct inno_hdmi_i2c *i2c; 409 427 struct i2c_adapter *ddc; 410 - 411 - const struct inno_hdmi_variant *variant; 428 + const struct inno_hdmi_plat_data *plat_data; 412 429 }; 413 - 414 - struct inno_hdmi_connector_state { 415 - struct drm_connector_state base; 416 - unsigned int colorimetry; 417 - }; 418 - 419 - static struct inno_hdmi *encoder_to_inno_hdmi(struct drm_encoder *encoder) 420 - { 421 - struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder); 422 - 423 - return container_of(rkencoder, struct inno_hdmi, encoder); 424 - } 425 - 426 - static struct inno_hdmi *connector_to_inno_hdmi(struct drm_connector *connector) 427 - { 428 - return container_of(connector, struct inno_hdmi, connector); 429 - } 430 - 431 - #define to_inno_hdmi_conn_state(conn_state) \ 432 - container_of_const(conn_state, struct inno_hdmi_connector_state, base) 433 430 434 431 enum { 435 432 CSC_RGB_0_255_TO_ITU601_16_235_8BIT, ··· 449 494 }, 450 495 }; 451 496 452 - static struct inno_hdmi_phy_config rk3036_hdmi_phy_configs[] = { 453 - { 74250000, 0x3f, 0xbb }, 454 - { 165000000, 0x6f, 0xbb }, 455 - { ~0UL, 0x00, 0x00 } 456 - }; 457 - 458 - static struct inno_hdmi_phy_config rk3128_hdmi_phy_configs[] = { 459 - { 74250000, 0x3f, 0xaa }, 460 - { 165000000, 0x5f, 0xaa }, 461 - { ~0UL, 0x00, 0x00 } 462 - }; 497 + static struct inno_hdmi *bridge_to_inno_hdmi(struct drm_bridge *bridge) 498 + { 499 + return container_of(bridge, struct inno_hdmi, bridge); 500 + } 463 501 464 502 static int inno_hdmi_find_phy_config(struct inno_hdmi *hdmi, 465 503 unsigned long pixelclk) 466 504 { 467 - const struct inno_hdmi_phy_config *phy_configs = 468 - hdmi->variant->phy_configs; 505 + const struct inno_hdmi_phy_config *phy_configs = hdmi->plat_data->phy_configs; 469 506 int i; 470 507 471 508 for (i = 0; phy_configs[i].pixelclock != ~0UL; i++) { ··· 529 582 int ret = inno_hdmi_find_phy_config(hdmi, mpixelclock); 530 583 531 584 if (ret < 0) { 532 - phy_config = hdmi->variant->default_phy_config; 585 + phy_config = hdmi->plat_data->default_phy_config; 533 586 DRM_DEV_ERROR(hdmi->dev, 534 587 "Using default phy configuration for TMDS rate %lu", 535 588 mpixelclock); 536 589 } else { 537 - phy_config = &hdmi->variant->phy_configs[ret]; 590 + phy_config = &hdmi->plat_data->phy_configs[ret]; 538 591 } 539 592 540 593 inno_hdmi_sys_power(hdmi, false); ··· 584 637 hdmi_modb(hdmi, HDMI_STATUS, m_MASK_INT_HOTPLUG, v_MASK_INT_HOTPLUG(1)); 585 638 } 586 639 587 - static int inno_hdmi_disable_frame(struct drm_connector *connector, 588 - enum hdmi_infoframe_type type) 640 + static int inno_hdmi_bridge_clear_infoframe(struct drm_bridge *bridge, 641 + enum hdmi_infoframe_type type) 589 642 { 590 - struct inno_hdmi *hdmi = connector_to_inno_hdmi(connector); 643 + struct inno_hdmi *hdmi = bridge_to_inno_hdmi(bridge); 591 644 592 645 if (type != HDMI_INFOFRAME_TYPE_AVI) { 593 - drm_err(connector->dev, 594 - "Unsupported infoframe type: %u\n", type); 646 + drm_err(bridge->dev, "Unsupported infoframe type: %u\n", type); 595 647 return 0; 596 648 } 597 649 ··· 599 653 return 0; 600 654 } 601 655 602 - static int inno_hdmi_upload_frame(struct drm_connector *connector, 603 - enum hdmi_infoframe_type type, 604 - const u8 *buffer, size_t len) 656 + static int inno_hdmi_bridge_write_infoframe(struct drm_bridge *bridge, 657 + enum hdmi_infoframe_type type, 658 + const u8 *buffer, size_t len) 605 659 { 606 - struct inno_hdmi *hdmi = connector_to_inno_hdmi(connector); 660 + struct inno_hdmi *hdmi = bridge_to_inno_hdmi(bridge); 607 661 ssize_t i; 608 662 609 663 if (type != HDMI_INFOFRAME_TYPE_AVI) { 610 - drm_err(connector->dev, 611 - "Unsupported infoframe type: %u\n", type); 664 + drm_err(bridge->dev, "Unsupported infoframe type: %u\n", type); 612 665 return 0; 613 666 } 614 667 615 - inno_hdmi_disable_frame(connector, type); 668 + inno_hdmi_bridge_clear_infoframe(bridge, type); 616 669 617 670 for (i = 0; i < len; i++) 618 671 hdmi_writeb(hdmi, HDMI_CONTROL_PACKET_ADDR + i, buffer[i]); ··· 619 674 return 0; 620 675 } 621 676 622 - static const struct drm_connector_hdmi_funcs inno_hdmi_hdmi_connector_funcs = { 623 - .clear_infoframe = inno_hdmi_disable_frame, 624 - .write_infoframe = inno_hdmi_upload_frame, 625 - }; 626 - 627 - static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi) 677 + static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi, 678 + struct drm_connector *connector, 679 + struct drm_display_mode *mode) 628 680 { 629 - struct drm_connector *connector = &hdmi->connector; 630 681 struct drm_connector_state *conn_state = connector->state; 631 - struct inno_hdmi_connector_state *inno_conn_state = 632 - to_inno_hdmi_conn_state(conn_state); 633 682 int c0_c2_change = 0; 634 683 int csc_enable = 0; 635 684 int csc_mode = 0; 636 685 int auto_csc = 0; 637 686 int value; 638 687 int i; 688 + int colorimetry; 689 + u8 vic = drm_match_cea_mode(mode); 690 + 691 + if (vic == 6 || vic == 7 || vic == 21 || vic == 22 || 692 + vic == 2 || vic == 3 || vic == 17 || vic == 18) 693 + colorimetry = HDMI_COLORIMETRY_ITU_601; 694 + else 695 + colorimetry = HDMI_COLORIMETRY_ITU_709; 696 + 639 697 640 698 /* Input video mode is SDR RGB24bit, data enable signal from external */ 641 699 hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL1, v_DE_EXTERNAL | ··· 668 720 return 0; 669 721 } 670 722 } else { 671 - if (inno_conn_state->colorimetry == HDMI_COLORIMETRY_ITU_601) { 723 + if (colorimetry == HDMI_COLORIMETRY_ITU_601) { 672 724 if (conn_state->hdmi.output_format == HDMI_COLORSPACE_YUV444) { 673 725 csc_mode = CSC_RGB_0_255_TO_ITU601_16_235_8BIT; 674 726 auto_csc = AUTO_CSC_DISABLE; ··· 686 738 } 687 739 688 740 for (i = 0; i < 24; i++) 689 - hdmi_writeb(hdmi, HDMI_VIDEO_CSC_COEF + i, 690 - coeff_csc[csc_mode][i]); 741 + hdmi_writeb(hdmi, HDMI_VIDEO_CSC_COEF + i, coeff_csc[csc_mode][i]); 691 742 692 743 value = v_SOF_DISABLE | csc_enable | v_COLOR_DEPTH_NOT_INDICATED(1); 693 744 hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL3, value); ··· 700 753 static int inno_hdmi_config_video_timing(struct inno_hdmi *hdmi, 701 754 struct drm_display_mode *mode) 702 755 { 703 - int value, psync; 756 + const struct inno_hdmi_plat_ops *plat_ops = hdmi->plat_data->ops; 757 + u32 value; 704 758 705 - if (hdmi->variant->dev_type == RK3036_HDMI) { 706 - psync = mode->flags & DRM_MODE_FLAG_PHSYNC ? 1 : 0; 707 - value = FIELD_PREP_WM16(RK3036_HDMI_PHSYNC, psync); 708 - psync = mode->flags & DRM_MODE_FLAG_PVSYNC ? 1 : 0; 709 - value |= FIELD_PREP_WM16(RK3036_HDMI_PVSYNC, psync); 710 - regmap_write(hdmi->grf, RK3036_GRF_SOC_CON2, value); 711 - } 759 + if (plat_ops && plat_ops->enable) 760 + plat_ops->enable(hdmi->dev, mode); 712 761 713 762 /* Set detail external video timing polarity and interlace mode */ 714 763 value = v_EXTERANL_VIDEO(1); ··· 753 810 return 0; 754 811 } 755 812 756 - static int inno_hdmi_setup(struct inno_hdmi *hdmi, 757 - struct drm_atomic_state *state) 813 + static int inno_hdmi_setup(struct inno_hdmi *hdmi, struct drm_atomic_state *state) 758 814 { 759 - struct drm_connector *connector = &hdmi->connector; 760 - struct drm_display_info *display = &connector->display_info; 815 + struct drm_bridge *bridge = &hdmi->bridge; 816 + struct drm_connector *connector; 817 + struct drm_display_info *info; 761 818 struct drm_connector_state *new_conn_state; 762 819 struct drm_crtc_state *new_crtc_state; 820 + 821 + connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder); 763 822 764 823 new_conn_state = drm_atomic_get_new_connector_state(state, connector); 765 824 if (WARN_ON(!new_conn_state)) ··· 771 826 if (WARN_ON(!new_crtc_state)) 772 827 return -EINVAL; 773 828 829 + info = &connector->display_info; 830 + 774 831 /* Mute video and audio output */ 775 832 hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_VIDEO_BLACK, 776 833 v_AUDIO_MUTE(1) | v_VIDEO_MUTE(1)); 777 834 778 835 /* Set HDMI Mode */ 779 - hdmi_writeb(hdmi, HDMI_HDCP_CTRL, 780 - v_HDMI_DVI(display->is_hdmi)); 836 + hdmi_writeb(hdmi, HDMI_HDCP_CTRL, v_HDMI_DVI(info->is_hdmi)); 781 837 782 838 inno_hdmi_config_video_timing(hdmi, &new_crtc_state->adjusted_mode); 783 839 784 - inno_hdmi_config_video_csc(hdmi); 840 + inno_hdmi_config_video_csc(hdmi, connector, &new_crtc_state->adjusted_mode); 785 841 786 842 drm_atomic_helper_connector_hdmi_update_infoframes(connector, state); 787 843 ··· 803 857 return 0; 804 858 } 805 859 806 - static enum drm_mode_status inno_hdmi_display_mode_valid(struct inno_hdmi *hdmi, 807 - const struct drm_display_mode *mode) 860 + static enum drm_mode_status inno_hdmi_bridge_mode_valid(struct drm_bridge *bridge, 861 + const struct drm_display_info *info, 862 + const struct drm_display_mode *mode) 808 863 { 864 + struct inno_hdmi *hdmi = bridge_to_inno_hdmi(bridge); 809 865 unsigned long mpixelclk, max_tolerance; 810 866 long rounded_refclk; 811 867 ··· 837 889 return MODE_OK; 838 890 } 839 891 840 - static void inno_hdmi_encoder_enable(struct drm_encoder *encoder, 841 - struct drm_atomic_state *state) 842 - { 843 - struct inno_hdmi *hdmi = encoder_to_inno_hdmi(encoder); 844 - 845 - inno_hdmi_setup(hdmi, state); 846 - } 847 - 848 - static void inno_hdmi_encoder_disable(struct drm_encoder *encoder, 849 - struct drm_atomic_state *state) 850 - { 851 - struct inno_hdmi *hdmi = encoder_to_inno_hdmi(encoder); 852 - 853 - inno_hdmi_standby(hdmi); 854 - } 855 - 856 - static int 857 - inno_hdmi_encoder_atomic_check(struct drm_encoder *encoder, 858 - struct drm_crtc_state *crtc_state, 859 - struct drm_connector_state *conn_state) 860 - { 861 - struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); 862 - struct drm_display_mode *mode = &crtc_state->adjusted_mode; 863 - u8 vic = drm_match_cea_mode(mode); 864 - struct inno_hdmi_connector_state *inno_conn_state = 865 - to_inno_hdmi_conn_state(conn_state); 866 - 867 - s->output_mode = ROCKCHIP_OUT_MODE_P888; 868 - s->output_type = DRM_MODE_CONNECTOR_HDMIA; 869 - 870 - if (vic == 6 || vic == 7 || 871 - vic == 21 || vic == 22 || 872 - vic == 2 || vic == 3 || 873 - vic == 17 || vic == 18) 874 - inno_conn_state->colorimetry = HDMI_COLORIMETRY_ITU_601; 875 - else 876 - inno_conn_state->colorimetry = HDMI_COLORIMETRY_ITU_709; 877 - 878 - return 0; 879 - } 880 - 881 - static const struct drm_encoder_helper_funcs inno_hdmi_encoder_helper_funcs = { 882 - .atomic_check = inno_hdmi_encoder_atomic_check, 883 - .atomic_enable = inno_hdmi_encoder_enable, 884 - .atomic_disable = inno_hdmi_encoder_disable, 885 - }; 886 - 887 892 static enum drm_connector_status 888 - inno_hdmi_connector_detect(struct drm_connector *connector, bool force) 893 + inno_hdmi_bridge_detect(struct drm_bridge *bridge, struct drm_connector *connector) 889 894 { 890 - struct inno_hdmi *hdmi = connector_to_inno_hdmi(connector); 895 + struct inno_hdmi *hdmi = bridge_to_inno_hdmi(bridge); 891 896 892 897 return (hdmi_readb(hdmi, HDMI_STATUS) & m_HOTPLUG) ? 893 898 connector_status_connected : connector_status_disconnected; 894 899 } 895 900 896 - static int inno_hdmi_connector_get_modes(struct drm_connector *connector) 901 + static const struct drm_edid * 902 + inno_hdmi_bridge_edid_read(struct drm_bridge *bridge, struct drm_connector *connector) 897 903 { 898 - struct inno_hdmi *hdmi = connector_to_inno_hdmi(connector); 904 + struct inno_hdmi *hdmi = bridge_to_inno_hdmi(bridge); 899 905 const struct drm_edid *drm_edid; 900 - int ret = 0; 901 906 902 - if (!hdmi->ddc) 903 - return 0; 907 + drm_edid = drm_edid_read_ddc(connector, bridge->ddc); 908 + if (!drm_edid) 909 + dev_dbg(hdmi->dev, "failed to get edid\n"); 904 910 905 - drm_edid = drm_edid_read_ddc(connector, hdmi->ddc); 906 - drm_edid_connector_update(connector, drm_edid); 907 - ret = drm_edid_connector_add_modes(connector); 908 - drm_edid_free(drm_edid); 909 - 910 - return ret; 911 + return drm_edid; 911 912 } 912 913 913 - static enum drm_mode_status 914 - inno_hdmi_connector_mode_valid(struct drm_connector *connector, 915 - const struct drm_display_mode *mode) 914 + static void inno_hdmi_bridge_atomic_enable(struct drm_bridge *bridge, 915 + struct drm_atomic_state *state) 916 916 { 917 - struct inno_hdmi *hdmi = connector_to_inno_hdmi(connector); 917 + struct inno_hdmi *hdmi = bridge_to_inno_hdmi(bridge); 918 918 919 - return inno_hdmi_display_mode_valid(hdmi, mode); 919 + inno_hdmi_setup(hdmi, state); 920 920 } 921 921 922 - static void 923 - inno_hdmi_connector_destroy_state(struct drm_connector *connector, 924 - struct drm_connector_state *state) 922 + static void inno_hdmi_bridge_atomic_disable(struct drm_bridge *bridge, 923 + struct drm_atomic_state *state) 925 924 { 926 - struct inno_hdmi_connector_state *inno_conn_state = 927 - to_inno_hdmi_conn_state(state); 925 + struct inno_hdmi *hdmi = bridge_to_inno_hdmi(bridge); 928 926 929 - __drm_atomic_helper_connector_destroy_state(&inno_conn_state->base); 930 - kfree(inno_conn_state); 927 + inno_hdmi_standby(hdmi); 931 928 } 932 929 933 - static void inno_hdmi_connector_reset(struct drm_connector *connector) 934 - { 935 - struct inno_hdmi_connector_state *inno_conn_state; 936 - 937 - if (connector->state) { 938 - inno_hdmi_connector_destroy_state(connector, connector->state); 939 - connector->state = NULL; 940 - } 941 - 942 - inno_conn_state = kzalloc(sizeof(*inno_conn_state), GFP_KERNEL); 943 - if (!inno_conn_state) 944 - return; 945 - 946 - __drm_atomic_helper_connector_reset(connector, &inno_conn_state->base); 947 - __drm_atomic_helper_connector_hdmi_reset(connector, connector->state); 948 - 949 - inno_conn_state->colorimetry = HDMI_COLORIMETRY_ITU_709; 950 - } 951 - 952 - static struct drm_connector_state * 953 - inno_hdmi_connector_duplicate_state(struct drm_connector *connector) 954 - { 955 - struct inno_hdmi_connector_state *inno_conn_state; 956 - 957 - if (WARN_ON(!connector->state)) 958 - return NULL; 959 - 960 - inno_conn_state = kmemdup(to_inno_hdmi_conn_state(connector->state), 961 - sizeof(*inno_conn_state), GFP_KERNEL); 962 - 963 - if (!inno_conn_state) 964 - return NULL; 965 - 966 - __drm_atomic_helper_connector_duplicate_state(connector, 967 - &inno_conn_state->base); 968 - 969 - return &inno_conn_state->base; 970 - } 971 - 972 - static const struct drm_connector_funcs inno_hdmi_connector_funcs = { 973 - .fill_modes = drm_helper_probe_single_connector_modes, 974 - .detect = inno_hdmi_connector_detect, 975 - .reset = inno_hdmi_connector_reset, 976 - .atomic_duplicate_state = inno_hdmi_connector_duplicate_state, 977 - .atomic_destroy_state = inno_hdmi_connector_destroy_state, 930 + static const struct drm_bridge_funcs inno_hdmi_bridge_funcs = { 931 + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, 932 + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, 933 + .atomic_reset = drm_atomic_helper_bridge_reset, 934 + .atomic_enable = inno_hdmi_bridge_atomic_enable, 935 + .atomic_disable = inno_hdmi_bridge_atomic_disable, 936 + .detect = inno_hdmi_bridge_detect, 937 + .edid_read = inno_hdmi_bridge_edid_read, 938 + .hdmi_clear_infoframe = inno_hdmi_bridge_clear_infoframe, 939 + .hdmi_write_infoframe = inno_hdmi_bridge_write_infoframe, 940 + .mode_valid = inno_hdmi_bridge_mode_valid, 978 941 }; 979 - 980 - static struct drm_connector_helper_funcs inno_hdmi_connector_helper_funcs = { 981 - .atomic_check = drm_atomic_helper_connector_hdmi_check, 982 - .get_modes = inno_hdmi_connector_get_modes, 983 - .mode_valid = inno_hdmi_connector_mode_valid, 984 - }; 985 - 986 - static int inno_hdmi_register(struct drm_device *drm, struct inno_hdmi *hdmi) 987 - { 988 - struct drm_encoder *encoder = &hdmi->encoder.encoder; 989 - struct device *dev = hdmi->dev; 990 - 991 - encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node); 992 - 993 - /* 994 - * If we failed to find the CRTC(s) which this encoder is 995 - * supposed to be connected to, it's because the CRTC has 996 - * not been registered yet. Defer probing, and hope that 997 - * the required CRTC is added later. 998 - */ 999 - if (encoder->possible_crtcs == 0) 1000 - return -EPROBE_DEFER; 1001 - 1002 - drm_encoder_helper_add(encoder, &inno_hdmi_encoder_helper_funcs); 1003 - drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS); 1004 - 1005 - hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD; 1006 - 1007 - drm_connector_helper_add(&hdmi->connector, 1008 - &inno_hdmi_connector_helper_funcs); 1009 - drmm_connector_hdmi_init(drm, &hdmi->connector, 1010 - "Rockchip", "Inno HDMI", 1011 - &inno_hdmi_connector_funcs, 1012 - &inno_hdmi_hdmi_connector_funcs, 1013 - DRM_MODE_CONNECTOR_HDMIA, 1014 - hdmi->ddc, 1015 - BIT(HDMI_COLORSPACE_RGB), 1016 - 8); 1017 - 1018 - drm_connector_attach_encoder(&hdmi->connector, encoder); 1019 - 1020 - return 0; 1021 - } 1022 942 1023 943 static irqreturn_t inno_hdmi_i2c_irq(struct inno_hdmi *hdmi) 1024 944 { ··· 927 1111 { 928 1112 struct inno_hdmi *hdmi = dev_id; 929 1113 930 - drm_helper_hpd_irq_event(hdmi->connector.dev); 1114 + drm_helper_hpd_irq_event(hdmi->bridge.dev); 931 1115 932 1116 return IRQ_HANDLED; 933 1117 } ··· 1059 1243 return adap; 1060 1244 } 1061 1245 1062 - static int inno_hdmi_bind(struct device *dev, struct device *master, 1063 - void *data) 1246 + struct inno_hdmi *inno_hdmi_bind(struct device *dev, 1247 + struct drm_encoder *encoder, 1248 + const struct inno_hdmi_plat_data *plat_data) 1064 1249 { 1065 1250 struct platform_device *pdev = to_platform_device(dev); 1066 - struct drm_device *drm = data; 1067 1251 struct inno_hdmi *hdmi; 1068 - const struct inno_hdmi_variant *variant; 1069 1252 int irq; 1070 1253 int ret; 1071 1254 1072 - hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL); 1073 - if (!hdmi) 1074 - return -ENOMEM; 1255 + if (!plat_data->phy_configs || !plat_data->default_phy_config) { 1256 + dev_err(dev, "Missing platform PHY ops\n"); 1257 + return ERR_PTR(-ENODEV); 1258 + } 1259 + 1260 + hdmi = devm_drm_bridge_alloc(dev, struct inno_hdmi, bridge, &inno_hdmi_bridge_funcs); 1261 + if (IS_ERR(hdmi)) 1262 + return ERR_CAST(hdmi); 1075 1263 1076 1264 hdmi->dev = dev; 1077 - 1078 - variant = of_device_get_match_data(hdmi->dev); 1079 - if (!variant) 1080 - return -EINVAL; 1081 - 1082 - hdmi->variant = variant; 1265 + hdmi->plat_data = plat_data; 1083 1266 1084 1267 hdmi->regs = devm_platform_ioremap_resource(pdev, 0); 1085 1268 if (IS_ERR(hdmi->regs)) 1086 - return PTR_ERR(hdmi->regs); 1269 + return ERR_CAST(hdmi->regs); 1087 1270 1088 1271 hdmi->pclk = devm_clk_get_enabled(hdmi->dev, "pclk"); 1089 - if (IS_ERR(hdmi->pclk)) 1090 - return dev_err_probe(dev, PTR_ERR(hdmi->pclk), "Unable to get HDMI pclk\n"); 1091 - 1092 - hdmi->refclk = devm_clk_get_optional_enabled(hdmi->dev, "ref"); 1093 - if (IS_ERR(hdmi->refclk)) 1094 - return dev_err_probe(dev, PTR_ERR(hdmi->refclk), "Unable to get HDMI refclk\n"); 1095 - 1096 - if (hdmi->variant->dev_type == RK3036_HDMI) { 1097 - hdmi->grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,grf"); 1098 - if (IS_ERR(hdmi->grf)) 1099 - return dev_err_probe(dev, 1100 - PTR_ERR(hdmi->grf), "Unable to get rockchip,grf\n"); 1272 + if (IS_ERR(hdmi->pclk)) { 1273 + dev_err_probe(dev, PTR_ERR(hdmi->pclk), "Unable to get HDMI pclk\n"); 1274 + return ERR_CAST(hdmi->pclk); 1101 1275 } 1102 1276 1103 - irq = platform_get_irq(pdev, 0); 1104 - if (irq < 0) 1105 - return irq; 1277 + hdmi->refclk = devm_clk_get_optional_enabled(hdmi->dev, "ref"); 1278 + if (IS_ERR(hdmi->refclk)) { 1279 + dev_err_probe(dev, PTR_ERR(hdmi->refclk), "Unable to get HDMI refclk\n"); 1280 + return ERR_CAST(hdmi->refclk); 1281 + } 1106 1282 1107 1283 inno_hdmi_init_hw(hdmi); 1108 1284 1109 - hdmi->ddc = inno_hdmi_i2c_adapter(hdmi); 1110 - if (IS_ERR(hdmi->ddc)) 1111 - return PTR_ERR(hdmi->ddc); 1112 - 1113 - ret = inno_hdmi_register(drm, hdmi); 1114 - if (ret) 1115 - return ret; 1116 - 1117 - dev_set_drvdata(dev, hdmi); 1285 + irq = platform_get_irq(pdev, 0); 1286 + if (irq < 0) 1287 + return ERR_PTR(irq); 1118 1288 1119 1289 ret = devm_request_threaded_irq(dev, irq, inno_hdmi_hardirq, 1120 1290 inno_hdmi_irq, IRQF_SHARED, 1121 1291 dev_name(dev), hdmi); 1122 - if (ret < 0) 1123 - goto err_cleanup_hdmi; 1292 + if (ret) 1293 + return ERR_PTR(ret); 1124 1294 1125 - return 0; 1126 - err_cleanup_hdmi: 1127 - hdmi->connector.funcs->destroy(&hdmi->connector); 1128 - hdmi->encoder.encoder.funcs->destroy(&hdmi->encoder.encoder); 1129 - return ret; 1295 + hdmi->bridge.driver_private = hdmi; 1296 + hdmi->bridge.ops = DRM_BRIDGE_OP_DETECT | 1297 + DRM_BRIDGE_OP_EDID | 1298 + DRM_BRIDGE_OP_HDMI | 1299 + DRM_BRIDGE_OP_HPD; 1300 + hdmi->bridge.of_node = pdev->dev.of_node; 1301 + hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA; 1302 + hdmi->bridge.vendor = "Inno"; 1303 + hdmi->bridge.product = "Inno HDMI"; 1304 + 1305 + hdmi->bridge.ddc = inno_hdmi_i2c_adapter(hdmi); 1306 + if (IS_ERR(hdmi->bridge.ddc)) 1307 + return ERR_CAST(hdmi->bridge.ddc); 1308 + 1309 + ret = devm_drm_bridge_add(dev, &hdmi->bridge); 1310 + if (ret) 1311 + return ERR_PTR(ret); 1312 + 1313 + ret = drm_bridge_attach(encoder, &hdmi->bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR); 1314 + if (ret) 1315 + return ERR_PTR(ret); 1316 + 1317 + return hdmi; 1130 1318 } 1131 - 1132 - static void inno_hdmi_unbind(struct device *dev, struct device *master, 1133 - void *data) 1134 - { 1135 - struct inno_hdmi *hdmi = dev_get_drvdata(dev); 1136 - 1137 - hdmi->connector.funcs->destroy(&hdmi->connector); 1138 - hdmi->encoder.encoder.funcs->destroy(&hdmi->encoder.encoder); 1139 - } 1140 - 1141 - static const struct component_ops inno_hdmi_ops = { 1142 - .bind = inno_hdmi_bind, 1143 - .unbind = inno_hdmi_unbind, 1144 - }; 1145 - 1146 - static int inno_hdmi_probe(struct platform_device *pdev) 1147 - { 1148 - return component_add(&pdev->dev, &inno_hdmi_ops); 1149 - } 1150 - 1151 - static void inno_hdmi_remove(struct platform_device *pdev) 1152 - { 1153 - component_del(&pdev->dev, &inno_hdmi_ops); 1154 - } 1155 - 1156 - static const struct inno_hdmi_variant rk3036_inno_hdmi_variant = { 1157 - .dev_type = RK3036_HDMI, 1158 - .phy_configs = rk3036_hdmi_phy_configs, 1159 - .default_phy_config = &rk3036_hdmi_phy_configs[1], 1160 - }; 1161 - 1162 - static const struct inno_hdmi_variant rk3128_inno_hdmi_variant = { 1163 - .dev_type = RK3128_HDMI, 1164 - .phy_configs = rk3128_hdmi_phy_configs, 1165 - .default_phy_config = &rk3128_hdmi_phy_configs[1], 1166 - }; 1167 - 1168 - static const struct of_device_id inno_hdmi_dt_ids[] = { 1169 - { .compatible = "rockchip,rk3036-inno-hdmi", 1170 - .data = &rk3036_inno_hdmi_variant, 1171 - }, 1172 - { .compatible = "rockchip,rk3128-inno-hdmi", 1173 - .data = &rk3128_inno_hdmi_variant, 1174 - }, 1175 - {}, 1176 - }; 1177 - MODULE_DEVICE_TABLE(of, inno_hdmi_dt_ids); 1178 - 1179 - struct platform_driver inno_hdmi_driver = { 1180 - .probe = inno_hdmi_probe, 1181 - .remove = inno_hdmi_remove, 1182 - .driver = { 1183 - .name = "innohdmi-rockchip", 1184 - .of_match_table = inno_hdmi_dt_ids, 1185 - }, 1186 - }; 1319 + EXPORT_SYMBOL_GPL(inno_hdmi_bind); 1320 + MODULE_AUTHOR("Andy Yan <andyshrk@163.com>"); 1321 + MODULE_DESCRIPTION("INNOSILICON HDMI transmitter library"); 1322 + MODULE_LICENSE("GPL");
+20 -10
drivers/gpu/drm/tests/drm_gem_shmem_test.c
··· 19 19 #include <drm/drm_gem_shmem_helper.h> 20 20 #include <drm/drm_kunit_helpers.h> 21 21 22 + MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING"); 23 + 22 24 #define TEST_SIZE SZ_1M 23 25 #define TEST_BYTE 0xae 24 26 ··· 34 32 struct sg_table *); 35 33 36 34 KUNIT_DEFINE_ACTION_WRAPPER(drm_gem_shmem_free_wrapper, drm_gem_shmem_free, 35 + struct drm_gem_shmem_object *); 36 + 37 + KUNIT_DEFINE_ACTION_WRAPPER(drm_gem_shmem_unpin_wrapper, drm_gem_shmem_unpin, 37 38 struct drm_gem_shmem_object *); 38 39 39 40 /* ··· 178 173 ret = kunit_add_action_or_reset(test, drm_gem_shmem_free_wrapper, shmem); 179 174 KUNIT_ASSERT_EQ(test, ret, 0); 180 175 181 - ret = drm_gem_shmem_vmap_locked(shmem, &map); 176 + ret = drm_gem_shmem_vmap(shmem, &map); 182 177 KUNIT_ASSERT_EQ(test, ret, 0); 183 178 KUNIT_ASSERT_NOT_NULL(test, shmem->vaddr); 184 179 KUNIT_ASSERT_FALSE(test, iosys_map_is_null(&map)); ··· 188 183 for (i = 0; i < TEST_SIZE; i++) 189 184 KUNIT_EXPECT_EQ(test, iosys_map_rd(&map, i, u8), TEST_BYTE); 190 185 191 - drm_gem_shmem_vunmap_locked(shmem, &map); 186 + drm_gem_shmem_vunmap(shmem, &map); 192 187 KUNIT_EXPECT_NULL(test, shmem->vaddr); 193 188 KUNIT_EXPECT_EQ(test, refcount_read(&shmem->vmap_use_count), 0); 194 189 } ··· 199 194 * scatter/gather table large enough to accommodate the backing memory 200 195 * is successfully exported. 201 196 */ 202 - static void drm_gem_shmem_test_get_pages_sgt(struct kunit *test) 197 + static void drm_gem_shmem_test_get_sg_table(struct kunit *test) 203 198 { 204 199 struct drm_device *drm_dev = test->priv; 205 200 struct drm_gem_shmem_object *shmem; ··· 215 210 KUNIT_ASSERT_EQ(test, ret, 0); 216 211 217 212 ret = drm_gem_shmem_pin(shmem); 213 + KUNIT_ASSERT_EQ(test, ret, 0); 214 + 215 + ret = kunit_add_action_or_reset(test, drm_gem_shmem_unpin_wrapper, shmem); 218 216 KUNIT_ASSERT_EQ(test, ret, 0); 219 217 220 218 sgt = drm_gem_shmem_get_sg_table(shmem); ··· 244 236 * backing pages are pinned and a scatter/gather table large enough to 245 237 * accommodate the backing memory is successfully exported. 246 238 */ 247 - static void drm_gem_shmem_test_get_sg_table(struct kunit *test) 239 + static void drm_gem_shmem_test_get_pages_sgt(struct kunit *test) 248 240 { 249 241 struct drm_device *drm_dev = test->priv; 250 242 struct drm_gem_shmem_object *shmem; ··· 292 284 ret = kunit_add_action_or_reset(test, drm_gem_shmem_free_wrapper, shmem); 293 285 KUNIT_ASSERT_EQ(test, ret, 0); 294 286 295 - ret = drm_gem_shmem_madvise_locked(shmem, 1); 287 + ret = drm_gem_shmem_madvise(shmem, 1); 296 288 KUNIT_EXPECT_TRUE(test, ret); 297 289 KUNIT_ASSERT_EQ(test, shmem->madv, 1); 298 290 299 291 /* Set madv to a negative value */ 300 - ret = drm_gem_shmem_madvise_locked(shmem, -1); 292 + ret = drm_gem_shmem_madvise(shmem, -1); 301 293 KUNIT_EXPECT_FALSE(test, ret); 302 294 KUNIT_ASSERT_EQ(test, shmem->madv, -1); 303 295 304 296 /* Check that madv cannot be set back to a positive value */ 305 - ret = drm_gem_shmem_madvise_locked(shmem, 0); 297 + ret = drm_gem_shmem_madvise(shmem, 0); 306 298 KUNIT_EXPECT_FALSE(test, ret); 307 299 KUNIT_ASSERT_EQ(test, shmem->madv, -1); 308 300 } ··· 330 322 ret = drm_gem_shmem_is_purgeable(shmem); 331 323 KUNIT_EXPECT_FALSE(test, ret); 332 324 333 - ret = drm_gem_shmem_madvise_locked(shmem, 1); 325 + ret = drm_gem_shmem_madvise(shmem, 1); 334 326 KUNIT_EXPECT_TRUE(test, ret); 335 327 336 328 /* The scatter/gather table will be freed by drm_gem_shmem_free */ ··· 340 332 ret = drm_gem_shmem_is_purgeable(shmem); 341 333 KUNIT_EXPECT_TRUE(test, ret); 342 334 343 - drm_gem_shmem_purge_locked(shmem); 335 + ret = drm_gem_shmem_purge(shmem); 336 + KUNIT_ASSERT_EQ(test, ret, 0); 337 + 344 338 KUNIT_EXPECT_NULL(test, shmem->pages); 345 339 KUNIT_EXPECT_NULL(test, shmem->sgt); 346 340 KUNIT_EXPECT_EQ(test, shmem->madv, -1); ··· 376 366 KUNIT_CASE(drm_gem_shmem_test_obj_create_private), 377 367 KUNIT_CASE(drm_gem_shmem_test_pin_pages), 378 368 KUNIT_CASE(drm_gem_shmem_test_vmap), 379 - KUNIT_CASE(drm_gem_shmem_test_get_pages_sgt), 380 369 KUNIT_CASE(drm_gem_shmem_test_get_sg_table), 370 + KUNIT_CASE(drm_gem_shmem_test_get_pages_sgt), 381 371 KUNIT_CASE(drm_gem_shmem_test_madvise), 382 372 KUNIT_CASE(drm_gem_shmem_test_purge), 383 373 {}
+221
drivers/gpu/drm/tests/drm_panic_test.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 or MIT 2 + /* 3 + * Copyright (c) 2025 Red Hat. 4 + * Author: Jocelyn Falempe <jfalempe@redhat.com> 5 + * 6 + * KUNIT tests for drm panic 7 + */ 8 + 9 + #include <drm/drm_fourcc.h> 10 + #include <drm/drm_panic.h> 11 + 12 + #include <kunit/test.h> 13 + 14 + #include <linux/units.h> 15 + #include <linux/vmalloc.h> 16 + 17 + /* Check the framebuffer color only if the panic colors are the default */ 18 + #if (CONFIG_DRM_PANIC_BACKGROUND_COLOR == 0 && \ 19 + CONFIG_DRM_PANIC_FOREGROUND_COLOR == 0xffffff) 20 + 21 + static void drm_panic_check_color_byte(struct kunit *test, u8 b) 22 + { 23 + KUNIT_EXPECT_TRUE(test, (b == 0 || b == 0xff)); 24 + } 25 + #else 26 + static void drm_panic_check_color_byte(struct kunit *test, u8 b) {} 27 + #endif 28 + 29 + struct drm_test_mode { 30 + const int width; 31 + const int height; 32 + const u32 format; 33 + void (*draw_screen)(struct drm_scanout_buffer *sb); 34 + const char *fname; 35 + }; 36 + 37 + /* 38 + * Run all tests for the 3 panic screens: user, kmsg and qr_code 39 + */ 40 + #define DRM_TEST_MODE_LIST(func) \ 41 + DRM_PANIC_TEST_MODE(1024, 768, DRM_FORMAT_XRGB8888, func) \ 42 + DRM_PANIC_TEST_MODE(300, 200, DRM_FORMAT_XRGB8888, func) \ 43 + DRM_PANIC_TEST_MODE(1920, 1080, DRM_FORMAT_XRGB8888, func) \ 44 + DRM_PANIC_TEST_MODE(1024, 768, DRM_FORMAT_RGB565, func) \ 45 + DRM_PANIC_TEST_MODE(1024, 768, DRM_FORMAT_RGB888, func) \ 46 + 47 + #define DRM_PANIC_TEST_MODE(w, h, f, name) { \ 48 + .width = w, \ 49 + .height = h, \ 50 + .format = f, \ 51 + .draw_screen = draw_panic_screen_##name, \ 52 + .fname = #name, \ 53 + }, \ 54 + 55 + static const struct drm_test_mode drm_test_modes_cases[] = { 56 + DRM_TEST_MODE_LIST(user) 57 + DRM_TEST_MODE_LIST(kmsg) 58 + #if IS_ENABLED(CONFIG_DRM_PANIC_SCREEN_QR_CODE) 59 + DRM_TEST_MODE_LIST(qr_code) 60 + #endif 61 + }; 62 + 63 + #undef DRM_PANIC_TEST_MODE 64 + 65 + static int drm_test_panic_init(struct kunit *test) 66 + { 67 + struct drm_scanout_buffer *priv; 68 + 69 + priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL); 70 + KUNIT_ASSERT_NOT_NULL(test, priv); 71 + 72 + test->priv = priv; 73 + 74 + drm_panic_set_description("Kunit testing"); 75 + 76 + return 0; 77 + } 78 + 79 + /* 80 + * Test drawing the panic screen, using a memory mapped framebuffer 81 + * Set the whole buffer to 0xa5, and then check that all pixels have been 82 + * written. 83 + */ 84 + static void drm_test_panic_screen_user_map(struct kunit *test) 85 + { 86 + struct drm_scanout_buffer *sb = test->priv; 87 + const struct drm_test_mode *params = test->param_value; 88 + char *fb; 89 + int fb_size; 90 + int i; 91 + 92 + sb->format = drm_format_info(params->format); 93 + fb_size = params->width * params->height * sb->format->cpp[0]; 94 + 95 + fb = vmalloc(fb_size); 96 + KUNIT_ASSERT_NOT_NULL(test, fb); 97 + 98 + memset(fb, 0xa5, fb_size); 99 + 100 + iosys_map_set_vaddr(&sb->map[0], fb); 101 + sb->width = params->width; 102 + sb->height = params->height; 103 + sb->pitch[0] = params->width * sb->format->cpp[0]; 104 + 105 + params->draw_screen(sb); 106 + 107 + for (i = 0; i < fb_size; i++) 108 + drm_panic_check_color_byte(test, fb[i]); 109 + 110 + vfree(fb); 111 + } 112 + 113 + /* 114 + * Test drawing the panic screen, using a list of pages framebuffer 115 + * Set the whole buffer to 0xa5, and then check that all pixels have been 116 + * written. 117 + */ 118 + static void drm_test_panic_screen_user_page(struct kunit *test) 119 + { 120 + struct drm_scanout_buffer *sb = test->priv; 121 + const struct drm_test_mode *params = test->param_value; 122 + int fb_size, p, i, npages; 123 + struct page **pages; 124 + u8 *vaddr; 125 + 126 + sb->format = drm_format_info(params->format); 127 + fb_size = params->width * params->height * sb->format->cpp[0]; 128 + npages = DIV_ROUND_UP(fb_size, PAGE_SIZE); 129 + 130 + pages = kmalloc_array(npages, sizeof(struct page *), GFP_KERNEL); 131 + KUNIT_ASSERT_NOT_NULL(test, pages); 132 + 133 + for (p = 0; p < npages; p++) { 134 + pages[p] = alloc_page(GFP_KERNEL); 135 + if (!pages[p]) { 136 + npages = p - 1; 137 + KUNIT_FAIL(test, "Can't allocate page\n"); 138 + goto free_pages; 139 + } 140 + vaddr = kmap_local_page(pages[p]); 141 + memset(vaddr, 0xa5, PAGE_SIZE); 142 + kunmap_local(vaddr); 143 + } 144 + sb->pages = pages; 145 + sb->width = params->width; 146 + sb->height = params->height; 147 + sb->pitch[0] = params->width * sb->format->cpp[0]; 148 + 149 + params->draw_screen(sb); 150 + 151 + for (p = 0; p < npages; p++) { 152 + int bytes_in_page = (p == npages - 1) ? fb_size - p * PAGE_SIZE : PAGE_SIZE; 153 + 154 + vaddr = kmap_local_page(pages[p]); 155 + for (i = 0; i < bytes_in_page; i++) 156 + drm_panic_check_color_byte(test, vaddr[i]); 157 + 158 + kunmap_local(vaddr); 159 + } 160 + 161 + free_pages: 162 + for (p = 0; p < npages; p++) 163 + __free_page(pages[p]); 164 + kfree(pages); 165 + } 166 + 167 + static void drm_test_panic_set_pixel(struct drm_scanout_buffer *sb, 168 + unsigned int x, 169 + unsigned int y, 170 + u32 color) 171 + { 172 + struct kunit *test = (struct kunit *)sb->private; 173 + 174 + KUNIT_ASSERT_TRUE(test, x < sb->width && y < sb->height); 175 + } 176 + 177 + /* 178 + * Test drawing the panic screen, using the set_pixel callback 179 + * Check that all calls to set_pixel() are within the framebuffer 180 + */ 181 + static void drm_test_panic_screen_user_set_pixel(struct kunit *test) 182 + { 183 + struct drm_scanout_buffer *sb = test->priv; 184 + const struct drm_test_mode *params = test->param_value; 185 + 186 + sb->format = drm_format_info(params->format); 187 + sb->set_pixel = drm_test_panic_set_pixel; 188 + sb->width = params->width; 189 + sb->height = params->height; 190 + sb->private = test; 191 + 192 + params->draw_screen(sb); 193 + } 194 + 195 + static void drm_test_panic_desc(const struct drm_test_mode *t, char *desc) 196 + { 197 + sprintf(desc, "Panic screen %s, mode: %d x %d \t%p4cc", 198 + t->fname, t->width, t->height, &t->format); 199 + } 200 + 201 + KUNIT_ARRAY_PARAM(drm_test_panic_screen_user_map, drm_test_modes_cases, drm_test_panic_desc); 202 + KUNIT_ARRAY_PARAM(drm_test_panic_screen_user_page, drm_test_modes_cases, drm_test_panic_desc); 203 + KUNIT_ARRAY_PARAM(drm_test_panic_screen_user_set_pixel, drm_test_modes_cases, drm_test_panic_desc); 204 + 205 + static struct kunit_case drm_panic_screen_user_test[] = { 206 + KUNIT_CASE_PARAM(drm_test_panic_screen_user_map, 207 + drm_test_panic_screen_user_map_gen_params), 208 + KUNIT_CASE_PARAM(drm_test_panic_screen_user_page, 209 + drm_test_panic_screen_user_page_gen_params), 210 + KUNIT_CASE_PARAM(drm_test_panic_screen_user_set_pixel, 211 + drm_test_panic_screen_user_set_pixel_gen_params), 212 + { } 213 + }; 214 + 215 + static struct kunit_suite drm_panic_suite = { 216 + .name = "drm_panic", 217 + .init = drm_test_panic_init, 218 + .test_cases = drm_panic_screen_user_test, 219 + }; 220 + 221 + kunit_test_suite(drm_panic_suite);
+2 -3
drivers/gpu/drm/tiny/arcpgu.c
··· 308 308 return ret; 309 309 310 310 if (encoder_node) { 311 - struct drm_bridge *bridge; 312 - 313 311 /* Locate drm bridge from the hdmi encoder DT node */ 314 - bridge = of_drm_find_bridge(encoder_node); 312 + struct drm_bridge *bridge __free(drm_bridge_put) = 313 + of_drm_find_and_get_bridge(encoder_node); 315 314 if (!bridge) 316 315 return -EPROBE_DEFER; 317 316
+2
drivers/gpu/drm/v3d/v3d_drv.c
··· 378 378 if (ret) 379 379 goto clk_disable; 380 380 381 + dma_set_max_seg_size(&pdev->dev, UINT_MAX); 382 + 381 383 v3d->va_width = 30 + V3D_GET_FIELD(mmu_debug, V3D_MMU_VA_WIDTH); 382 384 383 385 ident1 = V3D_READ(V3D_HUB_IDENT1);
+1
drivers/gpu/drm/vkms/vkms_composer.c
··· 5 5 #include <drm/drm_atomic.h> 6 6 #include <drm/drm_atomic_helper.h> 7 7 #include <drm/drm_blend.h> 8 + #include <drm/drm_colorop.h> 8 9 #include <drm/drm_fourcc.h> 9 10 #include <drm/drm_fixed.h> 10 11 #include <drm/drm_gem_framebuffer_helper.h>
+1
drivers/gpu/drm/vkms/vkms_drv.c
··· 17 17 #include <drm/drm_gem.h> 18 18 #include <drm/drm_atomic.h> 19 19 #include <drm/drm_atomic_helper.h> 20 + #include <drm/drm_colorop.h> 20 21 #include <drm/drm_drv.h> 21 22 #include <drm/drm_fbdev_shmem.h> 22 23 #include <drm/drm_file.h>
+2 -30
drivers/tty/vt/vt.c
··· 38 38 * 39 39 * - Arno Griffioen <arno@usn.nl> 40 40 * - David Carter <carter@cs.bris.ac.uk> 41 - * 41 + * 42 42 * The abstract console driver provides a generic interface for a text 43 43 * console. It supports VGA text mode, frame buffer based graphical consoles 44 44 * and special graphics processors that are only accessible through some ··· 187 187 * fg_console is the current virtual console, 188 188 * last_console is the last used one, 189 189 * want_console is the console we want to switch to, 190 - * saved_* variants are for save/restore around kernel debugger enter/leave 191 190 */ 192 191 int fg_console; 193 192 EXPORT_SYMBOL(fg_console); 194 193 int last_console; 195 194 int want_console = -1; 196 - 197 - static int saved_fg_console; 198 - static int saved_last_console; 199 - static int saved_want_console; 200 - static int saved_vc_mode; 201 - static int saved_console_blanked; 202 195 203 196 /* 204 197 * For each existing display, we have a pointer to console currently visible ··· 4280 4287 */ 4281 4288 void con_debug_enter(struct vc_data *vc) 4282 4289 { 4283 - saved_fg_console = fg_console; 4284 - saved_last_console = last_console; 4285 - saved_want_console = want_console; 4286 - saved_vc_mode = vc->vc_mode; 4287 - saved_console_blanked = console_blanked; 4288 - vc->vc_mode = KD_TEXT; 4289 - console_blanked = 0; 4290 - if (vc->vc_sw->con_debug_enter) 4291 - vc->vc_sw->con_debug_enter(vc); 4292 4290 #ifdef CONFIG_KGDB_KDB 4293 4291 /* Set the initial LINES variable if it is not already set */ 4294 4292 if (vc->vc_rows < 999) { ··· 4319 4335 * was invoked. 4320 4336 */ 4321 4337 void con_debug_leave(void) 4322 - { 4323 - struct vc_data *vc; 4324 - 4325 - fg_console = saved_fg_console; 4326 - last_console = saved_last_console; 4327 - want_console = saved_want_console; 4328 - console_blanked = saved_console_blanked; 4329 - vc_cons[fg_console].d->vc_mode = saved_vc_mode; 4330 - 4331 - vc = vc_cons[fg_console].d; 4332 - if (vc->vc_sw->con_debug_leave) 4333 - vc->vc_sw->con_debug_leave(vc); 4334 - } 4338 + { } 4335 4339 EXPORT_SYMBOL_GPL(con_debug_leave); 4336 4340 4337 4341 static int do_register_con_driver(const struct consw *csw, int first, int last)
+33
include/drm/bridge/inno_hdmi.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 + /* 3 + * Copyright (c) 2025 Rockchip Electronics Co., Ltd. 4 + */ 5 + 6 + #ifndef __INNO_HDMI__ 7 + #define __INNO_HDMI__ 8 + 9 + struct device; 10 + struct drm_encoder; 11 + struct drm_display_mode; 12 + struct inno_hdmi; 13 + 14 + struct inno_hdmi_plat_ops { 15 + void (*enable)(struct device *pdev, struct drm_display_mode *mode); 16 + }; 17 + 18 + struct inno_hdmi_phy_config { 19 + unsigned long pixelclock; 20 + u8 pre_emphasis; 21 + u8 voltage_level_control; 22 + }; 23 + 24 + struct inno_hdmi_plat_data { 25 + const struct inno_hdmi_plat_ops *ops; 26 + struct inno_hdmi_phy_config *phy_configs; 27 + struct inno_hdmi_phy_config *default_phy_config; 28 + }; 29 + 30 + struct inno_hdmi *inno_hdmi_bind(struct device *pdev, 31 + struct drm_encoder *encoder, 32 + const struct inno_hdmi_plat_data *plat_data); 33 + #endif /* __INNO_HDMI__ */
+8 -31
include/drm/drm_atomic.h
··· 30 30 31 31 #include <drm/drm_crtc.h> 32 32 #include <drm/drm_util.h> 33 - #include <drm/drm_colorop.h> 34 33 35 34 /** 36 35 * struct drm_crtc_commit - track modeset commits on a CRTC ··· 711 712 struct drm_colorop_state * 712 713 drm_atomic_get_colorop_state(struct drm_atomic_state *state, 713 714 struct drm_colorop *colorop); 715 + 716 + struct drm_colorop_state * 717 + drm_atomic_get_old_colorop_state(struct drm_atomic_state *state, 718 + struct drm_colorop *colorop); 719 + struct drm_colorop_state * 720 + drm_atomic_get_new_colorop_state(struct drm_atomic_state *state, 721 + struct drm_colorop *colorop); 722 + 714 723 struct drm_connector_state * __must_check 715 724 drm_atomic_get_connector_state(struct drm_atomic_state *state, 716 725 struct drm_connector *connector); ··· 813 806 struct drm_plane *plane) 814 807 { 815 808 return state->planes[drm_plane_index(plane)].new_state; 816 - } 817 - 818 - /** 819 - * drm_atomic_get_old_colorop_state - get colorop state, if it exists 820 - * @state: global atomic state object 821 - * @colorop: colorop to grab 822 - * 823 - * This function returns the old colorop state for the given colorop, or 824 - * NULL if the colorop is not part of the global atomic state. 825 - */ 826 - static inline struct drm_colorop_state * 827 - drm_atomic_get_old_colorop_state(struct drm_atomic_state *state, 828 - struct drm_colorop *colorop) 829 - { 830 - return state->colorops[drm_colorop_index(colorop)].old_state; 831 - } 832 - 833 - /** 834 - * drm_atomic_get_new_colorop_state - get colorop state, if it exists 835 - * @state: global atomic state object 836 - * @colorop: colorop to grab 837 - * 838 - * This function returns the new colorop state for the given colorop, or 839 - * NULL if the colorop is not part of the global atomic state. 840 - */ 841 - static inline struct drm_colorop_state * 842 - drm_atomic_get_new_colorop_state(struct drm_atomic_state *state, 843 - struct drm_colorop *colorop) 844 - { 845 - return state->colorops[drm_colorop_index(colorop)].new_state; 846 809 } 847 810 848 811 /**
+17
include/drm/drm_bridge.h
··· 731 731 * controllers for HDMI bridges. 732 732 */ 733 733 void (*hpd_notify)(struct drm_bridge *bridge, 734 + struct drm_connector *connector, 734 735 enum drm_connector_status status); 735 736 736 737 /** ··· 1279 1278 * @hpd_cb. 1280 1279 */ 1281 1280 void *hpd_data; 1281 + 1282 + /** 1283 + * @next_bridge: Pointer to the following bridge, automatically put 1284 + * when this bridge is freed (i.e. at destroy time). This is for 1285 + * drivers needing to store a pointer to the next bridge in the 1286 + * chain, and ensures any code still holding a reference to this 1287 + * bridge after its removal cannot use-after-free the next 1288 + * bridge. Any other bridge pointers stored by the driver must be 1289 + * put in the .destroy callback by driver code. 1290 + */ 1291 + struct drm_bridge *next_bridge; 1282 1292 }; 1283 1293 1284 1294 static inline struct drm_bridge * ··· 1337 1325 enum drm_bridge_attach_flags flags); 1338 1326 1339 1327 #ifdef CONFIG_OF 1328 + struct drm_bridge *of_drm_find_and_get_bridge(struct device_node *np); 1340 1329 struct drm_bridge *of_drm_find_bridge(struct device_node *np); 1341 1330 #else 1331 + static inline struct drm_bridge *of_drm_find_and_get_bridge(struct device_node *np) 1332 + { 1333 + return NULL; 1334 + } 1342 1335 static inline struct drm_bridge *of_drm_find_bridge(struct device_node *np) 1343 1336 { 1344 1337 return NULL;
+11
include/drm/drm_gem_shmem_helper.h
··· 300 300 .gem_prime_import = drm_gem_shmem_prime_import_no_map, \ 301 301 .dumb_create = drm_gem_shmem_dumb_create 302 302 303 + /* 304 + * Kunit helpers 305 + */ 306 + 307 + #if IS_ENABLED(CONFIG_KUNIT) 308 + int drm_gem_shmem_vmap(struct drm_gem_shmem_object *shmem, struct iosys_map *map); 309 + void drm_gem_shmem_vunmap(struct drm_gem_shmem_object *shmem, struct iosys_map *map); 310 + int drm_gem_shmem_madvise(struct drm_gem_shmem_object *shmem, int madv); 311 + int drm_gem_shmem_purge(struct drm_gem_shmem_object *shmem); 312 + #endif 313 + 303 314 #endif /* __DRM_GEM_SHMEM_HELPER_H__ */
-8
include/linux/console.h
··· 79 79 * characters. (optional) 80 80 * @con_invert_region: invert a region of length @count on @vc starting at @p. 81 81 * (optional) 82 - * @con_debug_enter: prepare the console for the debugger. This includes, but 83 - * is not limited to, unblanking the console, loading an 84 - * appropriate palette, and allowing debugger generated output. 85 - * (optional) 86 - * @con_debug_leave: restore the console to its pre-debug state as closely as 87 - * possible. (optional) 88 82 */ 89 83 struct consw { 90 84 struct module *owner; ··· 117 123 enum vc_intensity intensity, 118 124 bool blink, bool underline, bool reverse, bool italic); 119 125 void (*con_invert_region)(struct vc_data *vc, u16 *p, int count); 120 - void (*con_debug_enter)(struct vc_data *vc); 121 - void (*con_debug_leave)(struct vc_data *vc); 122 126 }; 123 127 124 128 extern const struct consw *conswitchp;