diff options
| -rw-r--r-- | drivers/gpu/drm/i915/i915_reg.h | 2 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/intel_display.c | 186 |
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 | }; |
| 1625 | static struct intel_watermark_params i945_wm_info = { | 1625 | static 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 | }; |
| 1632 | static struct intel_watermark_params i915_wm_info = { | 1632 | static 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 | }; |
| 1639 | static struct intel_watermark_params i855_wm_info = { | 1639 | static 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 | }; |
| 1646 | static struct intel_watermark_params i830_wm_info = { | 1646 | static 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 | */ | ||
| 1654 | static unsigned long intel_calculate_wm(unsigned long clock_in_khz, | 1672 | static 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 | ||
| 1802 | const static int latency_ns = 5000; /* default for non-igd platforms */ | 1825 | const static int latency_ns = 3000; /* default for non-igd platforms */ |
| 1826 | |||
| 1827 | static 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 | ||
| 1805 | static void i965_update_wm(struct drm_device *dev) | 1857 | static 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 | ||
| 1898 | static void i830_update_wm(struct drm_device *dev, int planea_clock, | 1941 | static 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)) |
