diff options
author | Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> | 2013-08-14 15:43:31 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2013-08-18 19:10:38 -0400 |
commit | 088d61d1fdfde56850c157138a6dc08880c1853d (patch) | |
tree | 186dfc72bd5cf74d1e9d90fdd73030acd6e6a86b /drivers/gpu/drm/i2c | |
parent | c4c11dd160a8cc98f402c4e12f94b1572e822ffd (diff) |
drm/i2c: tda998x: fix sync generation and calculation
This fixes the wrong sync generation and sync calculation of TDA998x
for HS/VS-based sync detection.
Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
Tested-by: Darren Etheridge <detheridge@ti.com>
Tested-by: Russell King <rmk_kernel@arm.linux.org.uk>
Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/i2c')
-rw-r--r-- | drivers/gpu/drm/i2c/tda998x_drv.c | 181 |
1 files changed, 115 insertions, 66 deletions
diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index 2b64dfa60205..92fcb3deae22 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c | |||
@@ -140,8 +140,12 @@ struct tda998x_priv { | |||
140 | #define REG_VS_LINE_END_1_LSB REG(0x00, 0xae) /* write */ | 140 | #define REG_VS_LINE_END_1_LSB REG(0x00, 0xae) /* write */ |
141 | #define REG_VS_PIX_END_1_MSB REG(0x00, 0xaf) /* write */ | 141 | #define REG_VS_PIX_END_1_MSB REG(0x00, 0xaf) /* write */ |
142 | #define REG_VS_PIX_END_1_LSB REG(0x00, 0xb0) /* write */ | 142 | #define REG_VS_PIX_END_1_LSB REG(0x00, 0xb0) /* write */ |
143 | #define REG_VS_LINE_STRT_2_MSB REG(0x00, 0xb1) /* write */ | ||
144 | #define REG_VS_LINE_STRT_2_LSB REG(0x00, 0xb2) /* write */ | ||
143 | #define REG_VS_PIX_STRT_2_MSB REG(0x00, 0xb3) /* write */ | 145 | #define REG_VS_PIX_STRT_2_MSB REG(0x00, 0xb3) /* write */ |
144 | #define REG_VS_PIX_STRT_2_LSB REG(0x00, 0xb4) /* write */ | 146 | #define REG_VS_PIX_STRT_2_LSB REG(0x00, 0xb4) /* write */ |
147 | #define REG_VS_LINE_END_2_MSB REG(0x00, 0xb5) /* write */ | ||
148 | #define REG_VS_LINE_END_2_LSB REG(0x00, 0xb6) /* write */ | ||
145 | #define REG_VS_PIX_END_2_MSB REG(0x00, 0xb7) /* write */ | 149 | #define REG_VS_PIX_END_2_MSB REG(0x00, 0xb7) /* write */ |
146 | #define REG_VS_PIX_END_2_LSB REG(0x00, 0xb8) /* write */ | 150 | #define REG_VS_PIX_END_2_LSB REG(0x00, 0xb8) /* write */ |
147 | #define REG_HS_PIX_START_MSB REG(0x00, 0xb9) /* write */ | 151 | #define REG_HS_PIX_START_MSB REG(0x00, 0xb9) /* write */ |
@@ -152,21 +156,29 @@ struct tda998x_priv { | |||
152 | #define REG_VWIN_START_1_LSB REG(0x00, 0xbe) /* write */ | 156 | #define REG_VWIN_START_1_LSB REG(0x00, 0xbe) /* write */ |
153 | #define REG_VWIN_END_1_MSB REG(0x00, 0xbf) /* write */ | 157 | #define REG_VWIN_END_1_MSB REG(0x00, 0xbf) /* write */ |
154 | #define REG_VWIN_END_1_LSB REG(0x00, 0xc0) /* write */ | 158 | #define REG_VWIN_END_1_LSB REG(0x00, 0xc0) /* write */ |
159 | #define REG_VWIN_START_2_MSB REG(0x00, 0xc1) /* write */ | ||
160 | #define REG_VWIN_START_2_LSB REG(0x00, 0xc2) /* write */ | ||
161 | #define REG_VWIN_END_2_MSB REG(0x00, 0xc3) /* write */ | ||
162 | #define REG_VWIN_END_2_LSB REG(0x00, 0xc4) /* write */ | ||
155 | #define REG_DE_START_MSB REG(0x00, 0xc5) /* write */ | 163 | #define REG_DE_START_MSB REG(0x00, 0xc5) /* write */ |
156 | #define REG_DE_START_LSB REG(0x00, 0xc6) /* write */ | 164 | #define REG_DE_START_LSB REG(0x00, 0xc6) /* write */ |
157 | #define REG_DE_STOP_MSB REG(0x00, 0xc7) /* write */ | 165 | #define REG_DE_STOP_MSB REG(0x00, 0xc7) /* write */ |
158 | #define REG_DE_STOP_LSB REG(0x00, 0xc8) /* write */ | 166 | #define REG_DE_STOP_LSB REG(0x00, 0xc8) /* write */ |
159 | #define REG_TBG_CNTRL_0 REG(0x00, 0xca) /* write */ | 167 | #define REG_TBG_CNTRL_0 REG(0x00, 0xca) /* write */ |
168 | # define TBG_CNTRL_0_TOP_TGL (1 << 0) | ||
169 | # define TBG_CNTRL_0_TOP_SEL (1 << 1) | ||
170 | # define TBG_CNTRL_0_DE_EXT (1 << 2) | ||
171 | # define TBG_CNTRL_0_TOP_EXT (1 << 3) | ||
160 | # define TBG_CNTRL_0_FRAME_DIS (1 << 5) | 172 | # define TBG_CNTRL_0_FRAME_DIS (1 << 5) |
161 | # define TBG_CNTRL_0_SYNC_MTHD (1 << 6) | 173 | # define TBG_CNTRL_0_SYNC_MTHD (1 << 6) |
162 | # define TBG_CNTRL_0_SYNC_ONCE (1 << 7) | 174 | # define TBG_CNTRL_0_SYNC_ONCE (1 << 7) |
163 | #define REG_TBG_CNTRL_1 REG(0x00, 0xcb) /* write */ | 175 | #define REG_TBG_CNTRL_1 REG(0x00, 0xcb) /* write */ |
164 | # define TBG_CNTRL_1_VH_TGL_0 (1 << 0) | 176 | # define TBG_CNTRL_1_H_TGL (1 << 0) |
165 | # define TBG_CNTRL_1_VH_TGL_1 (1 << 1) | 177 | # define TBG_CNTRL_1_V_TGL (1 << 1) |
166 | # define TBG_CNTRL_1_VH_TGL_2 (1 << 2) | 178 | # define TBG_CNTRL_1_TGL_EN (1 << 2) |
167 | # define TBG_CNTRL_1_VHX_EXT_DE (1 << 3) | 179 | # define TBG_CNTRL_1_X_EXT (1 << 3) |
168 | # define TBG_CNTRL_1_VHX_EXT_HS (1 << 4) | 180 | # define TBG_CNTRL_1_H_EXT (1 << 4) |
169 | # define TBG_CNTRL_1_VHX_EXT_VS (1 << 5) | 181 | # define TBG_CNTRL_1_V_EXT (1 << 5) |
170 | # define TBG_CNTRL_1_DWIN_DIS (1 << 6) | 182 | # define TBG_CNTRL_1_DWIN_DIS (1 << 6) |
171 | #define REG_ENABLE_SPACE REG(0x00, 0xd6) /* write */ | 183 | #define REG_ENABLE_SPACE REG(0x00, 0xd6) /* write */ |
172 | #define REG_HVF_CNTRL_0 REG(0x00, 0xe4) /* write */ | 184 | #define REG_HVF_CNTRL_0 REG(0x00, 0xe4) /* write */ |
@@ -735,43 +747,70 @@ tda998x_encoder_mode_set(struct drm_encoder *encoder, | |||
735 | struct drm_display_mode *adjusted_mode) | 747 | struct drm_display_mode *adjusted_mode) |
736 | { | 748 | { |
737 | struct tda998x_priv *priv = to_tda998x_priv(encoder); | 749 | struct tda998x_priv *priv = to_tda998x_priv(encoder); |
738 | uint16_t hs_start, hs_end, line_start, line_end; | 750 | uint16_t ref_pix, ref_line, n_pix, n_line; |
739 | uint16_t vwin_start, vwin_end, de_start, de_end; | 751 | uint16_t hs_pix_s, hs_pix_e; |
740 | uint16_t ref_pix, ref_line, pix_start2; | 752 | uint16_t vs1_pix_s, vs1_pix_e, vs1_line_s, vs1_line_e; |
753 | uint16_t vs2_pix_s, vs2_pix_e, vs2_line_s, vs2_line_e; | ||
754 | uint16_t vwin1_line_s, vwin1_line_e; | ||
755 | uint16_t vwin2_line_s, vwin2_line_e; | ||
756 | uint16_t de_pix_s, de_pix_e; | ||
741 | uint8_t reg, div, rep; | 757 | uint8_t reg, div, rep; |
742 | 758 | ||
743 | hs_start = mode->hsync_start - mode->hdisplay; | 759 | /* |
744 | hs_end = mode->hsync_end - mode->hdisplay; | 760 | * Internally TDA998x is using ITU-R BT.656 style sync but |
745 | line_start = 1; | 761 | * we get VESA style sync. TDA998x is using a reference pixel |
746 | line_end = 1 + mode->vsync_end - mode->vsync_start; | 762 | * relative to ITU to sync to the input frame and for output |
747 | vwin_start = mode->vtotal - mode->vsync_start; | 763 | * sync generation. Currently, we are using reference detection |
748 | vwin_end = vwin_start + mode->vdisplay; | 764 | * from HS/VS, i.e. REFPIX/REFLINE denote frame start sync point |
749 | de_start = mode->htotal - mode->hdisplay; | 765 | * which is position of rising VS with coincident rising HS. |
750 | de_end = mode->htotal; | 766 | * |
751 | 767 | * Now there is some issues to take care of: | |
752 | pix_start2 = 0; | 768 | * - HDMI data islands require sync-before-active |
753 | if (mode->flags & DRM_MODE_FLAG_INTERLACE) | 769 | * - TDA998x register values must be > 0 to be enabled |
754 | pix_start2 = (mode->htotal / 2) + hs_start; | 770 | * - REFLINE needs an additional offset of +1 |
755 | 771 | * - REFPIX needs an addtional offset of +1 for UYUV and +3 for RGB | |
756 | /* TODO how is this value calculated? It is 2 for all common | 772 | * |
757 | * formats in the tables in out of tree nxp driver (assuming | 773 | * So we add +1 to all horizontal and vertical register values, |
758 | * I've properly deciphered their byzantine table system) | 774 | * plus an additional +3 for REFPIX as we are using RGB input only. |
759 | */ | 775 | */ |
760 | ref_line = 2; | 776 | n_pix = mode->htotal; |
761 | 777 | n_line = mode->vtotal; | |
762 | /* this might changes for other color formats from the CRTC: */ | 778 | |
763 | ref_pix = 3 + hs_start; | 779 | hs_pix_e = mode->hsync_end - mode->hdisplay; |
780 | hs_pix_s = mode->hsync_start - mode->hdisplay; | ||
781 | de_pix_e = mode->htotal; | ||
782 | de_pix_s = mode->htotal - mode->hdisplay; | ||
783 | ref_pix = 3 + hs_pix_s; | ||
784 | |||
785 | if ((mode->flags & DRM_MODE_FLAG_INTERLACE) == 0) { | ||
786 | ref_line = 1 + mode->vsync_start - mode->vdisplay; | ||
787 | vwin1_line_s = mode->vtotal - mode->vdisplay - 1; | ||
788 | vwin1_line_e = vwin1_line_s + mode->vdisplay; | ||
789 | vs1_pix_s = vs1_pix_e = hs_pix_s; | ||
790 | vs1_line_s = mode->vsync_start - mode->vdisplay; | ||
791 | vs1_line_e = vs1_line_s + | ||
792 | mode->vsync_end - mode->vsync_start; | ||
793 | vwin2_line_s = vwin2_line_e = 0; | ||
794 | vs2_pix_s = vs2_pix_e = 0; | ||
795 | vs2_line_s = vs2_line_e = 0; | ||
796 | } else { | ||
797 | ref_line = 1 + (mode->vsync_start - mode->vdisplay)/2; | ||
798 | vwin1_line_s = (mode->vtotal - mode->vdisplay)/2; | ||
799 | vwin1_line_e = vwin1_line_s + mode->vdisplay/2; | ||
800 | vs1_pix_s = vs1_pix_e = hs_pix_s; | ||
801 | vs1_line_s = (mode->vsync_start - mode->vdisplay)/2; | ||
802 | vs1_line_e = vs1_line_s + | ||
803 | (mode->vsync_end - mode->vsync_start)/2; | ||
804 | vwin2_line_s = vwin1_line_s + mode->vtotal/2; | ||
805 | vwin2_line_e = vwin2_line_s + mode->vdisplay/2; | ||
806 | vs2_pix_s = vs2_pix_e = hs_pix_s + mode->htotal/2; | ||
807 | vs2_line_s = vs1_line_s + mode->vtotal/2 ; | ||
808 | vs2_line_e = vs2_line_s + | ||
809 | (mode->vsync_end - mode->vsync_start)/2; | ||
810 | } | ||
764 | 811 | ||
765 | div = 148500 / mode->clock; | 812 | div = 148500 / mode->clock; |
766 | 813 | ||
767 | DBG("clock=%d, div=%u", mode->clock, div); | ||
768 | DBG("hs_start=%u, hs_end=%u, line_start=%u, line_end=%u", | ||
769 | hs_start, hs_end, line_start, line_end); | ||
770 | DBG("vwin_start=%u, vwin_end=%u, de_start=%u, de_end=%u", | ||
771 | vwin_start, vwin_end, de_start, de_end); | ||
772 | DBG("ref_line=%u, ref_pix=%u, pix_start2=%u", | ||
773 | ref_line, ref_pix, pix_start2); | ||
774 | |||
775 | /* mute the audio FIFO: */ | 814 | /* mute the audio FIFO: */ |
776 | reg_set(encoder, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_FIFO); | 815 | reg_set(encoder, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_FIFO); |
777 | 816 | ||
@@ -802,9 +841,6 @@ tda998x_encoder_mode_set(struct drm_encoder *encoder, | |||
802 | reg_write(encoder, REG_PLL_SERIAL_2, PLL_SERIAL_2_SRL_NOSC(div) | | 841 | reg_write(encoder, REG_PLL_SERIAL_2, PLL_SERIAL_2_SRL_NOSC(div) | |
803 | PLL_SERIAL_2_SRL_PR(rep)); | 842 | PLL_SERIAL_2_SRL_PR(rep)); |
804 | 843 | ||
805 | reg_write16(encoder, REG_VS_PIX_STRT_2_MSB, pix_start2); | ||
806 | reg_write16(encoder, REG_VS_PIX_END_2_MSB, pix_start2); | ||
807 | |||
808 | /* set color matrix bypass flag: */ | 844 | /* set color matrix bypass flag: */ |
809 | reg_set(encoder, REG_MAT_CONTRL, MAT_CONTRL_MAT_BP); | 845 | reg_set(encoder, REG_MAT_CONTRL, MAT_CONTRL_MAT_BP); |
810 | 846 | ||
@@ -813,46 +849,59 @@ tda998x_encoder_mode_set(struct drm_encoder *encoder, | |||
813 | 849 | ||
814 | reg_clear(encoder, REG_TBG_CNTRL_0, TBG_CNTRL_0_SYNC_MTHD); | 850 | reg_clear(encoder, REG_TBG_CNTRL_0, TBG_CNTRL_0_SYNC_MTHD); |
815 | 851 | ||
852 | /* | ||
853 | * Sync on rising HSYNC/VSYNC | ||
854 | */ | ||
816 | reg_write(encoder, REG_VIP_CNTRL_3, 0); | 855 | reg_write(encoder, REG_VIP_CNTRL_3, 0); |
817 | reg_set(encoder, REG_VIP_CNTRL_3, VIP_CNTRL_3_SYNC_HS); | 856 | reg_set(encoder, REG_VIP_CNTRL_3, VIP_CNTRL_3_SYNC_HS); |
857 | |||
858 | /* | ||
859 | * TDA19988 requires high-active sync at input stage, | ||
860 | * so invert low-active sync provided by master encoder here | ||
861 | */ | ||
862 | if (mode->flags & DRM_MODE_FLAG_NHSYNC) | ||
863 | reg_set(encoder, REG_VIP_CNTRL_3, VIP_CNTRL_3_H_TGL); | ||
818 | if (mode->flags & DRM_MODE_FLAG_NVSYNC) | 864 | if (mode->flags & DRM_MODE_FLAG_NVSYNC) |
819 | reg_set(encoder, REG_VIP_CNTRL_3, VIP_CNTRL_3_V_TGL); | 865 | reg_set(encoder, REG_VIP_CNTRL_3, VIP_CNTRL_3_V_TGL); |
820 | 866 | ||
867 | /* | ||
868 | * Always generate sync polarity relative to input sync and | ||
869 | * revert input stage toggled sync at output stage | ||
870 | */ | ||
871 | reg = TBG_CNTRL_1_TGL_EN; | ||
821 | if (mode->flags & DRM_MODE_FLAG_NHSYNC) | 872 | if (mode->flags & DRM_MODE_FLAG_NHSYNC) |
822 | reg_set(encoder, REG_VIP_CNTRL_3, VIP_CNTRL_3_H_TGL); | 873 | reg |= TBG_CNTRL_1_H_TGL; |
874 | if (mode->flags & DRM_MODE_FLAG_NVSYNC) | ||
875 | reg |= TBG_CNTRL_1_V_TGL; | ||
876 | reg_write(encoder, REG_TBG_CNTRL_1, reg); | ||
823 | 877 | ||
824 | reg_write(encoder, REG_VIDFORMAT, 0x00); | 878 | reg_write(encoder, REG_VIDFORMAT, 0x00); |
825 | reg_write16(encoder, REG_NPIX_MSB, mode->htotal); | 879 | reg_write16(encoder, REG_REFPIX_MSB, ref_pix); |
826 | reg_write16(encoder, REG_NLINE_MSB, mode->vtotal); | 880 | reg_write16(encoder, REG_REFLINE_MSB, ref_line); |
827 | reg_write16(encoder, REG_VS_LINE_STRT_1_MSB, line_start); | 881 | reg_write16(encoder, REG_NPIX_MSB, n_pix); |
828 | reg_write16(encoder, REG_VS_LINE_END_1_MSB, line_end); | 882 | reg_write16(encoder, REG_NLINE_MSB, n_line); |
829 | reg_write16(encoder, REG_VS_PIX_STRT_1_MSB, hs_start); | 883 | reg_write16(encoder, REG_VS_LINE_STRT_1_MSB, vs1_line_s); |
830 | reg_write16(encoder, REG_VS_PIX_END_1_MSB, hs_start); | 884 | reg_write16(encoder, REG_VS_PIX_STRT_1_MSB, vs1_pix_s); |
831 | reg_write16(encoder, REG_HS_PIX_START_MSB, hs_start); | 885 | reg_write16(encoder, REG_VS_LINE_END_1_MSB, vs1_line_e); |
832 | reg_write16(encoder, REG_HS_PIX_STOP_MSB, hs_end); | 886 | reg_write16(encoder, REG_VS_PIX_END_1_MSB, vs1_pix_e); |
833 | reg_write16(encoder, REG_VWIN_START_1_MSB, vwin_start); | 887 | reg_write16(encoder, REG_VS_LINE_STRT_2_MSB, vs2_line_s); |
834 | reg_write16(encoder, REG_VWIN_END_1_MSB, vwin_end); | 888 | reg_write16(encoder, REG_VS_PIX_STRT_2_MSB, vs2_pix_s); |
835 | reg_write16(encoder, REG_DE_START_MSB, de_start); | 889 | reg_write16(encoder, REG_VS_LINE_END_2_MSB, vs2_line_e); |
836 | reg_write16(encoder, REG_DE_STOP_MSB, de_end); | 890 | reg_write16(encoder, REG_VS_PIX_END_2_MSB, vs2_pix_e); |
891 | reg_write16(encoder, REG_HS_PIX_START_MSB, hs_pix_s); | ||
892 | reg_write16(encoder, REG_HS_PIX_STOP_MSB, hs_pix_e); | ||
893 | reg_write16(encoder, REG_VWIN_START_1_MSB, vwin1_line_s); | ||
894 | reg_write16(encoder, REG_VWIN_END_1_MSB, vwin1_line_e); | ||
895 | reg_write16(encoder, REG_VWIN_START_2_MSB, vwin2_line_s); | ||
896 | reg_write16(encoder, REG_VWIN_END_2_MSB, vwin2_line_e); | ||
897 | reg_write16(encoder, REG_DE_START_MSB, de_pix_s); | ||
898 | reg_write16(encoder, REG_DE_STOP_MSB, de_pix_e); | ||
837 | 899 | ||
838 | if (priv->rev == TDA19988) { | 900 | if (priv->rev == TDA19988) { |
839 | /* let incoming pixels fill the active space (if any) */ | 901 | /* let incoming pixels fill the active space (if any) */ |
840 | reg_write(encoder, REG_ENABLE_SPACE, 0x01); | 902 | reg_write(encoder, REG_ENABLE_SPACE, 0x01); |
841 | } | 903 | } |
842 | 904 | ||
843 | reg_write16(encoder, REG_REFPIX_MSB, ref_pix); | ||
844 | reg_write16(encoder, REG_REFLINE_MSB, ref_line); | ||
845 | |||
846 | reg = TBG_CNTRL_1_DWIN_DIS | /* HDCP off */ | ||
847 | TBG_CNTRL_1_VH_TGL_2; | ||
848 | /* | ||
849 | * It is questionable whether this is correct - the nxp driver | ||
850 | * does not set VH_TGL_2 and the below for all display modes. | ||
851 | */ | ||
852 | if (mode->flags & (DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC)) | ||
853 | reg |= TBG_CNTRL_1_VH_TGL_0; | ||
854 | reg_set(encoder, REG_TBG_CNTRL_1, reg); | ||
855 | |||
856 | /* must be last register set: */ | 905 | /* must be last register set: */ |
857 | reg_clear(encoder, REG_TBG_CNTRL_0, TBG_CNTRL_0_SYNC_ONCE); | 906 | reg_clear(encoder, REG_TBG_CNTRL_0, TBG_CNTRL_0_SYNC_ONCE); |
858 | 907 | ||