@@ -1592,6 +1592,146 @@ nv50_sor_atomic_disable(struct drm_encoder *encoder, struct drm_atomic_state *st
15921592 nv_encoder -> crtc = NULL ;
15931593}
15941594
1595+ // common/inc/displayport/displayport.h
1596+ #define DP_CONFIG_WATERMARK_ADJUST 2
1597+ #define DP_CONFIG_WATERMARK_LIMIT 20
1598+ #define DP_CONFIG_INCREASED_WATERMARK_ADJUST 8
1599+ #define DP_CONFIG_INCREASED_WATERMARK_LIMIT 22
1600+
1601+ static bool
1602+ nv50_sor_dp_watermark_sst (struct nouveau_encoder * outp ,
1603+ struct nv50_head * head , struct nv50_head_atom * asyh )
1604+ {
1605+ bool enhancedFraming = outp -> dp .dpcd [DP_MAX_LANE_COUNT ] & DP_ENHANCED_FRAME_CAP ;
1606+ u64 minRate = outp -> dp .link_bw * 1000 ;
1607+ unsigned tuSize = 64 ;
1608+ unsigned waterMark ;
1609+ unsigned hBlankSym ;
1610+ unsigned vBlankSym ;
1611+ unsigned watermarkAdjust = DP_CONFIG_WATERMARK_ADJUST ;
1612+ unsigned watermarkMinimum = DP_CONFIG_WATERMARK_LIMIT ;
1613+ // depth is multiplied by 16 in case of DSC enable
1614+ s32 hblank_symbols ;
1615+ // number of link clocks per line.
1616+ int vblank_symbols = 0 ;
1617+ bool bEnableDsc = false;
1618+ unsigned surfaceWidth = asyh -> mode .h .blanks - asyh -> mode .h .blanke ;
1619+ unsigned rasterWidth = asyh -> mode .h .active ;
1620+ unsigned depth = asyh -> or .bpc * 3 ;
1621+ unsigned DSC_FACTOR = bEnableDsc ? 16 : 1 ;
1622+ u64 pixelClockHz = asyh -> mode .clock * 1000 ;
1623+ u64 PrecisionFactor = 100000 , ratioF , watermarkF ;
1624+ u32 numLanesPerLink = outp -> dp .link_nr ;
1625+ u32 numSymbolsPerLine ;
1626+ u32 BlankingBits ;
1627+ u32 surfaceWidthPerLink ;
1628+ u32 PixelSteeringBits ;
1629+ u64 NumBlankingLinkClocks ;
1630+ u32 MinHBlank ;
1631+
1632+ if (outp -> outp .info .dp .increased_wm ) {
1633+ watermarkAdjust = DP_CONFIG_INCREASED_WATERMARK_ADJUST ;
1634+ watermarkMinimum = DP_CONFIG_INCREASED_WATERMARK_LIMIT ;
1635+ }
1636+
1637+ if ((pixelClockHz * depth ) >= (8 * minRate * outp -> dp .link_nr * DSC_FACTOR ))
1638+ {
1639+ return false;
1640+ }
1641+
1642+ //
1643+ // For DSC, if (pclk * bpp) < (1/64 * orclk * 8 * lanes) then some TU may end up with
1644+ // 0 active symbols. This may cause HW hang. Bug 200379426
1645+ //
1646+ if ((bEnableDsc ) &&
1647+ ((pixelClockHz * depth ) < ((8 * minRate * outp -> dp .link_nr * DSC_FACTOR ) / 64 )))
1648+ {
1649+ return false;
1650+ }
1651+
1652+ //
1653+ // Perform the SST calculation.
1654+ // For auto mode the watermark calculation does not need to track accumulated error the
1655+ // formulas for manual mode will not work. So below calculation was extracted from the DTB.
1656+ //
1657+ ratioF = ((u64 )pixelClockHz * depth * PrecisionFactor ) / DSC_FACTOR ;
1658+
1659+ ratioF /= 8 * (u64 ) minRate * outp -> dp .link_nr ;
1660+
1661+ if (PrecisionFactor < ratioF ) // Assert if we will end up with a negative number in below
1662+ return false;
1663+
1664+ watermarkF = ratioF * tuSize * (PrecisionFactor - ratioF ) / PrecisionFactor ;
1665+ waterMark = (unsigned )(watermarkAdjust + ((2 * (depth * PrecisionFactor / (8 * numLanesPerLink * DSC_FACTOR )) + watermarkF ) / PrecisionFactor ));
1666+
1667+ //
1668+ // Bounds check the watermark
1669+ //
1670+ numSymbolsPerLine = (surfaceWidth * depth ) / (8 * outp -> dp .link_nr * DSC_FACTOR );
1671+
1672+ if (WARN_ON (waterMark > 39 || waterMark > numSymbolsPerLine ))
1673+ return false;
1674+
1675+ //
1676+ // Clamp the low side
1677+ //
1678+ if (waterMark < watermarkMinimum )
1679+ waterMark = watermarkMinimum ;
1680+
1681+ //Bits to send BS/BE/Extra symbols due to pixel padding
1682+ //Also accounts for enhanced framing.
1683+ BlankingBits = 3 * 8 * numLanesPerLink + (enhancedFraming ? 3 * 8 * numLanesPerLink : 0 );
1684+
1685+ //VBID/MVID/MAUD sent 4 times all the time
1686+ BlankingBits += 3 * 8 * 4 ;
1687+
1688+ surfaceWidthPerLink = surfaceWidth ;
1689+
1690+ //Extra bits sent due to pixel steering
1691+ PixelSteeringBits = (surfaceWidthPerLink % numLanesPerLink ) ? (((numLanesPerLink - surfaceWidthPerLink % numLanesPerLink ) * depth ) / DSC_FACTOR ) : 0 ;
1692+
1693+ BlankingBits += PixelSteeringBits ;
1694+ NumBlankingLinkClocks = (u64 )BlankingBits * PrecisionFactor / (8 * numLanesPerLink );
1695+ MinHBlank = (u32 )(NumBlankingLinkClocks * pixelClockHz / minRate / PrecisionFactor );
1696+ MinHBlank += 12 ;
1697+
1698+ if (WARN_ON (MinHBlank > rasterWidth - surfaceWidth ))
1699+ return false;
1700+
1701+ // Bug 702290 - Active Width should be greater than 60
1702+ if (WARN_ON (surfaceWidth <= 60 ))
1703+ return false;
1704+
1705+
1706+ hblank_symbols = (s32 )(((u64 )(rasterWidth - surfaceWidth - MinHBlank ) * minRate ) / pixelClockHz );
1707+
1708+ //reduce HBlank Symbols to account for secondary data packet
1709+ hblank_symbols -= 1 ; //Stuffer latency to send BS
1710+ hblank_symbols -= 3 ; //SPKT latency to send data to stuffer
1711+
1712+ hblank_symbols -= numLanesPerLink == 1 ? 9 : numLanesPerLink == 2 ? 6 : 3 ;
1713+
1714+ hBlankSym = (hblank_symbols < 0 ) ? 0 : hblank_symbols ;
1715+
1716+ // Refer to dev_disp.ref for more information.
1717+ // # symbols/vblank = ((SetRasterBlankEnd.X + SetRasterSize.Width - SetRasterBlankStart.X - 40) * link_clk / pclk) - Y - 1;
1718+ // where Y = (# lanes == 4) 12 : (# lanes == 2) ? 21 : 39
1719+ if (surfaceWidth < 40 )
1720+ {
1721+ vblank_symbols = 0 ;
1722+ }
1723+ else
1724+ {
1725+ vblank_symbols = (s32 )(((u64 )(surfaceWidth - 40 ) * minRate ) / pixelClockHz ) - 1 ;
1726+
1727+ vblank_symbols -= numLanesPerLink == 1 ? 39 : numLanesPerLink == 2 ? 21 : 12 ;
1728+ }
1729+
1730+ vBlankSym = (vblank_symbols < 0 ) ? 0 : vblank_symbols ;
1731+
1732+ return nvif_outp_dp_sst (& outp -> outp , head -> base .index , waterMark , hBlankSym , vBlankSym );
1733+ }
1734+
15951735static void
15961736nv50_sor_atomic_enable (struct drm_encoder * encoder , struct drm_atomic_state * state )
15971737{
@@ -1679,6 +1819,7 @@ nv50_sor_atomic_enable(struct drm_encoder *encoder, struct drm_atomic_state *sta
16791819 break ;
16801820 case DCB_OUTPUT_DP :
16811821 nouveau_dp_train (nv_encoder , false, mode -> clock , asyh -> or .bpc );
1822+ nv50_sor_dp_watermark_sst (nv_encoder , head , asyh );
16821823 depth = nv50_dp_bpc_to_depth (asyh -> or .bpc );
16831824
16841825 if (nv_encoder -> outp .or .link & 1 )
0 commit comments