| .. | .. |
|---|
| 8 | 8 | */ |
|---|
| 9 | 9 | |
|---|
| 10 | 10 | #include <linux/clk.h> |
|---|
| 11 | +#include <linux/gpio/consumer.h> |
|---|
| 11 | 12 | #include <linux/mfd/syscon.h> |
|---|
| 12 | 13 | #include <linux/module.h> |
|---|
| 14 | +#include <linux/of_gpio.h> |
|---|
| 13 | 15 | #include <linux/platform_device.h> |
|---|
| 14 | 16 | #include <linux/phy/phy.h> |
|---|
| 15 | 17 | #include <linux/regmap.h> |
|---|
| .. | .. |
|---|
| 57 | 59 | #define RK3399_GRF_SOC_CON20 0x6250 |
|---|
| 58 | 60 | #define RK3399_HDMI_LCDC_SEL BIT(6) |
|---|
| 59 | 61 | |
|---|
| 62 | +#define RK3528_VO_GRF_HDMI_MASK 0x60014 |
|---|
| 63 | +#define RK3528_HDMI_SNKDET_SEL BIT(6) |
|---|
| 64 | +#define RK3528_HDMI_SNKDET BIT(5) |
|---|
| 65 | +#define RK3528_HDMI_CECIN_MSK BIT(2) |
|---|
| 66 | +#define RK3528_HDMI_SDAIN_MSK BIT(1) |
|---|
| 67 | +#define RK3528_HDMI_SCLIN_MSK BIT(0) |
|---|
| 68 | + |
|---|
| 69 | +#define RK3528PMU_GRF_SOC_CON6 0x70018 |
|---|
| 70 | +#define RK3528_HDMI_SDA5V_GRF BIT(6) |
|---|
| 71 | +#define RK3528_HDMI_SCL5V_GRF BIT(5) |
|---|
| 72 | +#define RK3528_HDMI_CEC5V_GRF BIT(4) |
|---|
| 73 | +#define RK3528_HDMI_HPD5V_GRF BIT(3) |
|---|
| 74 | + |
|---|
| 75 | +#define RK3528_GPIO_SWPORT_DR_L 0x0000 |
|---|
| 76 | +#define RK3528_GPIO0_A2_DR BIT(2) |
|---|
| 77 | + |
|---|
| 60 | 78 | #define RK3568_GRF_VO_CON1 0x0364 |
|---|
| 61 | 79 | #define RK3568_HDMI_SDAIN_MSK BIT(15) |
|---|
| 62 | 80 | #define RK3568_HDMI_SCLIN_MSK BIT(14) |
|---|
| .. | .. |
|---|
| 103 | 121 | struct rockchip_hdmi { |
|---|
| 104 | 122 | struct device *dev; |
|---|
| 105 | 123 | struct regmap *regmap; |
|---|
| 124 | + void __iomem *gpio_base; |
|---|
| 106 | 125 | struct drm_encoder encoder; |
|---|
| 107 | 126 | const struct rockchip_hdmi_chip_data *chip_data; |
|---|
| 108 | 127 | struct clk *phyref_clk; |
|---|
| 109 | 128 | struct clk *grf_clk; |
|---|
| 110 | 129 | struct clk *hclk_vio; |
|---|
| 111 | 130 | struct clk *hclk_vop; |
|---|
| 131 | + struct clk *dclk_vop; |
|---|
| 112 | 132 | struct dw_hdmi *hdmi; |
|---|
| 113 | 133 | |
|---|
| 114 | 134 | struct phy *phy; |
|---|
| .. | .. |
|---|
| 117 | 137 | bool unsupported_deep_color; |
|---|
| 118 | 138 | bool skip_check_420_mode; |
|---|
| 119 | 139 | bool mode_changed; |
|---|
| 140 | + bool hpd_wake_en; |
|---|
| 120 | 141 | u8 force_output; |
|---|
| 121 | 142 | u8 id; |
|---|
| 122 | 143 | |
|---|
| 123 | 144 | unsigned long bus_format; |
|---|
| 124 | 145 | unsigned long output_bus_format; |
|---|
| 125 | 146 | unsigned long enc_out_encoding; |
|---|
| 147 | + unsigned long prev_bus_format; |
|---|
| 126 | 148 | int color_changed; |
|---|
| 127 | 149 | |
|---|
| 128 | 150 | struct drm_property *color_depth_property; |
|---|
| .. | .. |
|---|
| 143 | 165 | unsigned int phy_bus_width; |
|---|
| 144 | 166 | enum drm_hdmi_output_type hdmi_output; |
|---|
| 145 | 167 | struct rockchip_drm_sub_dev sub_dev; |
|---|
| 168 | + |
|---|
| 169 | + struct gpio_desc *hpd_gpiod; |
|---|
| 170 | + struct pinctrl *p; |
|---|
| 171 | + struct pinctrl_state *idle_state; |
|---|
| 172 | + struct pinctrl_state *default_state; |
|---|
| 173 | + int hpd_irq; |
|---|
| 146 | 174 | }; |
|---|
| 147 | 175 | |
|---|
| 148 | 176 | #define to_rockchip_hdmi(x) container_of(x, struct rockchip_hdmi, x) |
|---|
| .. | .. |
|---|
| 460 | 488 | { ~0UL, 0x0000, 0x0000, 0x0000}, |
|---|
| 461 | 489 | }; |
|---|
| 462 | 490 | |
|---|
| 491 | +static int hdmi_bus_fmt_color_depth(unsigned int bus_format) |
|---|
| 492 | +{ |
|---|
| 493 | + switch (bus_format) { |
|---|
| 494 | + case MEDIA_BUS_FMT_RGB888_1X24: |
|---|
| 495 | + case MEDIA_BUS_FMT_YUV8_1X24: |
|---|
| 496 | + case MEDIA_BUS_FMT_UYVY8_1X16: |
|---|
| 497 | + case MEDIA_BUS_FMT_UYYVYY8_0_5X24: |
|---|
| 498 | + return 8; |
|---|
| 499 | + |
|---|
| 500 | + case MEDIA_BUS_FMT_RGB101010_1X30: |
|---|
| 501 | + case MEDIA_BUS_FMT_YUV10_1X30: |
|---|
| 502 | + case MEDIA_BUS_FMT_UYVY10_1X20: |
|---|
| 503 | + case MEDIA_BUS_FMT_UYYVYY10_0_5X30: |
|---|
| 504 | + return 10; |
|---|
| 505 | + |
|---|
| 506 | + case MEDIA_BUS_FMT_RGB121212_1X36: |
|---|
| 507 | + case MEDIA_BUS_FMT_YUV12_1X36: |
|---|
| 508 | + case MEDIA_BUS_FMT_UYVY12_1X24: |
|---|
| 509 | + case MEDIA_BUS_FMT_UYYVYY12_0_5X36: |
|---|
| 510 | + return 12; |
|---|
| 511 | + |
|---|
| 512 | + case MEDIA_BUS_FMT_RGB161616_1X48: |
|---|
| 513 | + case MEDIA_BUS_FMT_YUV16_1X48: |
|---|
| 514 | + case MEDIA_BUS_FMT_UYYVYY16_0_5X48: |
|---|
| 515 | + return 16; |
|---|
| 516 | + |
|---|
| 517 | + default: |
|---|
| 518 | + return 0; |
|---|
| 519 | + } |
|---|
| 520 | +} |
|---|
| 521 | + |
|---|
| 463 | 522 | static int rockchip_hdmi_update_phy_table(struct rockchip_hdmi *hdmi, |
|---|
| 464 | 523 | u32 *config, |
|---|
| 465 | 524 | int phy_table_size) |
|---|
| .. | .. |
|---|
| 482 | 541 | } |
|---|
| 483 | 542 | |
|---|
| 484 | 543 | return 0; |
|---|
| 544 | +} |
|---|
| 545 | + |
|---|
| 546 | +static irqreturn_t rockchip_hdmi_hpd_irq_handler(int irq, void *arg) |
|---|
| 547 | +{ |
|---|
| 548 | + u32 val; |
|---|
| 549 | + struct rockchip_hdmi *hdmi = arg; |
|---|
| 550 | + |
|---|
| 551 | + val = gpiod_get_value(hdmi->hpd_gpiod); |
|---|
| 552 | + if (val) { |
|---|
| 553 | + val = HIWORD_UPDATE(RK3528_HDMI_SNKDET, RK3528_HDMI_SNKDET); |
|---|
| 554 | + if (hdmi->hdmi && hdmi->hpd_wake_en && hdmi->hpd_gpiod) |
|---|
| 555 | + dw_hdmi_set_hpd_wake(hdmi->hdmi); |
|---|
| 556 | + } else { |
|---|
| 557 | + val = HIWORD_UPDATE(0, RK3528_HDMI_SNKDET); |
|---|
| 558 | + } |
|---|
| 559 | + regmap_write(hdmi->regmap, RK3528_VO_GRF_HDMI_MASK, val); |
|---|
| 560 | + |
|---|
| 561 | + return IRQ_HANDLED; |
|---|
| 562 | +} |
|---|
| 563 | + |
|---|
| 564 | +static void dw_hdmi_rk3528_gpio_hpd_init(struct rockchip_hdmi *hdmi) |
|---|
| 565 | +{ |
|---|
| 566 | + u32 val; |
|---|
| 567 | + |
|---|
| 568 | + if (hdmi->hpd_gpiod) { |
|---|
| 569 | + /* gpio0_a2's input enable is controlled by gpio output data bit */ |
|---|
| 570 | + val = HIWORD_UPDATE(RK3528_GPIO0_A2_DR, RK3528_GPIO0_A2_DR); |
|---|
| 571 | + writel(val, hdmi->gpio_base + RK3528_GPIO_SWPORT_DR_L); |
|---|
| 572 | + |
|---|
| 573 | + val = HIWORD_UPDATE(RK3528_HDMI_SNKDET_SEL | RK3528_HDMI_SDAIN_MSK | |
|---|
| 574 | + RK3528_HDMI_SCLIN_MSK, |
|---|
| 575 | + RK3528_HDMI_SNKDET_SEL | RK3528_HDMI_SDAIN_MSK | |
|---|
| 576 | + RK3528_HDMI_SCLIN_MSK); |
|---|
| 577 | + } else { |
|---|
| 578 | + val = HIWORD_UPDATE(RK3528_HDMI_SDAIN_MSK | RK3528_HDMI_SCLIN_MSK, |
|---|
| 579 | + RK3528_HDMI_SDAIN_MSK | RK3528_HDMI_SCLIN_MSK); |
|---|
| 580 | + } |
|---|
| 581 | + |
|---|
| 582 | + regmap_write(hdmi->regmap, RK3528_VO_GRF_HDMI_MASK, val); |
|---|
| 583 | + |
|---|
| 584 | + val = gpiod_get_value(hdmi->hpd_gpiod); |
|---|
| 585 | + if (val) { |
|---|
| 586 | + val = HIWORD_UPDATE(RK3528_HDMI_SNKDET, RK3528_HDMI_SNKDET); |
|---|
| 587 | + if (hdmi->hdmi && hdmi->hpd_wake_en && hdmi->hpd_gpiod) |
|---|
| 588 | + dw_hdmi_set_hpd_wake(hdmi->hdmi); |
|---|
| 589 | + } else { |
|---|
| 590 | + val = HIWORD_UPDATE(0, RK3528_HDMI_SNKDET); |
|---|
| 591 | + } |
|---|
| 592 | + regmap_write(hdmi->regmap, RK3528_VO_GRF_HDMI_MASK, val); |
|---|
| 485 | 593 | } |
|---|
| 486 | 594 | |
|---|
| 487 | 595 | static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi) |
|---|
| .. | .. |
|---|
| 539 | 647 | return PTR_ERR(hdmi->hclk_vop); |
|---|
| 540 | 648 | } |
|---|
| 541 | 649 | |
|---|
| 650 | + hdmi->dclk_vop = devm_clk_get_optional(hdmi->dev, "dclk_vop"); |
|---|
| 651 | + if (IS_ERR(hdmi->dclk_vop)) { |
|---|
| 652 | + dev_err(hdmi->dev, "failed to get dclk_vop\n"); |
|---|
| 653 | + return PTR_ERR(hdmi->dclk_vop); |
|---|
| 654 | + } |
|---|
| 655 | + |
|---|
| 542 | 656 | ret = of_property_read_u32(np, "max-tmdsclk", |
|---|
| 543 | 657 | &hdmi->max_tmdsclk); |
|---|
| 544 | 658 | if (ret != -EINVAL && ret < 0) { |
|---|
| .. | .. |
|---|
| 576 | 690 | kfree(phy_config); |
|---|
| 577 | 691 | } else { |
|---|
| 578 | 692 | dev_dbg(hdmi->dev, "use default hdmi phy table\n"); |
|---|
| 693 | + } |
|---|
| 694 | + |
|---|
| 695 | + hdmi->hpd_gpiod = devm_gpiod_get_optional(hdmi->dev, "hpd", GPIOD_IN); |
|---|
| 696 | + |
|---|
| 697 | + if (IS_ERR(hdmi->hpd_gpiod)) { |
|---|
| 698 | + dev_err(hdmi->dev, "error getting HDP GPIO: %ld\n", |
|---|
| 699 | + PTR_ERR(hdmi->hpd_gpiod)); |
|---|
| 700 | + return PTR_ERR(hdmi->hpd_gpiod); |
|---|
| 701 | + } |
|---|
| 702 | + |
|---|
| 703 | + if (hdmi->hpd_gpiod) { |
|---|
| 704 | + struct resource *res; |
|---|
| 705 | + struct platform_device *pdev = to_platform_device(hdmi->dev); |
|---|
| 706 | + |
|---|
| 707 | + /* gpio interrupt reflects hpd status */ |
|---|
| 708 | + hdmi->hpd_irq = gpiod_to_irq(hdmi->hpd_gpiod); |
|---|
| 709 | + if (hdmi->hpd_irq < 0) |
|---|
| 710 | + return -EINVAL; |
|---|
| 711 | + |
|---|
| 712 | + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); |
|---|
| 713 | + if (!res) { |
|---|
| 714 | + DRM_DEV_ERROR(hdmi->dev, "failed to get gpio regs\n"); |
|---|
| 715 | + return -EINVAL; |
|---|
| 716 | + } |
|---|
| 717 | + |
|---|
| 718 | + hdmi->gpio_base = devm_ioremap(hdmi->dev, res->start, resource_size(res)); |
|---|
| 719 | + if (IS_ERR(hdmi->gpio_base)) { |
|---|
| 720 | + DRM_DEV_ERROR(hdmi->dev, "Unable to get gpio ioregmap\n"); |
|---|
| 721 | + return PTR_ERR(hdmi->gpio_base); |
|---|
| 722 | + } |
|---|
| 723 | + |
|---|
| 724 | + dw_hdmi_rk3528_gpio_hpd_init(hdmi); |
|---|
| 725 | + ret = devm_request_threaded_irq(hdmi->dev, hdmi->hpd_irq, NULL, |
|---|
| 726 | + rockchip_hdmi_hpd_irq_handler, |
|---|
| 727 | + IRQF_TRIGGER_RISING | |
|---|
| 728 | + IRQF_TRIGGER_FALLING | |
|---|
| 729 | + IRQF_ONESHOT, |
|---|
| 730 | + "hdmi-hpd", hdmi); |
|---|
| 731 | + if (ret) { |
|---|
| 732 | + dev_err(hdmi->dev, "failed to request hpd IRQ: %d\n", ret); |
|---|
| 733 | + return ret; |
|---|
| 734 | + } |
|---|
| 735 | + |
|---|
| 736 | + hdmi->hpd_wake_en = device_property_read_bool(hdmi->dev, "hpd-wake-up"); |
|---|
| 737 | + if (hdmi->hpd_wake_en) |
|---|
| 738 | + enable_irq_wake(hdmi->hpd_irq); |
|---|
| 739 | + } |
|---|
| 740 | + |
|---|
| 741 | + hdmi->p = devm_pinctrl_get(hdmi->dev); |
|---|
| 742 | + if (IS_ERR(hdmi->p)) { |
|---|
| 743 | + dev_err(hdmi->dev, "could not get pinctrl\n"); |
|---|
| 744 | + return PTR_ERR(hdmi->p); |
|---|
| 745 | + } |
|---|
| 746 | + |
|---|
| 747 | + hdmi->idle_state = pinctrl_lookup_state(hdmi->p, "idle"); |
|---|
| 748 | + if (IS_ERR(hdmi->idle_state)) { |
|---|
| 749 | + dev_dbg(hdmi->dev, "idle state is not defined\n"); |
|---|
| 750 | + return 0; |
|---|
| 751 | + } |
|---|
| 752 | + |
|---|
| 753 | + hdmi->default_state = pinctrl_lookup_state(hdmi->p, "default"); |
|---|
| 754 | + if (IS_ERR(hdmi->default_state)) { |
|---|
| 755 | + dev_err(hdmi->dev, "could not find default state\n"); |
|---|
| 756 | + return PTR_ERR(hdmi->default_state); |
|---|
| 579 | 757 | } |
|---|
| 580 | 758 | |
|---|
| 581 | 759 | return 0; |
|---|
| .. | .. |
|---|
| 670 | 848 | struct drm_crtc *crtc = encoder->crtc; |
|---|
| 671 | 849 | struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc->state); |
|---|
| 672 | 850 | |
|---|
| 851 | + if (WARN_ON(!crtc || !crtc->state)) |
|---|
| 852 | + return; |
|---|
| 853 | + |
|---|
| 673 | 854 | if (!hdmi->mode_changed) |
|---|
| 674 | 855 | s->output_if &= ~VOP_OUTPUT_IF_HDMI0; |
|---|
| 675 | 856 | /* |
|---|
| .. | .. |
|---|
| 754 | 935 | unsigned int color_depth; |
|---|
| 755 | 936 | bool support_dc = false; |
|---|
| 756 | 937 | bool sink_is_hdmi = dw_hdmi_get_output_whether_hdmi(hdmi->hdmi); |
|---|
| 938 | + bool yuv422_out = false; |
|---|
| 757 | 939 | int max_tmds_clock = info->max_tmds_clock; |
|---|
| 758 | 940 | int output_eotf; |
|---|
| 759 | 941 | |
|---|
| .. | .. |
|---|
| 829 | 1011 | *eotf = output_eotf; |
|---|
| 830 | 1012 | } |
|---|
| 831 | 1013 | |
|---|
| 832 | | - if ((*eotf > TRADITIONAL_GAMMA_HDR && |
|---|
| 833 | | - conn_state->connector->hdr_sink_metadata.hdmi_type1.eotf & |
|---|
| 834 | | - BIT(*eotf)) || (hdmi->colorimetry == |
|---|
| 835 | | - RK_HDMI_COLORIMETRY_BT2020 && info->hdmi.colorimetry & |
|---|
| 836 | | - (BIT(6) | BIT(7)))) |
|---|
| 1014 | + /* bt2020 sdr/hdr output */ |
|---|
| 1015 | + if (hdmi->colorimetry == RK_HDMI_COLORIMETRY_BT2020 && |
|---|
| 1016 | + info->hdmi.colorimetry & (BIT(6) | BIT(7))) { |
|---|
| 837 | 1017 | *enc_out_encoding = V4L2_YCBCR_ENC_BT2020; |
|---|
| 838 | | - else if ((vic == 6) || (vic == 7) || (vic == 21) || (vic == 22) || |
|---|
| 839 | | - (vic == 2) || (vic == 3) || (vic == 17) || (vic == 18)) |
|---|
| 840 | | - *enc_out_encoding = V4L2_YCBCR_ENC_601; |
|---|
| 841 | | - else |
|---|
| 1018 | + yuv422_out = true; |
|---|
| 1019 | + /* bt709 hdr output */ |
|---|
| 1020 | + } else if (hdmi->colorimetry != RK_HDMI_COLORIMETRY_BT2020 && |
|---|
| 1021 | + (conn_state->connector->hdr_sink_metadata.hdmi_type1.eotf & BIT(*eotf) && |
|---|
| 1022 | + *eotf > TRADITIONAL_GAMMA_HDR)) { |
|---|
| 842 | 1023 | *enc_out_encoding = V4L2_YCBCR_ENC_709; |
|---|
| 1024 | + yuv422_out = true; |
|---|
| 1025 | + } else if ((vic == 6) || (vic == 7) || (vic == 21) || (vic == 22) || |
|---|
| 1026 | + (vic == 2) || (vic == 3) || (vic == 17) || (vic == 18)) { |
|---|
| 1027 | + *enc_out_encoding = V4L2_YCBCR_ENC_601; |
|---|
| 1028 | + } else { |
|---|
| 1029 | + *enc_out_encoding = V4L2_YCBCR_ENC_709; |
|---|
| 1030 | + } |
|---|
| 843 | 1031 | |
|---|
| 844 | | - if (*enc_out_encoding == V4L2_YCBCR_ENC_BT2020) { |
|---|
| 845 | | - /* BT2020 require color depth at lest 10bit */ |
|---|
| 846 | | - color_depth = 10; |
|---|
| 847 | | - /* We prefer use YCbCr422 to send 10bit */ |
|---|
| 1032 | + if ((yuv422_out || hdmi->hdmi_output == DRM_HDMI_OUTPUT_YCBCR_HQ) && |
|---|
| 1033 | + color_depth == 10 && hdmi_bus_fmt_color_depth(hdmi->prev_bus_format) == 8) { |
|---|
| 1034 | + /* We prefer use YCbCr422 to send hdr 10bit */ |
|---|
| 848 | 1035 | if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422) |
|---|
| 849 | 1036 | *color_format = DRM_HDMI_OUTPUT_YCBCR422; |
|---|
| 850 | 1037 | } |
|---|
| .. | .. |
|---|
| 1063 | 1250 | return hdmi->hdr_panel_blob_ptr; |
|---|
| 1064 | 1251 | } |
|---|
| 1065 | 1252 | |
|---|
| 1253 | +static void dw_hdmi_rockchip_update_color_format(struct drm_connector_state *conn_state, |
|---|
| 1254 | + void *data) |
|---|
| 1255 | +{ |
|---|
| 1256 | + struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; |
|---|
| 1257 | + |
|---|
| 1258 | + dw_hdmi_rockchip_check_color(conn_state, hdmi); |
|---|
| 1259 | +} |
|---|
| 1260 | + |
|---|
| 1066 | 1261 | static bool |
|---|
| 1067 | 1262 | dw_hdmi_rockchip_get_color_changed(void *data) |
|---|
| 1068 | 1263 | { |
|---|
| .. | .. |
|---|
| 1072 | 1267 | if (hdmi->color_changed) |
|---|
| 1073 | 1268 | ret = true; |
|---|
| 1074 | 1269 | hdmi->color_changed = 0; |
|---|
| 1270 | + |
|---|
| 1271 | + return ret; |
|---|
| 1272 | +} |
|---|
| 1273 | + |
|---|
| 1274 | +static bool |
|---|
| 1275 | +dw_hdmi_rockchip_check_hdr_color_change(struct drm_connector_state *conn_state, |
|---|
| 1276 | + void *data) |
|---|
| 1277 | +{ |
|---|
| 1278 | + struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; |
|---|
| 1279 | + |
|---|
| 1280 | + if (!conn_state || !data) |
|---|
| 1281 | + return false; |
|---|
| 1282 | + |
|---|
| 1283 | + if (dw_hdmi_rockchip_check_color(conn_state, hdmi)) |
|---|
| 1284 | + return true; |
|---|
| 1285 | + |
|---|
| 1286 | + return false; |
|---|
| 1287 | +} |
|---|
| 1288 | + |
|---|
| 1289 | +static void dw_hdmi_rockchip_set_prev_bus_format(void *data, unsigned long bus_format) |
|---|
| 1290 | +{ |
|---|
| 1291 | + struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; |
|---|
| 1292 | + |
|---|
| 1293 | + hdmi->prev_bus_format = bus_format; |
|---|
| 1294 | +} |
|---|
| 1295 | + |
|---|
| 1296 | +static void dw_hdmi_rockchip_set_ddc_io(void *data, bool enable) |
|---|
| 1297 | +{ |
|---|
| 1298 | + struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; |
|---|
| 1299 | + |
|---|
| 1300 | + if (!hdmi->p || !hdmi->idle_state || !hdmi->default_state) |
|---|
| 1301 | + return; |
|---|
| 1302 | + |
|---|
| 1303 | + if (!enable) { |
|---|
| 1304 | + if (pinctrl_select_state(hdmi->p, hdmi->idle_state)) |
|---|
| 1305 | + dev_err(hdmi->dev, "could not select idle state\n"); |
|---|
| 1306 | + } else { |
|---|
| 1307 | + if (pinctrl_select_state(hdmi->p, hdmi->default_state)) |
|---|
| 1308 | + dev_err(hdmi->dev, "could not select default state\n"); |
|---|
| 1309 | + } |
|---|
| 1310 | +} |
|---|
| 1311 | + |
|---|
| 1312 | +static int dw_hdmi_rockchip_dclk_set(void *data, bool enable, int vp_id) |
|---|
| 1313 | +{ |
|---|
| 1314 | + struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; |
|---|
| 1315 | + int ret = 0; |
|---|
| 1316 | + |
|---|
| 1317 | + if (!hdmi->dclk_vop) |
|---|
| 1318 | + return 0; |
|---|
| 1319 | + |
|---|
| 1320 | + if (enable) { |
|---|
| 1321 | + ret = clk_prepare_enable(hdmi->dclk_vop); |
|---|
| 1322 | + if (ret < 0) |
|---|
| 1323 | + dev_err(hdmi->dev, "failed to enable dclk_vop\n"); |
|---|
| 1324 | + } else { |
|---|
| 1325 | + clk_disable_unprepare(hdmi->dclk_vop); |
|---|
| 1326 | + } |
|---|
| 1075 | 1327 | |
|---|
| 1076 | 1328 | return ret; |
|---|
| 1077 | 1329 | } |
|---|
| .. | .. |
|---|
| 1158 | 1410 | } |
|---|
| 1159 | 1411 | |
|---|
| 1160 | 1412 | hdmi->bus_format = color; |
|---|
| 1413 | + hdmi->prev_bus_format = color; |
|---|
| 1161 | 1414 | |
|---|
| 1162 | 1415 | if (hdmi->hdmi_output == DRM_HDMI_OUTPUT_YCBCR422) { |
|---|
| 1163 | 1416 | if (hdmi->colordepth == 12) |
|---|
| .. | .. |
|---|
| 1581 | 1834 | .setup_hpd = dw_hdmi_rk3328_setup_hpd, |
|---|
| 1582 | 1835 | }; |
|---|
| 1583 | 1836 | |
|---|
| 1837 | +static enum drm_connector_status |
|---|
| 1838 | +dw_hdmi_rk3528_read_hpd(struct dw_hdmi *dw_hdmi, void *data) |
|---|
| 1839 | +{ |
|---|
| 1840 | + return dw_hdmi_phy_read_hpd(dw_hdmi, data); |
|---|
| 1841 | +} |
|---|
| 1842 | + |
|---|
| 1843 | +static const struct dw_hdmi_phy_ops rk3528_hdmi_phy_ops = { |
|---|
| 1844 | + .init = dw_hdmi_rockchip_genphy_init, |
|---|
| 1845 | + .disable = dw_hdmi_rockchip_genphy_disable, |
|---|
| 1846 | + .read_hpd = dw_hdmi_rk3528_read_hpd, |
|---|
| 1847 | + .update_hpd = dw_hdmi_phy_update_hpd, |
|---|
| 1848 | + .setup_hpd = dw_hdmi_phy_setup_hpd, |
|---|
| 1849 | +}; |
|---|
| 1850 | + |
|---|
| 1584 | 1851 | static struct rockchip_hdmi_chip_data rk3328_chip_data = { |
|---|
| 1585 | 1852 | .lcdsel_grf_reg = -1, |
|---|
| 1586 | 1853 | }; |
|---|
| .. | .. |
|---|
| 1627 | 1894 | .ycbcr_420_allowed = true, |
|---|
| 1628 | 1895 | }; |
|---|
| 1629 | 1896 | |
|---|
| 1897 | +static struct rockchip_hdmi_chip_data rk3528_chip_data = { |
|---|
| 1898 | + .lcdsel_grf_reg = -1, |
|---|
| 1899 | +}; |
|---|
| 1900 | + |
|---|
| 1901 | +static const struct dw_hdmi_plat_data rk3528_hdmi_drv_data = { |
|---|
| 1902 | + .mode_valid = dw_hdmi_rockchip_mode_valid, |
|---|
| 1903 | + .mpll_cfg = rockchip_mpll_cfg, |
|---|
| 1904 | + .cur_ctr = rockchip_cur_ctr, |
|---|
| 1905 | + .phy_config = rockchip_phy_config, |
|---|
| 1906 | + .phy_data = &rk3528_chip_data, |
|---|
| 1907 | + .phy_ops = &rk3528_hdmi_phy_ops, |
|---|
| 1908 | + .phy_name = "inno_dw_hdmi_phy2", |
|---|
| 1909 | + .phy_force_vendor = true, |
|---|
| 1910 | + .ycbcr_420_allowed = true, |
|---|
| 1911 | +}; |
|---|
| 1912 | + |
|---|
| 1630 | 1913 | static struct rockchip_hdmi_chip_data rk3568_chip_data = { |
|---|
| 1631 | 1914 | .lcdsel_grf_reg = -1, |
|---|
| 1632 | 1915 | .ddc_en_reg = RK3568_GRF_VO_CON1, |
|---|
| .. | .. |
|---|
| 1658 | 1941 | }, |
|---|
| 1659 | 1942 | { .compatible = "rockchip,rk3399-dw-hdmi", |
|---|
| 1660 | 1943 | .data = &rk3399_hdmi_drv_data |
|---|
| 1944 | + }, |
|---|
| 1945 | + { .compatible = "rockchip,rk3528-dw-hdmi", |
|---|
| 1946 | + .data = &rk3528_hdmi_drv_data |
|---|
| 1661 | 1947 | }, |
|---|
| 1662 | 1948 | { .compatible = "rockchip,rk3568-dw-hdmi", |
|---|
| 1663 | 1949 | .data = &rk3568_hdmi_drv_data |
|---|
| .. | .. |
|---|
| 1713 | 1999 | dw_hdmi_rockchip_get_hdr_blob; |
|---|
| 1714 | 2000 | plat_data->get_color_changed = |
|---|
| 1715 | 2001 | dw_hdmi_rockchip_get_color_changed; |
|---|
| 2002 | + plat_data->update_color_format = |
|---|
| 2003 | + dw_hdmi_rockchip_update_color_format; |
|---|
| 2004 | + plat_data->check_hdr_color_change = |
|---|
| 2005 | + dw_hdmi_rockchip_check_hdr_color_change; |
|---|
| 2006 | + plat_data->set_prev_bus_format = |
|---|
| 2007 | + dw_hdmi_rockchip_set_prev_bus_format; |
|---|
| 2008 | + plat_data->set_ddc_io = |
|---|
| 2009 | + dw_hdmi_rockchip_set_ddc_io; |
|---|
| 2010 | + plat_data->dclk_set = |
|---|
| 2011 | + dw_hdmi_rockchip_dclk_set; |
|---|
| 1716 | 2012 | plat_data->property_ops = &dw_hdmi_rockchip_property_ops; |
|---|
| 1717 | 2013 | |
|---|
| 1718 | 2014 | encoder = &hdmi->encoder; |
|---|
| .. | .. |
|---|
| 1780 | 2076 | platform_set_drvdata(pdev, hdmi); |
|---|
| 1781 | 2077 | |
|---|
| 1782 | 2078 | hdmi->hdmi = dw_hdmi_bind(pdev, encoder, plat_data); |
|---|
| 1783 | | - |
|---|
| 1784 | 2079 | /* |
|---|
| 1785 | 2080 | * If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(), |
|---|
| 1786 | 2081 | * which would have called the encoder cleanup. Do it manually. |
|---|
| .. | .. |
|---|
| 1833 | 2128 | if (!hdmi) |
|---|
| 1834 | 2129 | return; |
|---|
| 1835 | 2130 | |
|---|
| 2131 | + if (hdmi->hpd_gpiod) { |
|---|
| 2132 | + disable_irq(hdmi->hpd_irq); |
|---|
| 2133 | + if (hdmi->hpd_wake_en) |
|---|
| 2134 | + disable_irq_wake(hdmi->hpd_irq); |
|---|
| 2135 | + } |
|---|
| 1836 | 2136 | dw_hdmi_suspend(&pdev->dev, hdmi->hdmi); |
|---|
| 1837 | 2137 | pm_runtime_put_sync(&pdev->dev); |
|---|
| 1838 | 2138 | } |
|---|
| .. | .. |
|---|
| 1849 | 2149 | { |
|---|
| 1850 | 2150 | struct rockchip_hdmi *hdmi = dev_get_drvdata(dev); |
|---|
| 1851 | 2151 | |
|---|
| 2152 | + if (hdmi->hpd_gpiod) |
|---|
| 2153 | + disable_irq(hdmi->hpd_irq); |
|---|
| 1852 | 2154 | dw_hdmi_suspend(dev, hdmi->hdmi); |
|---|
| 1853 | 2155 | pm_runtime_put_sync(dev); |
|---|
| 1854 | 2156 | |
|---|
| .. | .. |
|---|
| 1859 | 2161 | { |
|---|
| 1860 | 2162 | struct rockchip_hdmi *hdmi = dev_get_drvdata(dev); |
|---|
| 1861 | 2163 | |
|---|
| 2164 | + if (hdmi->hpd_gpiod) { |
|---|
| 2165 | + dw_hdmi_rk3528_gpio_hpd_init(hdmi); |
|---|
| 2166 | + enable_irq(hdmi->hpd_irq); |
|---|
| 2167 | + } |
|---|
| 1862 | 2168 | pm_runtime_get_sync(dev); |
|---|
| 1863 | 2169 | dw_hdmi_resume(dev, hdmi->hdmi); |
|---|
| 1864 | 2170 | |
|---|