aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorJesse Barnes <jbarnes@virtuousgeek.org>2009-07-14 13:15:56 -0400
committerEric Anholt <eric@anholt.net>2009-07-14 18:33:25 -0400
commitdff33cfcefa31c30b72c57f44586754ea9e8f3e2 (patch)
treeb3ea4aedd765071b0dbaf382974bc4683244cb83 /drivers
parented8c754b292f02d0550596481527b7bf2b52d024 (diff)
drm/i915: FIFO watermark calculation fixes
I discovered several bugs in the FIFO code that was recently applied. Some of them fell into the "how did this ever work" category, since in some cases we were using the wrong FIFO size values, and the calculations ended up being way off. This patch fixes all the bugs I found, and works well on my GM45, 915GM and 855GM test machines; but as usual with these sorts of patches broader testing is definitely requested (in particular this patch affects 830, 845 and 865 for which I don't have test hardware). Overall, the patch clarifies the watermark calculation function by adding some comments and debug info, and making the variable names a bit clearer. The "get FIFO size" portion of the code has also been corrected, so we should be able to properly detect the FIFO allocations for each pipe, for use in the watermark calculation. Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org> Signed-off-by: Eric Anholt <eric@anholt.net>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h2
-rw-r--r--drivers/gpu/drm/i915/intel_display.c186
2 files changed, 113 insertions, 75 deletions
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 6c0858484094..897a116cad14 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -1618,7 +1618,7 @@
1618#define I830_FIFO_LINE_SIZE 32 1618#define I830_FIFO_LINE_SIZE 32
1619#define I945_FIFO_SIZE 127 /* 945 & 965 */ 1619#define I945_FIFO_SIZE 127 /* 945 & 965 */
1620#define I915_FIFO_SIZE 95 1620#define I915_FIFO_SIZE 95
1621#define I855GM_FIFO_SIZE 255 1621#define I855GM_FIFO_SIZE 127 /* In cachelines */
1622#define I830_FIFO_SIZE 95 1622#define I830_FIFO_SIZE 95
1623#define I915_MAX_WM 0x3f 1623#define I915_MAX_WM 0x3f
1624 1624
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 984645e26a2d..3fa0d63c83b9 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -1623,44 +1623,67 @@ static struct intel_watermark_params igd_cursor_hplloff_wm = {
1623 IGD_FIFO_LINE_SIZE 1623 IGD_FIFO_LINE_SIZE
1624}; 1624};
1625static struct intel_watermark_params i945_wm_info = { 1625static struct intel_watermark_params i945_wm_info = {
1626 I915_FIFO_LINE_SIZE, 1626 I945_FIFO_SIZE,
1627 I915_MAX_WM, 1627 I915_MAX_WM,
1628 1, 1628 1,
1629 0, 1629 2,
1630 IGD_FIFO_LINE_SIZE 1630 I915_FIFO_LINE_SIZE
1631}; 1631};
1632static struct intel_watermark_params i915_wm_info = { 1632static struct intel_watermark_params i915_wm_info = {
1633 I945_FIFO_SIZE, 1633 I915_FIFO_SIZE,
1634 I915_MAX_WM, 1634 I915_MAX_WM,
1635 1, 1635 1,
1636 0, 1636 2,
1637 I915_FIFO_LINE_SIZE 1637 I915_FIFO_LINE_SIZE
1638}; 1638};
1639static struct intel_watermark_params i855_wm_info = { 1639static struct intel_watermark_params i855_wm_info = {
1640 I855GM_FIFO_SIZE, 1640 I855GM_FIFO_SIZE,
1641 I915_MAX_WM, 1641 I915_MAX_WM,
1642 1, 1642 1,
1643 0, 1643 2,
1644 I830_FIFO_LINE_SIZE 1644 I830_FIFO_LINE_SIZE
1645}; 1645};
1646static struct intel_watermark_params i830_wm_info = { 1646static struct intel_watermark_params i830_wm_info = {
1647 I830_FIFO_SIZE, 1647 I830_FIFO_SIZE,
1648 I915_MAX_WM, 1648 I915_MAX_WM,
1649 1, 1649 1,
1650 0, 1650 2,
1651 I830_FIFO_LINE_SIZE 1651 I830_FIFO_LINE_SIZE
1652}; 1652};
1653 1653
1654/**
1655 * intel_calculate_wm - calculate watermark level
1656 * @clock_in_khz: pixel clock
1657 * @wm: chip FIFO params
1658 * @pixel_size: display pixel size
1659 * @latency_ns: memory latency for the platform
1660 *
1661 * Calculate the watermark level (the level at which the display plane will
1662 * start fetching from memory again). Each chip has a different display
1663 * FIFO size and allocation, so the caller needs to figure that out and pass
1664 * in the correct intel_watermark_params structure.
1665 *
1666 * As the pixel clock runs, the FIFO will be drained at a rate that depends
1667 * on the pixel size. When it reaches the watermark level, it'll start
1668 * fetching FIFO line sized based chunks from memory until the FIFO fills
1669 * past the watermark point. If the FIFO drains completely, a FIFO underrun
1670 * will occur, and a display engine hang could result.
1671 */
1654static unsigned long intel_calculate_wm(unsigned long clock_in_khz, 1672static unsigned long intel_calculate_wm(unsigned long clock_in_khz,
1655 struct intel_watermark_params *wm, 1673 struct intel_watermark_params *wm,
1656 int pixel_size, 1674 int pixel_size,
1657 unsigned long latency_ns) 1675 unsigned long latency_ns)
1658{ 1676{
1659 unsigned long bytes_required, wm_size; 1677 unsigned long entries_required, wm_size;
1678
1679 entries_required = (clock_in_khz * pixel_size * latency_ns) / 1000000;
1680 entries_required /= wm->cacheline_size;
1681
1682 DRM_DEBUG("FIFO entries required for mode: %d\n", entries_required);
1660 1683
1661 bytes_required = (clock_in_khz * pixel_size * latency_ns) / 1000000; 1684 wm_size = wm->fifo_size - (entries_required + wm->guard_size);
1662 bytes_required /= wm->cacheline_size; 1685
1663 wm_size = wm->fifo_size - bytes_required - wm->guard_size; 1686 DRM_DEBUG("FIFO watermark level: %d\n", wm_size);
1664 1687
1665 if (wm_size > wm->max_wm) 1688 if (wm_size > wm->max_wm)
1666 wm_size = wm->max_wm; 1689 wm_size = wm->max_wm;
@@ -1799,8 +1822,37 @@ static void igd_enable_cxsr(struct drm_device *dev, unsigned long clock,
1799 return; 1822 return;
1800} 1823}
1801 1824
1802const static int latency_ns = 5000; /* default for non-igd platforms */ 1825const static int latency_ns = 3000; /* default for non-igd platforms */
1826
1827static int intel_get_fifo_size(struct drm_device *dev, int plane)
1828{
1829 struct drm_i915_private *dev_priv = dev->dev_private;
1830 uint32_t dsparb = I915_READ(DSPARB);
1831 int size;
1832
1833 if (IS_I9XX(dev)) {
1834 if (plane == 0)
1835 size = dsparb & 0x7f;
1836 else
1837 size = ((dsparb >> DSPARB_CSTART_SHIFT) & 0x7f) -
1838 (dsparb & 0x7f);
1839 } else if (IS_I85X(dev)) {
1840 if (plane == 0)
1841 size = dsparb & 0x1ff;
1842 else
1843 size = ((dsparb >> DSPARB_BEND_SHIFT) & 0x1ff) -
1844 (dsparb & 0x1ff);
1845 size >>= 1; /* Convert to cachelines */
1846 } else {
1847 size = dsparb & 0x7f;
1848 size >>= 1; /* Convert to cachelines */
1849 }
1850
1851 DRM_DEBUG("FIFO size - (0x%08x) %s: %d\n", dsparb, plane ? "B" : "A",
1852 size);
1803 1853
1854 return size;
1855}
1804 1856
1805static void i965_update_wm(struct drm_device *dev) 1857static void i965_update_wm(struct drm_device *dev)
1806{ 1858{
@@ -1817,101 +1869,87 @@ static void i9xx_update_wm(struct drm_device *dev, int planea_clock,
1817 int planeb_clock, int sr_hdisplay, int pixel_size) 1869 int planeb_clock, int sr_hdisplay, int pixel_size)
1818{ 1870{
1819 struct drm_i915_private *dev_priv = dev->dev_private; 1871 struct drm_i915_private *dev_priv = dev->dev_private;
1820 uint32_t fwater_lo = I915_READ(FW_BLC) & MM_FIFO_WATERMARK; 1872 uint32_t fwater_lo;
1821 uint32_t fwater_hi = I915_READ(FW_BLC2) & LM_FIFO_WATERMARK; 1873 uint32_t fwater_hi;
1822 int bsize, asize, cwm, bwm = 1, awm = 1, srwm = 1; 1874 int total_size, cacheline_size, cwm, srwm = 1;
1823 uint32_t dsparb = I915_READ(DSPARB); 1875 int planea_wm, planeb_wm;
1824 int planea_entries, planeb_entries; 1876 struct intel_watermark_params planea_params, planeb_params;
1825 struct intel_watermark_params *wm_params;
1826 unsigned long line_time_us; 1877 unsigned long line_time_us;
1827 int sr_clock, sr_entries = 0; 1878 int sr_clock, sr_entries = 0;
1828 1879
1880 /* Create copies of the base settings for each pipe */
1829 if (IS_I965GM(dev) || IS_I945GM(dev)) 1881 if (IS_I965GM(dev) || IS_I945GM(dev))
1830 wm_params = &i945_wm_info; 1882 planea_params = planeb_params = i945_wm_info;
1831 else if (IS_I9XX(dev)) 1883 else if (IS_I9XX(dev))
1832 wm_params = &i915_wm_info; 1884 planea_params = planeb_params = i915_wm_info;
1833 else 1885 else
1834 wm_params = &i855_wm_info; 1886 planea_params = planeb_params = i855_wm_info;
1835
1836 planea_entries = intel_calculate_wm(planea_clock, wm_params,
1837 pixel_size, latency_ns);
1838 planeb_entries = intel_calculate_wm(planeb_clock, wm_params,
1839 pixel_size, latency_ns);
1840 1887
1841 DRM_DEBUG("FIFO entries - A: %d, B: %d\n", planea_entries, 1888 /* Grab a couple of global values before we overwrite them */
1842 planeb_entries); 1889 total_size = planea_params.fifo_size;
1890 cacheline_size = planea_params.cacheline_size;
1843 1891
1844 if (IS_I9XX(dev)) { 1892 /* Update per-plane FIFO sizes */
1845 asize = dsparb & 0x7f; 1893 planea_params.fifo_size = intel_get_fifo_size(dev, 0);
1846 bsize = (dsparb >> DSPARB_CSTART_SHIFT) & 0x7f; 1894 planeb_params.fifo_size = intel_get_fifo_size(dev, 1);
1847 } else {
1848 asize = dsparb & 0x1ff;
1849 bsize = (dsparb >> DSPARB_BEND_SHIFT) & 0x1ff;
1850 }
1851 DRM_DEBUG("FIFO size - A: %d, B: %d\n", asize, bsize);
1852 1895
1853 /* Two extra entries for padding */ 1896 planea_wm = intel_calculate_wm(planea_clock, &planea_params,
1854 awm = asize - (planea_entries + 2); 1897 pixel_size, latency_ns);
1855 bwm = bsize - (planeb_entries + 2); 1898 planeb_wm = intel_calculate_wm(planeb_clock, &planeb_params,
1856 1899 pixel_size, latency_ns);
1857 /* Sanity check against potentially bad FIFO allocations */ 1900 DRM_DEBUG("FIFO watermarks - A: %d, B: %d\n", planea_wm, planeb_wm);
1858 if (awm <= 0) {
1859 /* pipe is on but has too few FIFO entries */
1860 if (planea_entries != 0)
1861 DRM_DEBUG("plane A needs more FIFO entries\n");
1862 awm = 1;
1863 }
1864 if (bwm <= 0) {
1865 if (planeb_entries != 0)
1866 DRM_DEBUG("plane B needs more FIFO entries\n");
1867 bwm = 1;
1868 }
1869 1901
1870 /* 1902 /*
1871 * Overlay gets an aggressive default since video jitter is bad. 1903 * Overlay gets an aggressive default since video jitter is bad.
1872 */ 1904 */
1873 cwm = 2; 1905 cwm = 2;
1874 1906
1875 /* Calc sr entries for one pipe configs */ 1907 /* Calc sr entries for one plane configs */
1876 if (!planea_clock || !planeb_clock) { 1908 if (!planea_clock || !planeb_clock) {
1909 /* self-refresh has much higher latency */
1910 const static int sr_latency_ns = 6000;
1911
1877 sr_clock = planea_clock ? planea_clock : planeb_clock; 1912 sr_clock = planea_clock ? planea_clock : planeb_clock;
1878 line_time_us = (sr_hdisplay * 1000) / sr_clock; 1913 line_time_us = ((sr_hdisplay * 1000) / sr_clock);
1879 sr_entries = (((latency_ns / line_time_us) + 1) * pixel_size * 1914
1880 sr_hdisplay) / 1000; 1915 /* Use ns/us then divide to preserve precision */
1881 sr_entries = roundup(sr_entries / wm_params->cacheline_size, 1); 1916 sr_entries = (((sr_latency_ns / line_time_us) + 1) *
1882 if (sr_entries < wm_params->fifo_size) 1917 pixel_size * sr_hdisplay) / 1000;
1883 srwm = wm_params->fifo_size - sr_entries; 1918 sr_entries = roundup(sr_entries / cacheline_size, 1);
1919 DRM_DEBUG("self-refresh entries: %d\n", sr_entries);
1920 srwm = total_size - sr_entries;
1921 if (srwm < 0)
1922 srwm = 1;
1884 } 1923 }
1885 1924
1886 DRM_DEBUG("Setting FIFO watermarks - A: %d, B: %d, C: %d, SR %d\n", 1925 DRM_DEBUG("Setting FIFO watermarks - A: %d, B: %d, C: %d, SR %d\n",
1887 awm, bwm, cwm, srwm); 1926 planea_wm, planeb_wm, cwm, srwm);
1888 1927
1889 fwater_lo = fwater_lo | ((bwm & 0x3f) << 16) | (awm & 0x3f); 1928 fwater_lo = ((planeb_wm & 0x3f) << 16) | (planea_wm & 0x3f);
1890 fwater_hi = fwater_hi | (cwm & 0x1f); 1929 fwater_hi = (cwm & 0x1f);
1930
1931 /* Set request length to 8 cachelines per fetch */
1932 fwater_lo = fwater_lo | (1 << 24) | (1 << 8);
1933 fwater_hi = fwater_hi | (1 << 8);
1891 1934
1892 I915_WRITE(FW_BLC, fwater_lo); 1935 I915_WRITE(FW_BLC, fwater_lo);
1893 I915_WRITE(FW_BLC2, fwater_hi); 1936 I915_WRITE(FW_BLC2, fwater_hi);
1894 if (IS_I9XX(dev)) 1937 if (IS_I9XX(dev))
1895 I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN | (srwm & 0x3f)); 1938 I915_WRITE(FW_BLC_SELF, (srwm & 0x3f));
1896} 1939}
1897 1940
1898static void i830_update_wm(struct drm_device *dev, int planea_clock, 1941static void i830_update_wm(struct drm_device *dev, int planea_clock,
1899 int pixel_size) 1942 int pixel_size)
1900{ 1943{
1901 struct drm_i915_private *dev_priv = dev->dev_private; 1944 struct drm_i915_private *dev_priv = dev->dev_private;
1902 uint32_t dsparb = I915_READ(DSPARB);
1903 uint32_t fwater_lo = I915_READ(FW_BLC) & MM_FIFO_WATERMARK; 1945 uint32_t fwater_lo = I915_READ(FW_BLC) & MM_FIFO_WATERMARK;
1904 unsigned int asize, awm; 1946 int planea_wm;
1905 int planea_entries;
1906
1907 planea_entries = intel_calculate_wm(planea_clock, &i830_wm_info,
1908 pixel_size, latency_ns);
1909
1910 asize = dsparb & 0x7f;
1911 1947
1912 awm = asize - planea_entries; 1948 i830_wm_info.fifo_size = intel_get_fifo_size(dev, 0);
1913 1949
1914 fwater_lo = fwater_lo | awm; 1950 planea_wm = intel_calculate_wm(planea_clock, &i830_wm_info,
1951 pixel_size, latency_ns);
1952 fwater_lo = fwater_lo | planea_wm;
1915 1953
1916 I915_WRITE(FW_BLC, fwater_lo); 1954 I915_WRITE(FW_BLC, fwater_lo);
1917} 1955}
@@ -1984,7 +2022,7 @@ static void intel_update_watermarks(struct drm_device *dev)
1984 if (enabled <= 0) 2022 if (enabled <= 0)
1985 return; 2023 return;
1986 2024
1987 /* Single pipe configs can enable self refresh */ 2025 /* Single plane configs can enable self refresh */
1988 if (enabled == 1 && IS_IGD(dev)) 2026 if (enabled == 1 && IS_IGD(dev))
1989 igd_enable_cxsr(dev, sr_clock, pixel_size); 2027 igd_enable_cxsr(dev, sr_clock, pixel_size);
1990 else if (IS_IGD(dev)) 2028 else if (IS_IGD(dev))