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.

drm/rockchip: inno-hdmi: Convert to drm bridge

Convert it to drm bridge driver, it will be convenient for us to
migrate the connector part to the display driver later.

Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Reviewed-by: Heiko Stuebner <heiko@sntech.de>
Link: https://patch.msgid.link/20251016083843.76675-2-andyshrk@163.com
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>

authored by

Andy Yan and committed by
Dmitry Baryshkov
969325a2 c08c123d

+368 -369
+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
+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");
+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__ */