132
132
#define REG_IRQ_STAT_CHA_SOT_BIT_ERR BIT(2)
133
133
#define REG_IRQ_STAT_CHA_PLL_UNLOCK BIT(0)
134
134
135
+ enum sn65dsi83_channel {
136
+ CHANNEL_A ,
137
+ CHANNEL_B
138
+ };
139
+
140
+ enum sn65dsi83_lvds_term {
141
+ OHM_100 ,
142
+ OHM_200
143
+ };
144
+
135
145
enum sn65dsi83_model {
136
146
MODEL_SN65DSI83 ,
137
147
MODEL_SN65DSI84 ,
@@ -147,6 +157,8 @@ struct sn65dsi83 {
147
157
struct regulator * vcc ;
148
158
bool lvds_dual_link ;
149
159
bool lvds_dual_link_even_odd_swap ;
160
+ int lvds_vod_swing_conf [2 ];
161
+ int lvds_term_conf [2 ];
150
162
};
151
163
152
164
static const struct regmap_range sn65dsi83_readable_ranges [] = {
@@ -237,6 +249,36 @@ static const struct regmap_config sn65dsi83_regmap_config = {
237
249
.max_register = REG_IRQ_STAT ,
238
250
};
239
251
252
+ static const int lvds_vod_swing_data_table [2 ][4 ][2 ] = {
253
+ { /* 100 Ohm */
254
+ { 180000 , 313000 },
255
+ { 215000 , 372000 },
256
+ { 250000 , 430000 },
257
+ { 290000 , 488000 },
258
+ },
259
+ { /* 200 Ohm */
260
+ { 150000 , 261000 },
261
+ { 200000 , 346000 },
262
+ { 250000 , 428000 },
263
+ { 300000 , 511000 },
264
+ },
265
+ };
266
+
267
+ static const int lvds_vod_swing_clock_table [2 ][4 ][2 ] = {
268
+ { /* 100 Ohm */
269
+ { 140000 , 244000 },
270
+ { 168000 , 290000 },
271
+ { 195000 , 335000 },
272
+ { 226000 , 381000 },
273
+ },
274
+ { /* 200 Ohm */
275
+ { 117000 , 204000 },
276
+ { 156000 , 270000 },
277
+ { 195000 , 334000 },
278
+ { 234000 , 399000 },
279
+ },
280
+ };
281
+
240
282
static struct sn65dsi83 * bridge_to_sn65dsi83 (struct drm_bridge * bridge )
241
283
{
242
284
return container_of (bridge , struct sn65dsi83 , bridge );
@@ -435,12 +477,16 @@ static void sn65dsi83_atomic_pre_enable(struct drm_bridge *bridge,
435
477
val |= REG_LVDS_FMT_LVDS_LINK_CFG ;
436
478
437
479
regmap_write (ctx -> regmap , REG_LVDS_FMT , val );
438
- regmap_write (ctx -> regmap , REG_LVDS_VCOM , 0x05 );
480
+ regmap_write (ctx -> regmap , REG_LVDS_VCOM ,
481
+ REG_LVDS_VCOM_CHA_LVDS_VOD_SWING (ctx -> lvds_vod_swing_conf [CHANNEL_A ]) |
482
+ REG_LVDS_VCOM_CHB_LVDS_VOD_SWING (ctx -> lvds_vod_swing_conf [CHANNEL_B ]));
439
483
regmap_write (ctx -> regmap , REG_LVDS_LANE ,
440
484
(ctx -> lvds_dual_link_even_odd_swap ?
441
485
REG_LVDS_LANE_EVEN_ODD_SWAP : 0 ) |
442
- REG_LVDS_LANE_CHA_LVDS_TERM |
443
- REG_LVDS_LANE_CHB_LVDS_TERM );
486
+ (ctx -> lvds_term_conf [CHANNEL_A ] ?
487
+ REG_LVDS_LANE_CHA_LVDS_TERM : 0 ) |
488
+ (ctx -> lvds_term_conf [CHANNEL_B ] ?
489
+ REG_LVDS_LANE_CHB_LVDS_TERM : 0 ));
444
490
regmap_write (ctx -> regmap , REG_LVDS_CM , 0x00 );
445
491
446
492
le16val = cpu_to_le16 (mode -> hdisplay );
@@ -576,10 +622,103 @@ static const struct drm_bridge_funcs sn65dsi83_funcs = {
576
622
.atomic_get_input_bus_fmts = sn65dsi83_atomic_get_input_bus_fmts ,
577
623
};
578
624
625
+ static int sn65dsi83_select_lvds_vod_swing (struct device * dev ,
626
+ u32 lvds_vod_swing_data [2 ], u32 lvds_vod_swing_clk [2 ], u8 lvds_term )
627
+ {
628
+ int i ;
629
+
630
+ for (i = 0 ; i <= 3 ; i ++ ) {
631
+ if (lvds_vod_swing_data_table [lvds_term ][i ][0 ] >= lvds_vod_swing_data [0 ] &&
632
+ lvds_vod_swing_data_table [lvds_term ][i ][1 ] <= lvds_vod_swing_data [1 ] &&
633
+ lvds_vod_swing_clock_table [lvds_term ][i ][0 ] >= lvds_vod_swing_clk [0 ] &&
634
+ lvds_vod_swing_clock_table [lvds_term ][i ][1 ] <= lvds_vod_swing_clk [1 ])
635
+ return i ;
636
+ }
637
+
638
+ dev_err (dev , "failed to find appropriate LVDS_VOD_SWING configuration\n" );
639
+ return - EINVAL ;
640
+ }
641
+
642
+ static int sn65dsi83_parse_lvds_endpoint (struct sn65dsi83 * ctx , int channel )
643
+ {
644
+ struct device * dev = ctx -> dev ;
645
+ struct device_node * endpoint ;
646
+ int endpoint_reg ;
647
+ /* Set so the property can be freely selected if not defined */
648
+ u32 lvds_vod_swing_data [2 ] = { 0 , 1000000 };
649
+ u32 lvds_vod_swing_clk [2 ] = { 0 , 1000000 };
650
+ /* Set default near end terminataion to 200 Ohm */
651
+ u32 lvds_term = 200 ;
652
+ int lvds_vod_swing_conf ;
653
+ int ret = 0 ;
654
+ int ret_data ;
655
+ int ret_clock ;
656
+
657
+ if (channel == CHANNEL_A )
658
+ endpoint_reg = 2 ;
659
+ else
660
+ endpoint_reg = 3 ;
661
+
662
+ endpoint = of_graph_get_endpoint_by_regs (dev -> of_node , endpoint_reg , -1 );
663
+
664
+ of_property_read_u32 (endpoint , "ti,lvds-termination-ohms" , & lvds_term );
665
+ if (lvds_term == 100 )
666
+ ctx -> lvds_term_conf [channel ] = OHM_100 ;
667
+ else if (lvds_term == 200 )
668
+ ctx -> lvds_term_conf [channel ] = OHM_200 ;
669
+ else {
670
+ ret = - EINVAL ;
671
+ goto exit ;
672
+ }
673
+
674
+ ret_data = of_property_read_u32_array (endpoint , "ti,lvds-vod-swing-data-microvolt" ,
675
+ lvds_vod_swing_data , ARRAY_SIZE (lvds_vod_swing_data ));
676
+ if (ret_data != 0 && ret_data != - EINVAL ) {
677
+ ret = ret_data ;
678
+ goto exit ;
679
+ }
680
+
681
+ ret_clock = of_property_read_u32_array (endpoint , "ti,lvds-vod-swing-clock-microvolt" ,
682
+ lvds_vod_swing_clk , ARRAY_SIZE (lvds_vod_swing_clk ));
683
+ if (ret_clock != 0 && ret_clock != - EINVAL ) {
684
+ ret = ret_clock ;
685
+ goto exit ;
686
+ }
687
+
688
+ /* Use default value if both properties are NOT defined. */
689
+ if (ret_data == - EINVAL && ret_clock == - EINVAL )
690
+ lvds_vod_swing_conf = 0x1 ;
691
+
692
+ /* Use lookup table if any of the two properties is defined. */
693
+ if (!ret_data || !ret_clock ) {
694
+ lvds_vod_swing_conf = sn65dsi83_select_lvds_vod_swing (dev , lvds_vod_swing_data ,
695
+ lvds_vod_swing_clk , ctx -> lvds_term_conf [channel ]);
696
+ if (lvds_vod_swing_conf < 0 ) {
697
+ ret = lvds_vod_swing_conf ;
698
+ goto exit ;
699
+ }
700
+ }
701
+
702
+ ctx -> lvds_vod_swing_conf [channel ] = lvds_vod_swing_conf ;
703
+ ret = 0 ;
704
+ exit :
705
+ of_node_put (endpoint );
706
+ return ret ;
707
+ }
708
+
579
709
static int sn65dsi83_parse_dt (struct sn65dsi83 * ctx , enum sn65dsi83_model model )
580
710
{
581
711
struct drm_bridge * panel_bridge ;
582
712
struct device * dev = ctx -> dev ;
713
+ int ret ;
714
+
715
+ ret = sn65dsi83_parse_lvds_endpoint (ctx , CHANNEL_A );
716
+ if (ret < 0 )
717
+ return ret ;
718
+
719
+ ret = sn65dsi83_parse_lvds_endpoint (ctx , CHANNEL_B );
720
+ if (ret < 0 )
721
+ return ret ;
583
722
584
723
ctx -> lvds_dual_link = false;
585
724
ctx -> lvds_dual_link_even_odd_swap = false;
0 commit comments