diff options
Diffstat (limited to 'drivers/gpu/drm/bridge/tc358767.c')
| -rw-r--r-- | drivers/gpu/drm/bridge/tc358767.c | 73 |
1 files changed, 40 insertions, 33 deletions
diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index 8571cfd877c5..8636e7eeb731 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c | |||
| @@ -97,7 +97,7 @@ | |||
| 97 | #define DP0_ACTIVEVAL 0x0650 | 97 | #define DP0_ACTIVEVAL 0x0650 |
| 98 | #define DP0_SYNCVAL 0x0654 | 98 | #define DP0_SYNCVAL 0x0654 |
| 99 | #define DP0_MISC 0x0658 | 99 | #define DP0_MISC 0x0658 |
| 100 | #define TU_SIZE_RECOMMENDED (0x3f << 16) /* LSCLK cycles per TU */ | 100 | #define TU_SIZE_RECOMMENDED (63) /* LSCLK cycles per TU */ |
| 101 | #define BPC_6 (0 << 5) | 101 | #define BPC_6 (0 << 5) |
| 102 | #define BPC_8 (1 << 5) | 102 | #define BPC_8 (1 << 5) |
| 103 | 103 | ||
| @@ -318,7 +318,7 @@ static ssize_t tc_aux_transfer(struct drm_dp_aux *aux, | |||
| 318 | tmp = (tmp << 8) | buf[i]; | 318 | tmp = (tmp << 8) | buf[i]; |
| 319 | i++; | 319 | i++; |
| 320 | if (((i % 4) == 0) || (i == size)) { | 320 | if (((i % 4) == 0) || (i == size)) { |
| 321 | tc_write(DP0_AUXWDATA(i >> 2), tmp); | 321 | tc_write(DP0_AUXWDATA((i - 1) >> 2), tmp); |
| 322 | tmp = 0; | 322 | tmp = 0; |
| 323 | } | 323 | } |
| 324 | } | 324 | } |
| @@ -603,8 +603,15 @@ static int tc_get_display_props(struct tc_data *tc) | |||
| 603 | ret = drm_dp_link_probe(&tc->aux, &tc->link.base); | 603 | ret = drm_dp_link_probe(&tc->aux, &tc->link.base); |
| 604 | if (ret < 0) | 604 | if (ret < 0) |
| 605 | goto err_dpcd_read; | 605 | goto err_dpcd_read; |
| 606 | if ((tc->link.base.rate != 162000) && (tc->link.base.rate != 270000)) | 606 | if (tc->link.base.rate != 162000 && tc->link.base.rate != 270000) { |
| 607 | goto err_dpcd_inval; | 607 | dev_dbg(tc->dev, "Falling to 2.7 Gbps rate\n"); |
| 608 | tc->link.base.rate = 270000; | ||
| 609 | } | ||
| 610 | |||
| 611 | if (tc->link.base.num_lanes > 2) { | ||
| 612 | dev_dbg(tc->dev, "Falling to 2 lanes\n"); | ||
| 613 | tc->link.base.num_lanes = 2; | ||
| 614 | } | ||
| 608 | 615 | ||
| 609 | ret = drm_dp_dpcd_readb(&tc->aux, DP_MAX_DOWNSPREAD, tmp); | 616 | ret = drm_dp_dpcd_readb(&tc->aux, DP_MAX_DOWNSPREAD, tmp); |
| 610 | if (ret < 0) | 617 | if (ret < 0) |
| @@ -637,9 +644,6 @@ static int tc_get_display_props(struct tc_data *tc) | |||
| 637 | err_dpcd_read: | 644 | err_dpcd_read: |
| 638 | dev_err(tc->dev, "failed to read DPCD: %d\n", ret); | 645 | dev_err(tc->dev, "failed to read DPCD: %d\n", ret); |
| 639 | return ret; | 646 | return ret; |
| 640 | err_dpcd_inval: | ||
| 641 | dev_err(tc->dev, "invalid DPCD\n"); | ||
| 642 | return -EINVAL; | ||
| 643 | } | 647 | } |
| 644 | 648 | ||
| 645 | static int tc_set_video_mode(struct tc_data *tc, struct drm_display_mode *mode) | 649 | static int tc_set_video_mode(struct tc_data *tc, struct drm_display_mode *mode) |
| @@ -655,6 +659,14 @@ static int tc_set_video_mode(struct tc_data *tc, struct drm_display_mode *mode) | |||
| 655 | int lower_margin = mode->vsync_start - mode->vdisplay; | 659 | int lower_margin = mode->vsync_start - mode->vdisplay; |
| 656 | int vsync_len = mode->vsync_end - mode->vsync_start; | 660 | int vsync_len = mode->vsync_end - mode->vsync_start; |
| 657 | 661 | ||
| 662 | /* | ||
| 663 | * Recommended maximum number of symbols transferred in a transfer unit: | ||
| 664 | * DIV_ROUND_UP((input active video bandwidth in bytes) * tu_size, | ||
| 665 | * (output active video bandwidth in bytes)) | ||
| 666 | * Must be less than tu_size. | ||
| 667 | */ | ||
| 668 | max_tu_symbol = TU_SIZE_RECOMMENDED - 1; | ||
| 669 | |||
| 658 | dev_dbg(tc->dev, "set mode %dx%d\n", | 670 | dev_dbg(tc->dev, "set mode %dx%d\n", |
| 659 | mode->hdisplay, mode->vdisplay); | 671 | mode->hdisplay, mode->vdisplay); |
| 660 | dev_dbg(tc->dev, "H margin %d,%d sync %d\n", | 672 | dev_dbg(tc->dev, "H margin %d,%d sync %d\n", |
| @@ -664,13 +676,18 @@ static int tc_set_video_mode(struct tc_data *tc, struct drm_display_mode *mode) | |||
| 664 | dev_dbg(tc->dev, "total: %dx%d\n", mode->htotal, mode->vtotal); | 676 | dev_dbg(tc->dev, "total: %dx%d\n", mode->htotal, mode->vtotal); |
| 665 | 677 | ||
| 666 | 678 | ||
| 667 | /* LCD Ctl Frame Size */ | 679 | /* |
| 668 | tc_write(VPCTRL0, (0x40 << 20) /* VSDELAY */ | | 680 | * LCD Ctl Frame Size |
| 681 | * datasheet is not clear of vsdelay in case of DPI | ||
| 682 | * assume we do not need any delay when DPI is a source of | ||
| 683 | * sync signals | ||
| 684 | */ | ||
| 685 | tc_write(VPCTRL0, (0 << 20) /* VSDELAY */ | | ||
| 669 | OPXLFMT_RGB888 | FRMSYNC_DISABLED | MSF_DISABLED); | 686 | OPXLFMT_RGB888 | FRMSYNC_DISABLED | MSF_DISABLED); |
| 670 | tc_write(HTIM01, (left_margin << 16) | /* H back porch */ | 687 | tc_write(HTIM01, (ALIGN(left_margin, 2) << 16) | /* H back porch */ |
| 671 | (hsync_len << 0)); /* Hsync */ | 688 | (ALIGN(hsync_len, 2) << 0)); /* Hsync */ |
| 672 | tc_write(HTIM02, (right_margin << 16) | /* H front porch */ | 689 | tc_write(HTIM02, (ALIGN(right_margin, 2) << 16) | /* H front porch */ |
| 673 | (mode->hdisplay << 0)); /* width */ | 690 | (ALIGN(mode->hdisplay, 2) << 0)); /* width */ |
| 674 | tc_write(VTIM01, (upper_margin << 16) | /* V back porch */ | 691 | tc_write(VTIM01, (upper_margin << 16) | /* V back porch */ |
| 675 | (vsync_len << 0)); /* Vsync */ | 692 | (vsync_len << 0)); /* Vsync */ |
| 676 | tc_write(VTIM02, (lower_margin << 16) | /* V front porch */ | 693 | tc_write(VTIM02, (lower_margin << 16) | /* V front porch */ |
| @@ -689,7 +706,7 @@ static int tc_set_video_mode(struct tc_data *tc, struct drm_display_mode *mode) | |||
| 689 | /* DP Main Stream Attributes */ | 706 | /* DP Main Stream Attributes */ |
| 690 | vid_sync_dly = hsync_len + left_margin + mode->hdisplay; | 707 | vid_sync_dly = hsync_len + left_margin + mode->hdisplay; |
| 691 | tc_write(DP0_VIDSYNCDELAY, | 708 | tc_write(DP0_VIDSYNCDELAY, |
| 692 | (0x003e << 16) | /* thresh_dly */ | 709 | (max_tu_symbol << 16) | /* thresh_dly */ |
| 693 | (vid_sync_dly << 0)); | 710 | (vid_sync_dly << 0)); |
| 694 | 711 | ||
| 695 | tc_write(DP0_TOTALVAL, (mode->vtotal << 16) | (mode->htotal)); | 712 | tc_write(DP0_TOTALVAL, (mode->vtotal << 16) | (mode->htotal)); |
| @@ -705,14 +722,8 @@ static int tc_set_video_mode(struct tc_data *tc, struct drm_display_mode *mode) | |||
| 705 | tc_write(DPIPXLFMT, VS_POL_ACTIVE_LOW | HS_POL_ACTIVE_LOW | | 722 | tc_write(DPIPXLFMT, VS_POL_ACTIVE_LOW | HS_POL_ACTIVE_LOW | |
| 706 | DE_POL_ACTIVE_HIGH | SUB_CFG_TYPE_CONFIG1 | DPI_BPP_RGB888); | 723 | DE_POL_ACTIVE_HIGH | SUB_CFG_TYPE_CONFIG1 | DPI_BPP_RGB888); |
| 707 | 724 | ||
| 708 | /* | 725 | tc_write(DP0_MISC, (max_tu_symbol << 23) | (TU_SIZE_RECOMMENDED << 16) | |
| 709 | * Recommended maximum number of symbols transferred in a transfer unit: | 726 | BPC_8); |
| 710 | * DIV_ROUND_UP((input active video bandwidth in bytes) * tu_size, | ||
| 711 | * (output active video bandwidth in bytes)) | ||
| 712 | * Must be less than tu_size. | ||
| 713 | */ | ||
| 714 | max_tu_symbol = TU_SIZE_RECOMMENDED - 1; | ||
| 715 | tc_write(DP0_MISC, (max_tu_symbol << 23) | TU_SIZE_RECOMMENDED | BPC_8); | ||
| 716 | 727 | ||
| 717 | return 0; | 728 | return 0; |
| 718 | err: | 729 | err: |
| @@ -808,8 +819,6 @@ static int tc_main_link_setup(struct tc_data *tc) | |||
| 808 | unsigned int rate; | 819 | unsigned int rate; |
| 809 | u32 dp_phy_ctrl; | 820 | u32 dp_phy_ctrl; |
| 810 | int timeout; | 821 | int timeout; |
| 811 | bool aligned; | ||
| 812 | bool ready; | ||
| 813 | u32 value; | 822 | u32 value; |
| 814 | int ret; | 823 | int ret; |
| 815 | u8 tmp[8]; | 824 | u8 tmp[8]; |
| @@ -954,16 +963,15 @@ static int tc_main_link_setup(struct tc_data *tc) | |||
| 954 | ret = drm_dp_dpcd_read_link_status(aux, tmp + 2); | 963 | ret = drm_dp_dpcd_read_link_status(aux, tmp + 2); |
| 955 | if (ret < 0) | 964 | if (ret < 0) |
| 956 | goto err_dpcd_read; | 965 | goto err_dpcd_read; |
| 957 | ready = (tmp[2] == ((DP_CHANNEL_EQ_BITS << 4) | /* Lane1 */ | 966 | } while ((--timeout) && |
| 958 | DP_CHANNEL_EQ_BITS)); /* Lane0 */ | 967 | !(drm_dp_channel_eq_ok(tmp + 2, tc->link.base.num_lanes))); |
| 959 | aligned = tmp[4] & DP_INTERLANE_ALIGN_DONE; | ||
| 960 | } while ((--timeout) && !(ready && aligned)); | ||
| 961 | 968 | ||
| 962 | if (timeout == 0) { | 969 | if (timeout == 0) { |
| 963 | /* Read DPCD 0x200-0x201 */ | 970 | /* Read DPCD 0x200-0x201 */ |
| 964 | ret = drm_dp_dpcd_read(aux, DP_SINK_COUNT, tmp, 2); | 971 | ret = drm_dp_dpcd_read(aux, DP_SINK_COUNT, tmp, 2); |
| 965 | if (ret < 0) | 972 | if (ret < 0) |
| 966 | goto err_dpcd_read; | 973 | goto err_dpcd_read; |
| 974 | dev_err(dev, "channel(s) EQ not ok\n"); | ||
| 967 | dev_info(dev, "0x0200 SINK_COUNT: 0x%02x\n", tmp[0]); | 975 | dev_info(dev, "0x0200 SINK_COUNT: 0x%02x\n", tmp[0]); |
| 968 | dev_info(dev, "0x0201 DEVICE_SERVICE_IRQ_VECTOR: 0x%02x\n", | 976 | dev_info(dev, "0x0201 DEVICE_SERVICE_IRQ_VECTOR: 0x%02x\n", |
| 969 | tmp[1]); | 977 | tmp[1]); |
| @@ -974,10 +982,6 @@ static int tc_main_link_setup(struct tc_data *tc) | |||
| 974 | dev_info(dev, "0x0206 ADJUST_REQUEST_LANE0_1: 0x%02x\n", | 982 | dev_info(dev, "0x0206 ADJUST_REQUEST_LANE0_1: 0x%02x\n", |
| 975 | tmp[6]); | 983 | tmp[6]); |
| 976 | 984 | ||
| 977 | if (!ready) | ||
| 978 | dev_err(dev, "Lane0/1 not ready\n"); | ||
| 979 | if (!aligned) | ||
| 980 | dev_err(dev, "Lane0/1 not aligned\n"); | ||
| 981 | return -EAGAIN; | 985 | return -EAGAIN; |
| 982 | } | 986 | } |
| 983 | 987 | ||
| @@ -1099,7 +1103,10 @@ static bool tc_bridge_mode_fixup(struct drm_bridge *bridge, | |||
| 1099 | static int tc_connector_mode_valid(struct drm_connector *connector, | 1103 | static int tc_connector_mode_valid(struct drm_connector *connector, |
| 1100 | struct drm_display_mode *mode) | 1104 | struct drm_display_mode *mode) |
| 1101 | { | 1105 | { |
| 1102 | /* Accept any mode */ | 1106 | /* DPI interface clock limitation: upto 154 MHz */ |
| 1107 | if (mode->clock > 154000) | ||
| 1108 | return MODE_CLOCK_HIGH; | ||
| 1109 | |||
| 1103 | return MODE_OK; | 1110 | return MODE_OK; |
| 1104 | } | 1111 | } |
| 1105 | 1112 | ||
