diff options
author | Dave Airlie <airlied@redhat.com> | 2018-06-21 19:58:57 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2018-06-21 21:03:43 -0400 |
commit | f3294568bbb19cbfc53451de192df6daae80f9b3 (patch) | |
tree | a9edc98aa1ef92a0f03c0d4a743b5dd87a3c37c0 | |
parent | 8325e6e36c239d5df2eecfb7983f49e0e6f5b2a7 (diff) | |
parent | e8b92efa629dac0e70ea4145c5e70616de5f89c8 (diff) |
Merge tag 'drm-misc-fixes-2018-06-21' of git://anongit.freedesktop.org/drm/drm-misc into drm-fixes
Fixes for v4.18-rc2:
- A reversion of a commit in drm/sun4i to fix a run-time fault.
- Various fixes to the sii8620 bridge.
- Small bugfix to correctly check stride in atmel-hlcdc.
Signed-off-by: Dave Airlie <airlied@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/787d4bef-a579-4046-d0fc-f8c2c5b80c25@linux.intel.com
-rw-r--r-- | drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/bridge/sil-sii8620.c | 309 | ||||
-rw-r--r-- | drivers/gpu/drm/sun4i/sun4i_tcon.c | 25 |
3 files changed, 118 insertions, 218 deletions
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c index 73c875db45f4..47e0992f3908 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c | |||
@@ -839,7 +839,7 @@ static int atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane) | |||
839 | return ret; | 839 | return ret; |
840 | } | 840 | } |
841 | 841 | ||
842 | if (desc->layout.xstride && desc->layout.pstride) { | 842 | if (desc->layout.xstride[0] && desc->layout.pstride[0]) { |
843 | int ret; | 843 | int ret; |
844 | 844 | ||
845 | ret = drm_plane_create_rotation_property(&plane->base, | 845 | ret = drm_plane_create_rotation_property(&plane->base, |
diff --git a/drivers/gpu/drm/bridge/sil-sii8620.c b/drivers/gpu/drm/bridge/sil-sii8620.c index 7ab36042a822..250effa0e6b8 100644 --- a/drivers/gpu/drm/bridge/sil-sii8620.c +++ b/drivers/gpu/drm/bridge/sil-sii8620.c | |||
@@ -36,8 +36,11 @@ | |||
36 | 36 | ||
37 | #define SII8620_BURST_BUF_LEN 288 | 37 | #define SII8620_BURST_BUF_LEN 288 |
38 | #define VAL_RX_HDMI_CTRL2_DEFVAL VAL_RX_HDMI_CTRL2_IDLE_CNT(3) | 38 | #define VAL_RX_HDMI_CTRL2_DEFVAL VAL_RX_HDMI_CTRL2_IDLE_CNT(3) |
39 | #define MHL1_MAX_LCLK 225000 | 39 | |
40 | #define MHL3_MAX_LCLK 600000 | 40 | #define MHL1_MAX_PCLK 75000 |
41 | #define MHL1_MAX_PCLK_PP_MODE 150000 | ||
42 | #define MHL3_MAX_PCLK 200000 | ||
43 | #define MHL3_MAX_PCLK_PP_MODE 300000 | ||
41 | 44 | ||
42 | enum sii8620_mode { | 45 | enum sii8620_mode { |
43 | CM_DISCONNECTED, | 46 | CM_DISCONNECTED, |
@@ -80,6 +83,9 @@ struct sii8620 { | |||
80 | u8 devcap[MHL_DCAP_SIZE]; | 83 | u8 devcap[MHL_DCAP_SIZE]; |
81 | u8 xdevcap[MHL_XDC_SIZE]; | 84 | u8 xdevcap[MHL_XDC_SIZE]; |
82 | u8 avif[HDMI_INFOFRAME_SIZE(AVI)]; | 85 | u8 avif[HDMI_INFOFRAME_SIZE(AVI)]; |
86 | bool feature_complete; | ||
87 | bool devcap_read; | ||
88 | bool sink_detected; | ||
83 | struct edid *edid; | 89 | struct edid *edid; |
84 | unsigned int gen2_write_burst:1; | 90 | unsigned int gen2_write_burst:1; |
85 | enum sii8620_mt_state mt_state; | 91 | enum sii8620_mt_state mt_state; |
@@ -476,7 +482,7 @@ static void sii8620_update_array(u8 *dst, u8 *src, int count) | |||
476 | } | 482 | } |
477 | } | 483 | } |
478 | 484 | ||
479 | static void sii8620_sink_detected(struct sii8620 *ctx, int ret) | 485 | static void sii8620_identify_sink(struct sii8620 *ctx) |
480 | { | 486 | { |
481 | static const char * const sink_str[] = { | 487 | static const char * const sink_str[] = { |
482 | [SINK_NONE] = "NONE", | 488 | [SINK_NONE] = "NONE", |
@@ -487,7 +493,7 @@ static void sii8620_sink_detected(struct sii8620 *ctx, int ret) | |||
487 | char sink_name[20]; | 493 | char sink_name[20]; |
488 | struct device *dev = ctx->dev; | 494 | struct device *dev = ctx->dev; |
489 | 495 | ||
490 | if (ret < 0) | 496 | if (!ctx->sink_detected || !ctx->devcap_read) |
491 | return; | 497 | return; |
492 | 498 | ||
493 | sii8620_fetch_edid(ctx); | 499 | sii8620_fetch_edid(ctx); |
@@ -496,6 +502,7 @@ static void sii8620_sink_detected(struct sii8620 *ctx, int ret) | |||
496 | sii8620_mhl_disconnected(ctx); | 502 | sii8620_mhl_disconnected(ctx); |
497 | return; | 503 | return; |
498 | } | 504 | } |
505 | sii8620_set_upstream_edid(ctx); | ||
499 | 506 | ||
500 | if (drm_detect_hdmi_monitor(ctx->edid)) | 507 | if (drm_detect_hdmi_monitor(ctx->edid)) |
501 | ctx->sink_type = SINK_HDMI; | 508 | ctx->sink_type = SINK_HDMI; |
@@ -508,53 +515,6 @@ static void sii8620_sink_detected(struct sii8620 *ctx, int ret) | |||
508 | sink_str[ctx->sink_type], sink_name); | 515 | sink_str[ctx->sink_type], sink_name); |
509 | } | 516 | } |
510 | 517 | ||
511 | static void sii8620_hsic_init(struct sii8620 *ctx) | ||
512 | { | ||
513 | if (!sii8620_is_mhl3(ctx)) | ||
514 | return; | ||
515 | |||
516 | sii8620_write(ctx, REG_FCGC, | ||
517 | BIT_FCGC_HSIC_HOSTMODE | BIT_FCGC_HSIC_ENABLE); | ||
518 | sii8620_setbits(ctx, REG_HRXCTRL3, | ||
519 | BIT_HRXCTRL3_HRX_STAY_RESET | BIT_HRXCTRL3_STATUS_EN, ~0); | ||
520 | sii8620_setbits(ctx, REG_TTXNUMB, MSK_TTXNUMB_TTX_NUMBPS, 4); | ||
521 | sii8620_setbits(ctx, REG_TRXCTRL, BIT_TRXCTRL_TRX_FROM_SE_COC, ~0); | ||
522 | sii8620_setbits(ctx, REG_HTXCTRL, BIT_HTXCTRL_HTX_DRVCONN1, 0); | ||
523 | sii8620_setbits(ctx, REG_KEEPER, MSK_KEEPER_MODE, VAL_KEEPER_MODE_HOST); | ||
524 | sii8620_write_seq_static(ctx, | ||
525 | REG_TDMLLCTL, 0, | ||
526 | REG_UTSRST, BIT_UTSRST_HRX_SRST | BIT_UTSRST_HTX_SRST | | ||
527 | BIT_UTSRST_KEEPER_SRST | BIT_UTSRST_FC_SRST, | ||
528 | REG_UTSRST, BIT_UTSRST_HRX_SRST | BIT_UTSRST_HTX_SRST, | ||
529 | REG_HRXINTL, 0xff, | ||
530 | REG_HRXINTH, 0xff, | ||
531 | REG_TTXINTL, 0xff, | ||
532 | REG_TTXINTH, 0xff, | ||
533 | REG_TRXINTL, 0xff, | ||
534 | REG_TRXINTH, 0xff, | ||
535 | REG_HTXINTL, 0xff, | ||
536 | REG_HTXINTH, 0xff, | ||
537 | REG_FCINTR0, 0xff, | ||
538 | REG_FCINTR1, 0xff, | ||
539 | REG_FCINTR2, 0xff, | ||
540 | REG_FCINTR3, 0xff, | ||
541 | REG_FCINTR4, 0xff, | ||
542 | REG_FCINTR5, 0xff, | ||
543 | REG_FCINTR6, 0xff, | ||
544 | REG_FCINTR7, 0xff | ||
545 | ); | ||
546 | } | ||
547 | |||
548 | static void sii8620_edid_read(struct sii8620 *ctx, int ret) | ||
549 | { | ||
550 | if (ret < 0) | ||
551 | return; | ||
552 | |||
553 | sii8620_set_upstream_edid(ctx); | ||
554 | sii8620_hsic_init(ctx); | ||
555 | sii8620_enable_hpd(ctx); | ||
556 | } | ||
557 | |||
558 | static void sii8620_mr_devcap(struct sii8620 *ctx) | 518 | static void sii8620_mr_devcap(struct sii8620 *ctx) |
559 | { | 519 | { |
560 | u8 dcap[MHL_DCAP_SIZE]; | 520 | u8 dcap[MHL_DCAP_SIZE]; |
@@ -570,6 +530,8 @@ static void sii8620_mr_devcap(struct sii8620 *ctx) | |||
570 | dcap[MHL_DCAP_ADOPTER_ID_H], dcap[MHL_DCAP_ADOPTER_ID_L], | 530 | dcap[MHL_DCAP_ADOPTER_ID_H], dcap[MHL_DCAP_ADOPTER_ID_L], |
571 | dcap[MHL_DCAP_DEVICE_ID_H], dcap[MHL_DCAP_DEVICE_ID_L]); | 531 | dcap[MHL_DCAP_DEVICE_ID_H], dcap[MHL_DCAP_DEVICE_ID_L]); |
572 | sii8620_update_array(ctx->devcap, dcap, MHL_DCAP_SIZE); | 532 | sii8620_update_array(ctx->devcap, dcap, MHL_DCAP_SIZE); |
533 | ctx->devcap_read = true; | ||
534 | sii8620_identify_sink(ctx); | ||
573 | } | 535 | } |
574 | 536 | ||
575 | static void sii8620_mr_xdevcap(struct sii8620 *ctx) | 537 | static void sii8620_mr_xdevcap(struct sii8620 *ctx) |
@@ -807,6 +769,7 @@ static void sii8620_burst_rx_all(struct sii8620 *ctx) | |||
807 | static void sii8620_fetch_edid(struct sii8620 *ctx) | 769 | static void sii8620_fetch_edid(struct sii8620 *ctx) |
808 | { | 770 | { |
809 | u8 lm_ddc, ddc_cmd, int3, cbus; | 771 | u8 lm_ddc, ddc_cmd, int3, cbus; |
772 | unsigned long timeout; | ||
810 | int fetched, i; | 773 | int fetched, i; |
811 | int edid_len = EDID_LENGTH; | 774 | int edid_len = EDID_LENGTH; |
812 | u8 *edid; | 775 | u8 *edid; |
@@ -856,23 +819,31 @@ static void sii8620_fetch_edid(struct sii8620 *ctx) | |||
856 | REG_DDC_CMD, ddc_cmd | VAL_DDC_CMD_ENH_DDC_READ_NO_ACK | 819 | REG_DDC_CMD, ddc_cmd | VAL_DDC_CMD_ENH_DDC_READ_NO_ACK |
857 | ); | 820 | ); |
858 | 821 | ||
859 | do { | 822 | int3 = 0; |
860 | int3 = sii8620_readb(ctx, REG_INTR3); | 823 | timeout = jiffies + msecs_to_jiffies(200); |
824 | for (;;) { | ||
861 | cbus = sii8620_readb(ctx, REG_CBUS_STATUS); | 825 | cbus = sii8620_readb(ctx, REG_CBUS_STATUS); |
862 | 826 | if (~cbus & BIT_CBUS_STATUS_CBUS_CONNECTED) { | |
863 | if (int3 & BIT_DDC_CMD_DONE) | 827 | kfree(edid); |
864 | break; | 828 | edid = NULL; |
865 | 829 | goto end; | |
866 | if (!(cbus & BIT_CBUS_STATUS_CBUS_CONNECTED)) { | 830 | } |
831 | if (int3 & BIT_DDC_CMD_DONE) { | ||
832 | if (sii8620_readb(ctx, REG_DDC_DOUT_CNT) | ||
833 | >= FETCH_SIZE) | ||
834 | break; | ||
835 | } else { | ||
836 | int3 = sii8620_readb(ctx, REG_INTR3); | ||
837 | } | ||
838 | if (time_is_before_jiffies(timeout)) { | ||
839 | ctx->error = -ETIMEDOUT; | ||
840 | dev_err(ctx->dev, "timeout during EDID read\n"); | ||
867 | kfree(edid); | 841 | kfree(edid); |
868 | edid = NULL; | 842 | edid = NULL; |
869 | goto end; | 843 | goto end; |
870 | } | 844 | } |
871 | } while (1); | ||
872 | |||
873 | sii8620_readb(ctx, REG_DDC_STATUS); | ||
874 | while (sii8620_readb(ctx, REG_DDC_DOUT_CNT) < FETCH_SIZE) | ||
875 | usleep_range(10, 20); | 845 | usleep_range(10, 20); |
846 | } | ||
876 | 847 | ||
877 | sii8620_read_buf(ctx, REG_DDC_DATA, edid + fetched, FETCH_SIZE); | 848 | sii8620_read_buf(ctx, REG_DDC_DATA, edid + fetched, FETCH_SIZE); |
878 | if (fetched + FETCH_SIZE == EDID_LENGTH) { | 849 | if (fetched + FETCH_SIZE == EDID_LENGTH) { |
@@ -971,8 +942,17 @@ static int sii8620_hw_on(struct sii8620 *ctx) | |||
971 | ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies); | 942 | ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies); |
972 | if (ret) | 943 | if (ret) |
973 | return ret; | 944 | return ret; |
945 | |||
974 | usleep_range(10000, 20000); | 946 | usleep_range(10000, 20000); |
975 | return clk_prepare_enable(ctx->clk_xtal); | 947 | ret = clk_prepare_enable(ctx->clk_xtal); |
948 | if (ret) | ||
949 | return ret; | ||
950 | |||
951 | msleep(100); | ||
952 | gpiod_set_value(ctx->gpio_reset, 0); | ||
953 | msleep(100); | ||
954 | |||
955 | return 0; | ||
976 | } | 956 | } |
977 | 957 | ||
978 | static int sii8620_hw_off(struct sii8620 *ctx) | 958 | static int sii8620_hw_off(struct sii8620 *ctx) |
@@ -982,17 +962,6 @@ static int sii8620_hw_off(struct sii8620 *ctx) | |||
982 | return regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); | 962 | return regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); |
983 | } | 963 | } |
984 | 964 | ||
985 | static void sii8620_hw_reset(struct sii8620 *ctx) | ||
986 | { | ||
987 | usleep_range(10000, 20000); | ||
988 | gpiod_set_value(ctx->gpio_reset, 0); | ||
989 | usleep_range(5000, 20000); | ||
990 | gpiod_set_value(ctx->gpio_reset, 1); | ||
991 | usleep_range(10000, 20000); | ||
992 | gpiod_set_value(ctx->gpio_reset, 0); | ||
993 | msleep(300); | ||
994 | } | ||
995 | |||
996 | static void sii8620_cbus_reset(struct sii8620 *ctx) | 965 | static void sii8620_cbus_reset(struct sii8620 *ctx) |
997 | { | 966 | { |
998 | sii8620_write(ctx, REG_PWD_SRST, BIT_PWD_SRST_CBUS_RST | 967 | sii8620_write(ctx, REG_PWD_SRST, BIT_PWD_SRST_CBUS_RST |
@@ -1048,20 +1017,11 @@ static void sii8620_stop_video(struct sii8620 *ctx) | |||
1048 | 1017 | ||
1049 | static void sii8620_set_format(struct sii8620 *ctx) | 1018 | static void sii8620_set_format(struct sii8620 *ctx) |
1050 | { | 1019 | { |
1051 | u8 out_fmt; | ||
1052 | |||
1053 | if (sii8620_is_mhl3(ctx)) { | 1020 | if (sii8620_is_mhl3(ctx)) { |
1054 | sii8620_setbits(ctx, REG_M3_P0CTRL, | 1021 | sii8620_setbits(ctx, REG_M3_P0CTRL, |
1055 | BIT_M3_P0CTRL_MHL3_P0_PIXEL_MODE_PACKED, | 1022 | BIT_M3_P0CTRL_MHL3_P0_PIXEL_MODE_PACKED, |
1056 | ctx->use_packed_pixel ? ~0 : 0); | 1023 | ctx->use_packed_pixel ? ~0 : 0); |
1057 | } else { | 1024 | } else { |
1058 | if (ctx->use_packed_pixel) | ||
1059 | sii8620_write_seq_static(ctx, | ||
1060 | REG_VID_MODE, BIT_VID_MODE_M1080P, | ||
1061 | REG_MHL_TOP_CTL, BIT_MHL_TOP_CTL_MHL_PP_SEL | 1, | ||
1062 | REG_MHLTX_CTL6, 0x60 | ||
1063 | ); | ||
1064 | else | ||
1065 | sii8620_write_seq_static(ctx, | 1025 | sii8620_write_seq_static(ctx, |
1066 | REG_VID_MODE, 0, | 1026 | REG_VID_MODE, 0, |
1067 | REG_MHL_TOP_CTL, 1, | 1027 | REG_MHL_TOP_CTL, 1, |
@@ -1069,15 +1029,9 @@ static void sii8620_set_format(struct sii8620 *ctx) | |||
1069 | ); | 1029 | ); |
1070 | } | 1030 | } |
1071 | 1031 | ||
1072 | if (ctx->use_packed_pixel) | ||
1073 | out_fmt = VAL_TPI_FORMAT(YCBCR422, FULL) | | ||
1074 | BIT_TPI_OUTPUT_CSCMODE709; | ||
1075 | else | ||
1076 | out_fmt = VAL_TPI_FORMAT(RGB, FULL); | ||
1077 | |||
1078 | sii8620_write_seq(ctx, | 1032 | sii8620_write_seq(ctx, |
1079 | REG_TPI_INPUT, VAL_TPI_FORMAT(RGB, FULL), | 1033 | REG_TPI_INPUT, VAL_TPI_FORMAT(RGB, FULL), |
1080 | REG_TPI_OUTPUT, out_fmt, | 1034 | REG_TPI_OUTPUT, VAL_TPI_FORMAT(RGB, FULL), |
1081 | ); | 1035 | ); |
1082 | } | 1036 | } |
1083 | 1037 | ||
@@ -1216,7 +1170,7 @@ static void sii8620_start_video(struct sii8620 *ctx) | |||
1216 | int clk = ctx->pixel_clock * (ctx->use_packed_pixel ? 2 : 3); | 1170 | int clk = ctx->pixel_clock * (ctx->use_packed_pixel ? 2 : 3); |
1217 | int i; | 1171 | int i; |
1218 | 1172 | ||
1219 | for (i = 0; i < ARRAY_SIZE(clk_spec); ++i) | 1173 | for (i = 0; i < ARRAY_SIZE(clk_spec) - 1; ++i) |
1220 | if (clk < clk_spec[i].max_clk) | 1174 | if (clk < clk_spec[i].max_clk) |
1221 | break; | 1175 | break; |
1222 | 1176 | ||
@@ -1534,6 +1488,16 @@ static void sii8620_set_mode(struct sii8620 *ctx, enum sii8620_mode mode) | |||
1534 | ); | 1488 | ); |
1535 | } | 1489 | } |
1536 | 1490 | ||
1491 | static void sii8620_hpd_unplugged(struct sii8620 *ctx) | ||
1492 | { | ||
1493 | sii8620_disable_hpd(ctx); | ||
1494 | ctx->sink_type = SINK_NONE; | ||
1495 | ctx->sink_detected = false; | ||
1496 | ctx->feature_complete = false; | ||
1497 | kfree(ctx->edid); | ||
1498 | ctx->edid = NULL; | ||
1499 | } | ||
1500 | |||
1537 | static void sii8620_disconnect(struct sii8620 *ctx) | 1501 | static void sii8620_disconnect(struct sii8620 *ctx) |
1538 | { | 1502 | { |
1539 | sii8620_disable_gen2_write_burst(ctx); | 1503 | sii8620_disable_gen2_write_burst(ctx); |
@@ -1561,7 +1525,7 @@ static void sii8620_disconnect(struct sii8620 *ctx) | |||
1561 | REG_MHL_DP_CTL6, 0x2A, | 1525 | REG_MHL_DP_CTL6, 0x2A, |
1562 | REG_MHL_DP_CTL7, 0x03 | 1526 | REG_MHL_DP_CTL7, 0x03 |
1563 | ); | 1527 | ); |
1564 | sii8620_disable_hpd(ctx); | 1528 | sii8620_hpd_unplugged(ctx); |
1565 | sii8620_write_seq_static(ctx, | 1529 | sii8620_write_seq_static(ctx, |
1566 | REG_M3_CTRL, VAL_M3_CTRL_MHL3_VALUE, | 1530 | REG_M3_CTRL, VAL_M3_CTRL_MHL3_VALUE, |
1567 | REG_MHL_COC_CTL1, 0x07, | 1531 | REG_MHL_COC_CTL1, 0x07, |
@@ -1609,10 +1573,8 @@ static void sii8620_disconnect(struct sii8620 *ctx) | |||
1609 | memset(ctx->xstat, 0, sizeof(ctx->xstat)); | 1573 | memset(ctx->xstat, 0, sizeof(ctx->xstat)); |
1610 | memset(ctx->devcap, 0, sizeof(ctx->devcap)); | 1574 | memset(ctx->devcap, 0, sizeof(ctx->devcap)); |
1611 | memset(ctx->xdevcap, 0, sizeof(ctx->xdevcap)); | 1575 | memset(ctx->xdevcap, 0, sizeof(ctx->xdevcap)); |
1576 | ctx->devcap_read = false; | ||
1612 | ctx->cbus_status = 0; | 1577 | ctx->cbus_status = 0; |
1613 | ctx->sink_type = SINK_NONE; | ||
1614 | kfree(ctx->edid); | ||
1615 | ctx->edid = NULL; | ||
1616 | sii8620_mt_cleanup(ctx); | 1578 | sii8620_mt_cleanup(ctx); |
1617 | } | 1579 | } |
1618 | 1580 | ||
@@ -1703,9 +1665,6 @@ static void sii8620_status_changed_path(struct sii8620 *ctx) | |||
1703 | sii8620_mt_write_stat(ctx, MHL_DST_REG(LINK_MODE), | 1665 | sii8620_mt_write_stat(ctx, MHL_DST_REG(LINK_MODE), |
1704 | MHL_DST_LM_CLK_MODE_NORMAL | 1666 | MHL_DST_LM_CLK_MODE_NORMAL |
1705 | | MHL_DST_LM_PATH_ENABLED); | 1667 | | MHL_DST_LM_PATH_ENABLED); |
1706 | if (!sii8620_is_mhl3(ctx)) | ||
1707 | sii8620_mt_read_devcap(ctx, false); | ||
1708 | sii8620_mt_set_cont(ctx, sii8620_sink_detected); | ||
1709 | } else { | 1668 | } else { |
1710 | sii8620_mt_write_stat(ctx, MHL_DST_REG(LINK_MODE), | 1669 | sii8620_mt_write_stat(ctx, MHL_DST_REG(LINK_MODE), |
1711 | MHL_DST_LM_CLK_MODE_NORMAL); | 1670 | MHL_DST_LM_CLK_MODE_NORMAL); |
@@ -1722,9 +1681,14 @@ static void sii8620_msc_mr_write_stat(struct sii8620 *ctx) | |||
1722 | sii8620_update_array(ctx->stat, st, MHL_DST_SIZE); | 1681 | sii8620_update_array(ctx->stat, st, MHL_DST_SIZE); |
1723 | sii8620_update_array(ctx->xstat, xst, MHL_XDS_SIZE); | 1682 | sii8620_update_array(ctx->xstat, xst, MHL_XDS_SIZE); |
1724 | 1683 | ||
1725 | if (ctx->stat[MHL_DST_CONNECTED_RDY] & MHL_DST_CONN_DCAP_RDY) | 1684 | if (ctx->stat[MHL_DST_CONNECTED_RDY] & st[MHL_DST_CONNECTED_RDY] & |
1685 | MHL_DST_CONN_DCAP_RDY) { | ||
1726 | sii8620_status_dcap_ready(ctx); | 1686 | sii8620_status_dcap_ready(ctx); |
1727 | 1687 | ||
1688 | if (!sii8620_is_mhl3(ctx)) | ||
1689 | sii8620_mt_read_devcap(ctx, false); | ||
1690 | } | ||
1691 | |||
1728 | if (st[MHL_DST_LINK_MODE] & MHL_DST_LM_PATH_ENABLED) | 1692 | if (st[MHL_DST_LINK_MODE] & MHL_DST_LM_PATH_ENABLED) |
1729 | sii8620_status_changed_path(ctx); | 1693 | sii8620_status_changed_path(ctx); |
1730 | } | 1694 | } |
@@ -1808,8 +1772,11 @@ static void sii8620_msc_mr_set_int(struct sii8620 *ctx) | |||
1808 | } | 1772 | } |
1809 | if (ints[MHL_INT_RCHANGE] & MHL_INT_RC_FEAT_REQ) | 1773 | if (ints[MHL_INT_RCHANGE] & MHL_INT_RC_FEAT_REQ) |
1810 | sii8620_send_features(ctx); | 1774 | sii8620_send_features(ctx); |
1811 | if (ints[MHL_INT_RCHANGE] & MHL_INT_RC_FEAT_COMPLETE) | 1775 | if (ints[MHL_INT_RCHANGE] & MHL_INT_RC_FEAT_COMPLETE) { |
1812 | sii8620_edid_read(ctx, 0); | 1776 | ctx->feature_complete = true; |
1777 | if (ctx->edid) | ||
1778 | sii8620_enable_hpd(ctx); | ||
1779 | } | ||
1813 | } | 1780 | } |
1814 | 1781 | ||
1815 | static struct sii8620_mt_msg *sii8620_msc_msg_first(struct sii8620 *ctx) | 1782 | static struct sii8620_mt_msg *sii8620_msc_msg_first(struct sii8620 *ctx) |
@@ -1884,6 +1851,15 @@ static void sii8620_irq_msc(struct sii8620 *ctx) | |||
1884 | if (stat & BIT_CBUS_MSC_MR_WRITE_STAT) | 1851 | if (stat & BIT_CBUS_MSC_MR_WRITE_STAT) |
1885 | sii8620_msc_mr_write_stat(ctx); | 1852 | sii8620_msc_mr_write_stat(ctx); |
1886 | 1853 | ||
1854 | if (stat & BIT_CBUS_HPD_CHG) { | ||
1855 | if (ctx->cbus_status & BIT_CBUS_STATUS_CBUS_HPD) { | ||
1856 | ctx->sink_detected = true; | ||
1857 | sii8620_identify_sink(ctx); | ||
1858 | } else { | ||
1859 | sii8620_hpd_unplugged(ctx); | ||
1860 | } | ||
1861 | } | ||
1862 | |||
1887 | if (stat & BIT_CBUS_MSC_MR_SET_INT) | 1863 | if (stat & BIT_CBUS_MSC_MR_SET_INT) |
1888 | sii8620_msc_mr_set_int(ctx); | 1864 | sii8620_msc_mr_set_int(ctx); |
1889 | 1865 | ||
@@ -1931,14 +1907,6 @@ static void sii8620_irq_edid(struct sii8620 *ctx) | |||
1931 | ctx->mt_state = MT_STATE_DONE; | 1907 | ctx->mt_state = MT_STATE_DONE; |
1932 | } | 1908 | } |
1933 | 1909 | ||
1934 | static void sii8620_scdt_high(struct sii8620 *ctx) | ||
1935 | { | ||
1936 | sii8620_write_seq_static(ctx, | ||
1937 | REG_INTR8_MASK, BIT_CEA_NEW_AVI | BIT_CEA_NEW_VSI, | ||
1938 | REG_TPI_SC, BIT_TPI_SC_TPI_OUTPUT_MODE_0_HDMI, | ||
1939 | ); | ||
1940 | } | ||
1941 | |||
1942 | static void sii8620_irq_scdt(struct sii8620 *ctx) | 1910 | static void sii8620_irq_scdt(struct sii8620 *ctx) |
1943 | { | 1911 | { |
1944 | u8 stat = sii8620_readb(ctx, REG_INTR5); | 1912 | u8 stat = sii8620_readb(ctx, REG_INTR5); |
@@ -1946,53 +1914,13 @@ static void sii8620_irq_scdt(struct sii8620 *ctx) | |||
1946 | if (stat & BIT_INTR_SCDT_CHANGE) { | 1914 | if (stat & BIT_INTR_SCDT_CHANGE) { |
1947 | u8 cstat = sii8620_readb(ctx, REG_TMDS_CSTAT_P3); | 1915 | u8 cstat = sii8620_readb(ctx, REG_TMDS_CSTAT_P3); |
1948 | 1916 | ||
1949 | if (cstat & BIT_TMDS_CSTAT_P3_SCDT) { | 1917 | if (cstat & BIT_TMDS_CSTAT_P3_SCDT) |
1950 | if (ctx->sink_type == SINK_HDMI) | 1918 | sii8620_start_video(ctx); |
1951 | /* enable infoframe interrupt */ | ||
1952 | sii8620_scdt_high(ctx); | ||
1953 | else | ||
1954 | sii8620_start_video(ctx); | ||
1955 | } | ||
1956 | } | 1919 | } |
1957 | 1920 | ||
1958 | sii8620_write(ctx, REG_INTR5, stat); | 1921 | sii8620_write(ctx, REG_INTR5, stat); |
1959 | } | 1922 | } |
1960 | 1923 | ||
1961 | static void sii8620_new_vsi(struct sii8620 *ctx) | ||
1962 | { | ||
1963 | u8 vsif[11]; | ||
1964 | |||
1965 | sii8620_write(ctx, REG_RX_HDMI_CTRL2, | ||
1966 | VAL_RX_HDMI_CTRL2_DEFVAL | | ||
1967 | BIT_RX_HDMI_CTRL2_VSI_MON_SEL_VSI); | ||
1968 | sii8620_read_buf(ctx, REG_RX_HDMI_MON_PKT_HEADER1, vsif, | ||
1969 | ARRAY_SIZE(vsif)); | ||
1970 | } | ||
1971 | |||
1972 | static void sii8620_new_avi(struct sii8620 *ctx) | ||
1973 | { | ||
1974 | sii8620_write(ctx, REG_RX_HDMI_CTRL2, VAL_RX_HDMI_CTRL2_DEFVAL); | ||
1975 | sii8620_read_buf(ctx, REG_RX_HDMI_MON_PKT_HEADER1, ctx->avif, | ||
1976 | ARRAY_SIZE(ctx->avif)); | ||
1977 | } | ||
1978 | |||
1979 | static void sii8620_irq_infr(struct sii8620 *ctx) | ||
1980 | { | ||
1981 | u8 stat = sii8620_readb(ctx, REG_INTR8) | ||
1982 | & (BIT_CEA_NEW_VSI | BIT_CEA_NEW_AVI); | ||
1983 | |||
1984 | sii8620_write(ctx, REG_INTR8, stat); | ||
1985 | |||
1986 | if (stat & BIT_CEA_NEW_VSI) | ||
1987 | sii8620_new_vsi(ctx); | ||
1988 | |||
1989 | if (stat & BIT_CEA_NEW_AVI) | ||
1990 | sii8620_new_avi(ctx); | ||
1991 | |||
1992 | if (stat & (BIT_CEA_NEW_VSI | BIT_CEA_NEW_AVI)) | ||
1993 | sii8620_start_video(ctx); | ||
1994 | } | ||
1995 | |||
1996 | static void sii8620_got_xdevcap(struct sii8620 *ctx, int ret) | 1924 | static void sii8620_got_xdevcap(struct sii8620 *ctx, int ret) |
1997 | { | 1925 | { |
1998 | if (ret < 0) | 1926 | if (ret < 0) |
@@ -2043,11 +1971,11 @@ static void sii8620_irq_ddc(struct sii8620 *ctx) | |||
2043 | 1971 | ||
2044 | if (stat & BIT_DDC_CMD_DONE) { | 1972 | if (stat & BIT_DDC_CMD_DONE) { |
2045 | sii8620_write(ctx, REG_INTR3_MASK, 0); | 1973 | sii8620_write(ctx, REG_INTR3_MASK, 0); |
2046 | if (sii8620_is_mhl3(ctx)) | 1974 | if (sii8620_is_mhl3(ctx) && !ctx->feature_complete) |
2047 | sii8620_mt_set_int(ctx, MHL_INT_REG(RCHANGE), | 1975 | sii8620_mt_set_int(ctx, MHL_INT_REG(RCHANGE), |
2048 | MHL_INT_RC_FEAT_REQ); | 1976 | MHL_INT_RC_FEAT_REQ); |
2049 | else | 1977 | else |
2050 | sii8620_edid_read(ctx, 0); | 1978 | sii8620_enable_hpd(ctx); |
2051 | } | 1979 | } |
2052 | sii8620_write(ctx, REG_INTR3, stat); | 1980 | sii8620_write(ctx, REG_INTR3, stat); |
2053 | } | 1981 | } |
@@ -2074,7 +2002,6 @@ static irqreturn_t sii8620_irq_thread(int irq, void *data) | |||
2074 | { BIT_FAST_INTR_STAT_EDID, sii8620_irq_edid }, | 2002 | { BIT_FAST_INTR_STAT_EDID, sii8620_irq_edid }, |
2075 | { BIT_FAST_INTR_STAT_DDC, sii8620_irq_ddc }, | 2003 | { BIT_FAST_INTR_STAT_DDC, sii8620_irq_ddc }, |
2076 | { BIT_FAST_INTR_STAT_SCDT, sii8620_irq_scdt }, | 2004 | { BIT_FAST_INTR_STAT_SCDT, sii8620_irq_scdt }, |
2077 | { BIT_FAST_INTR_STAT_INFR, sii8620_irq_infr }, | ||
2078 | }; | 2005 | }; |
2079 | struct sii8620 *ctx = data; | 2006 | struct sii8620 *ctx = data; |
2080 | u8 stats[LEN_FAST_INTR_STAT]; | 2007 | u8 stats[LEN_FAST_INTR_STAT]; |
@@ -2112,7 +2039,6 @@ static void sii8620_cable_in(struct sii8620 *ctx) | |||
2112 | dev_err(dev, "Error powering on, %d.\n", ret); | 2039 | dev_err(dev, "Error powering on, %d.\n", ret); |
2113 | return; | 2040 | return; |
2114 | } | 2041 | } |
2115 | sii8620_hw_reset(ctx); | ||
2116 | 2042 | ||
2117 | sii8620_read_buf(ctx, REG_VND_IDL, ver, ARRAY_SIZE(ver)); | 2043 | sii8620_read_buf(ctx, REG_VND_IDL, ver, ARRAY_SIZE(ver)); |
2118 | ret = sii8620_clear_error(ctx); | 2044 | ret = sii8620_clear_error(ctx); |
@@ -2268,17 +2194,43 @@ static void sii8620_detach(struct drm_bridge *bridge) | |||
2268 | rc_unregister_device(ctx->rc_dev); | 2194 | rc_unregister_device(ctx->rc_dev); |
2269 | } | 2195 | } |
2270 | 2196 | ||
2197 | static int sii8620_is_packing_required(struct sii8620 *ctx, | ||
2198 | const struct drm_display_mode *mode) | ||
2199 | { | ||
2200 | int max_pclk, max_pclk_pp_mode; | ||
2201 | |||
2202 | if (sii8620_is_mhl3(ctx)) { | ||
2203 | max_pclk = MHL3_MAX_PCLK; | ||
2204 | max_pclk_pp_mode = MHL3_MAX_PCLK_PP_MODE; | ||
2205 | } else { | ||
2206 | max_pclk = MHL1_MAX_PCLK; | ||
2207 | max_pclk_pp_mode = MHL1_MAX_PCLK_PP_MODE; | ||
2208 | } | ||
2209 | |||
2210 | if (mode->clock < max_pclk) | ||
2211 | return 0; | ||
2212 | else if (mode->clock < max_pclk_pp_mode) | ||
2213 | return 1; | ||
2214 | else | ||
2215 | return -1; | ||
2216 | } | ||
2217 | |||
2271 | static enum drm_mode_status sii8620_mode_valid(struct drm_bridge *bridge, | 2218 | static enum drm_mode_status sii8620_mode_valid(struct drm_bridge *bridge, |
2272 | const struct drm_display_mode *mode) | 2219 | const struct drm_display_mode *mode) |
2273 | { | 2220 | { |
2274 | struct sii8620 *ctx = bridge_to_sii8620(bridge); | 2221 | struct sii8620 *ctx = bridge_to_sii8620(bridge); |
2222 | int pack_required = sii8620_is_packing_required(ctx, mode); | ||
2275 | bool can_pack = ctx->devcap[MHL_DCAP_VID_LINK_MODE] & | 2223 | bool can_pack = ctx->devcap[MHL_DCAP_VID_LINK_MODE] & |
2276 | MHL_DCAP_VID_LINK_PPIXEL; | 2224 | MHL_DCAP_VID_LINK_PPIXEL; |
2277 | unsigned int max_pclk = sii8620_is_mhl3(ctx) ? MHL3_MAX_LCLK : | ||
2278 | MHL1_MAX_LCLK; | ||
2279 | max_pclk /= can_pack ? 2 : 3; | ||
2280 | 2225 | ||
2281 | return (mode->clock > max_pclk) ? MODE_CLOCK_HIGH : MODE_OK; | 2226 | switch (pack_required) { |
2227 | case 0: | ||
2228 | return MODE_OK; | ||
2229 | case 1: | ||
2230 | return (can_pack) ? MODE_OK : MODE_CLOCK_HIGH; | ||
2231 | default: | ||
2232 | return MODE_CLOCK_HIGH; | ||
2233 | } | ||
2282 | } | 2234 | } |
2283 | 2235 | ||
2284 | static bool sii8620_mode_fixup(struct drm_bridge *bridge, | 2236 | static bool sii8620_mode_fixup(struct drm_bridge *bridge, |
@@ -2286,43 +2238,16 @@ static bool sii8620_mode_fixup(struct drm_bridge *bridge, | |||
2286 | struct drm_display_mode *adjusted_mode) | 2238 | struct drm_display_mode *adjusted_mode) |
2287 | { | 2239 | { |
2288 | struct sii8620 *ctx = bridge_to_sii8620(bridge); | 2240 | struct sii8620 *ctx = bridge_to_sii8620(bridge); |
2289 | int max_lclk; | ||
2290 | bool ret = true; | ||
2291 | 2241 | ||
2292 | mutex_lock(&ctx->lock); | 2242 | mutex_lock(&ctx->lock); |
2293 | 2243 | ||
2294 | max_lclk = sii8620_is_mhl3(ctx) ? MHL3_MAX_LCLK : MHL1_MAX_LCLK; | 2244 | ctx->use_packed_pixel = sii8620_is_packing_required(ctx, adjusted_mode); |
2295 | if (max_lclk > 3 * adjusted_mode->clock) { | 2245 | ctx->video_code = drm_match_cea_mode(adjusted_mode); |
2296 | ctx->use_packed_pixel = 0; | 2246 | ctx->pixel_clock = adjusted_mode->clock; |
2297 | goto end; | 2247 | |
2298 | } | ||
2299 | if ((ctx->devcap[MHL_DCAP_VID_LINK_MODE] & MHL_DCAP_VID_LINK_PPIXEL) && | ||
2300 | max_lclk > 2 * adjusted_mode->clock) { | ||
2301 | ctx->use_packed_pixel = 1; | ||
2302 | goto end; | ||
2303 | } | ||
2304 | ret = false; | ||
2305 | end: | ||
2306 | if (ret) { | ||
2307 | u8 vic = drm_match_cea_mode(adjusted_mode); | ||
2308 | |||
2309 | if (!vic) { | ||
2310 | union hdmi_infoframe frm; | ||
2311 | u8 mhl_vic[] = { 0, 95, 94, 93, 98 }; | ||
2312 | |||
2313 | /* FIXME: We need the connector here */ | ||
2314 | drm_hdmi_vendor_infoframe_from_display_mode( | ||
2315 | &frm.vendor.hdmi, NULL, adjusted_mode); | ||
2316 | vic = frm.vendor.hdmi.vic; | ||
2317 | if (vic >= ARRAY_SIZE(mhl_vic)) | ||
2318 | vic = 0; | ||
2319 | vic = mhl_vic[vic]; | ||
2320 | } | ||
2321 | ctx->video_code = vic; | ||
2322 | ctx->pixel_clock = adjusted_mode->clock; | ||
2323 | } | ||
2324 | mutex_unlock(&ctx->lock); | 2248 | mutex_unlock(&ctx->lock); |
2325 | return ret; | 2249 | |
2250 | return true; | ||
2326 | } | 2251 | } |
2327 | 2252 | ||
2328 | static const struct drm_bridge_funcs sii8620_bridge_funcs = { | 2253 | static const struct drm_bridge_funcs sii8620_bridge_funcs = { |
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c index 08747fc3ee71..8232b39e16ca 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c | |||
@@ -17,7 +17,6 @@ | |||
17 | #include <drm/drm_encoder.h> | 17 | #include <drm/drm_encoder.h> |
18 | #include <drm/drm_modes.h> | 18 | #include <drm/drm_modes.h> |
19 | #include <drm/drm_of.h> | 19 | #include <drm/drm_of.h> |
20 | #include <drm/drm_panel.h> | ||
21 | 20 | ||
22 | #include <uapi/drm/drm_mode.h> | 21 | #include <uapi/drm/drm_mode.h> |
23 | 22 | ||
@@ -418,9 +417,6 @@ static void sun4i_tcon0_mode_set_lvds(struct sun4i_tcon *tcon, | |||
418 | static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon, | 417 | static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon, |
419 | const struct drm_display_mode *mode) | 418 | const struct drm_display_mode *mode) |
420 | { | 419 | { |
421 | struct drm_panel *panel = tcon->panel; | ||
422 | struct drm_connector *connector = panel->connector; | ||
423 | struct drm_display_info display_info = connector->display_info; | ||
424 | unsigned int bp, hsync, vsync; | 420 | unsigned int bp, hsync, vsync; |
425 | u8 clk_delay; | 421 | u8 clk_delay; |
426 | u32 val = 0; | 422 | u32 val = 0; |
@@ -478,27 +474,6 @@ static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon, | |||
478 | if (mode->flags & DRM_MODE_FLAG_PVSYNC) | 474 | if (mode->flags & DRM_MODE_FLAG_PVSYNC) |
479 | val |= SUN4I_TCON0_IO_POL_VSYNC_POSITIVE; | 475 | val |= SUN4I_TCON0_IO_POL_VSYNC_POSITIVE; |
480 | 476 | ||
481 | /* | ||
482 | * On A20 and similar SoCs, the only way to achieve Positive Edge | ||
483 | * (Rising Edge), is setting dclk clock phase to 2/3(240°). | ||
484 | * By default TCON works in Negative Edge(Falling Edge), | ||
485 | * this is why phase is set to 0 in that case. | ||
486 | * Unfortunately there's no way to logically invert dclk through | ||
487 | * IO_POL register. | ||
488 | * The only acceptable way to work, triple checked with scope, | ||
489 | * is using clock phase set to 0° for Negative Edge and set to 240° | ||
490 | * for Positive Edge. | ||
491 | * On A33 and similar SoCs there would be a 90° phase option, | ||
492 | * but it divides also dclk by 2. | ||
493 | * Following code is a way to avoid quirks all around TCON | ||
494 | * and DOTCLOCK drivers. | ||
495 | */ | ||
496 | if (display_info.bus_flags & DRM_BUS_FLAG_PIXDATA_POSEDGE) | ||
497 | clk_set_phase(tcon->dclk, 240); | ||
498 | |||
499 | if (display_info.bus_flags & DRM_BUS_FLAG_PIXDATA_NEGEDGE) | ||
500 | clk_set_phase(tcon->dclk, 0); | ||
501 | |||
502 | regmap_update_bits(tcon->regs, SUN4I_TCON0_IO_POL_REG, | 477 | regmap_update_bits(tcon->regs, SUN4I_TCON0_IO_POL_REG, |
503 | SUN4I_TCON0_IO_POL_HSYNC_POSITIVE | SUN4I_TCON0_IO_POL_VSYNC_POSITIVE, | 478 | SUN4I_TCON0_IO_POL_HSYNC_POSITIVE | SUN4I_TCON0_IO_POL_VSYNC_POSITIVE, |
504 | val); | 479 | val); |