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); |
