diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2014-06-04 20:59:55 -0400 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2014-06-11 02:11:29 -0400 |
commit | e84a35a8054397b0a4efc86ba82d9bc8b3895c75 (patch) | |
tree | 3681db98f5efa125772b664e4ab0a233b0a02d01 /drivers/gpu | |
parent | e32d68c9c799dbe90450b94146624d04aa25aa47 (diff) |
drm/nv50-: prepare for attaching a SOR to multiple heads
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_crtc.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_encoder.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nv50_display.c | 85 |
3 files changed, 46 insertions, 42 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_crtc.h b/drivers/gpu/drm/nouveau/nouveau_crtc.h index d1e5890784d7..a0534489d23f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_crtc.h +++ b/drivers/gpu/drm/nouveau/nouveau_crtc.h | |||
@@ -74,7 +74,7 @@ struct nouveau_crtc { | |||
74 | 74 | ||
75 | static inline struct nouveau_crtc *nouveau_crtc(struct drm_crtc *crtc) | 75 | static inline struct nouveau_crtc *nouveau_crtc(struct drm_crtc *crtc) |
76 | { | 76 | { |
77 | return container_of(crtc, struct nouveau_crtc, base); | 77 | return crtc ? container_of(crtc, struct nouveau_crtc, base) : NULL; |
78 | } | 78 | } |
79 | 79 | ||
80 | static inline struct drm_crtc *to_drm_crtc(struct nouveau_crtc *crtc) | 80 | static inline struct drm_crtc *to_drm_crtc(struct nouveau_crtc *crtc) |
diff --git a/drivers/gpu/drm/nouveau/nouveau_encoder.h b/drivers/gpu/drm/nouveau/nouveau_encoder.h index 24660c0f713d..fcf89c8c67b7 100644 --- a/drivers/gpu/drm/nouveau/nouveau_encoder.h +++ b/drivers/gpu/drm/nouveau/nouveau_encoder.h | |||
@@ -46,6 +46,7 @@ struct nouveau_encoder { | |||
46 | /* different to drm_encoder.crtc, this reflects what's | 46 | /* different to drm_encoder.crtc, this reflects what's |
47 | * actually programmed on the hw, not the proposed crtc */ | 47 | * actually programmed on the hw, not the proposed crtc */ |
48 | struct drm_crtc *crtc; | 48 | struct drm_crtc *crtc; |
49 | u32 ctrl; | ||
49 | 50 | ||
50 | struct drm_display_mode mode; | 51 | struct drm_display_mode mode; |
51 | int last_dpms; | 52 | int last_dpms; |
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 21c72480df82..765cf68545ae 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c | |||
@@ -1701,10 +1701,9 @@ nv50_hdmi_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode) | |||
1701 | } | 1701 | } |
1702 | 1702 | ||
1703 | static void | 1703 | static void |
1704 | nv50_hdmi_disconnect(struct drm_encoder *encoder) | 1704 | nv50_hdmi_disconnect(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc) |
1705 | { | 1705 | { |
1706 | struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); | 1706 | struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); |
1707 | struct nouveau_crtc *nv_crtc = nouveau_crtc(nv_encoder->crtc); | ||
1708 | struct nv50_disp *disp = nv50_disp(encoder->dev); | 1707 | struct nv50_disp *disp = nv50_disp(encoder->dev); |
1709 | const u32 moff = (nv_crtc->index << 3) | nv_encoder->or; | 1708 | const u32 moff = (nv_crtc->index << 3) | nv_encoder->or; |
1710 | 1709 | ||
@@ -1775,33 +1774,36 @@ nv50_sor_mode_fixup(struct drm_encoder *encoder, | |||
1775 | } | 1774 | } |
1776 | 1775 | ||
1777 | static void | 1776 | static void |
1778 | nv50_sor_disconnect(struct drm_encoder *encoder) | 1777 | nv50_sor_ctrl(struct nouveau_encoder *nv_encoder, u32 mask, u32 data) |
1779 | { | 1778 | { |
1780 | struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); | 1779 | struct nv50_mast *mast = nv50_mast(nv_encoder->base.base.dev); |
1781 | struct nv50_mast *mast = nv50_mast(encoder->dev); | 1780 | u32 temp = (nv_encoder->ctrl & ~mask) | (data & mask), *push; |
1782 | const int or = nv_encoder->or; | 1781 | if (temp != nv_encoder->ctrl && (push = evo_wait(mast, 2))) { |
1783 | u32 *push; | 1782 | if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) { |
1784 | 1783 | evo_mthd(push, 0x0600 + (nv_encoder->or * 0x40), 1); | |
1785 | if (nv_encoder->crtc) { | 1784 | evo_data(push, (nv_encoder->ctrl = temp)); |
1786 | nv50_crtc_prepare(nv_encoder->crtc); | 1785 | } else { |
1787 | 1786 | evo_mthd(push, 0x0200 + (nv_encoder->or * 0x20), 1); | |
1788 | push = evo_wait(mast, 4); | 1787 | evo_data(push, (nv_encoder->ctrl = temp)); |
1789 | if (push) { | ||
1790 | if (nv50_vers(mast) < NVD0_DISP_MAST_CLASS) { | ||
1791 | evo_mthd(push, 0x0600 + (or * 0x40), 1); | ||
1792 | evo_data(push, 0x00000000); | ||
1793 | } else { | ||
1794 | evo_mthd(push, 0x0200 + (or * 0x20), 1); | ||
1795 | evo_data(push, 0x00000000); | ||
1796 | } | ||
1797 | evo_kick(push, mast); | ||
1798 | } | 1788 | } |
1799 | 1789 | evo_kick(push, mast); | |
1800 | nv50_hdmi_disconnect(encoder); | ||
1801 | } | 1790 | } |
1791 | } | ||
1792 | |||
1793 | static void | ||
1794 | nv50_sor_disconnect(struct drm_encoder *encoder) | ||
1795 | { | ||
1796 | struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); | ||
1797 | struct nouveau_crtc *nv_crtc = nouveau_crtc(nv_encoder->crtc); | ||
1802 | 1798 | ||
1803 | nv_encoder->last_dpms = DRM_MODE_DPMS_OFF; | 1799 | nv_encoder->last_dpms = DRM_MODE_DPMS_OFF; |
1804 | nv_encoder->crtc = NULL; | 1800 | nv_encoder->crtc = NULL; |
1801 | |||
1802 | if (nv_crtc) { | ||
1803 | nv50_crtc_prepare(&nv_crtc->base); | ||
1804 | nv50_sor_ctrl(nv_encoder, 1 << nv_crtc->index, 0); | ||
1805 | nv50_hdmi_disconnect(&nv_encoder->base.base, nv_crtc); | ||
1806 | } | ||
1805 | } | 1807 | } |
1806 | 1808 | ||
1807 | static void | 1809 | static void |
@@ -1821,12 +1823,14 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode, | |||
1821 | struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc); | 1823 | struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc); |
1822 | struct nouveau_connector *nv_connector; | 1824 | struct nouveau_connector *nv_connector; |
1823 | struct nvbios *bios = &drm->vbios; | 1825 | struct nvbios *bios = &drm->vbios; |
1824 | u32 *push, lvds = 0; | 1826 | u32 lvds = 0, mask, ctrl; |
1825 | u8 owner = 1 << nv_crtc->index; | 1827 | u8 owner = 1 << nv_crtc->index; |
1826 | u8 proto = 0xf; | 1828 | u8 proto = 0xf; |
1827 | u8 depth = 0x0; | 1829 | u8 depth = 0x0; |
1828 | 1830 | ||
1829 | nv_connector = nouveau_encoder_connector_get(nv_encoder); | 1831 | nv_connector = nouveau_encoder_connector_get(nv_encoder); |
1832 | nv_encoder->crtc = encoder->crtc; | ||
1833 | |||
1830 | switch (nv_encoder->dcb->type) { | 1834 | switch (nv_encoder->dcb->type) { |
1831 | case DCB_OUTPUT_TMDS: | 1835 | case DCB_OUTPUT_TMDS: |
1832 | if (nv_encoder->dcb->sorconf.link & 1) { | 1836 | if (nv_encoder->dcb->sorconf.link & 1) { |
@@ -1838,7 +1842,7 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode, | |||
1838 | proto = 0x2; | 1842 | proto = 0x2; |
1839 | } | 1843 | } |
1840 | 1844 | ||
1841 | nv50_hdmi_mode_set(encoder, mode); | 1845 | nv50_hdmi_mode_set(&nv_encoder->base.base, mode); |
1842 | break; | 1846 | break; |
1843 | case DCB_OUTPUT_LVDS: | 1847 | case DCB_OUTPUT_LVDS: |
1844 | proto = 0x0; | 1848 | proto = 0x0; |
@@ -1894,19 +1898,11 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode, | |||
1894 | break; | 1898 | break; |
1895 | } | 1899 | } |
1896 | 1900 | ||
1897 | nv50_sor_dpms(encoder, DRM_MODE_DPMS_ON); | 1901 | nv50_sor_dpms(&nv_encoder->base.base, DRM_MODE_DPMS_ON); |
1898 | 1902 | ||
1899 | push = evo_wait(nv50_mast(dev), 8); | 1903 | if (nv50_vers(mast) >= NVD0_DISP_CLASS) { |
1900 | if (push) { | 1904 | u32 *push = evo_wait(mast, 3); |
1901 | if (nv50_vers(mast) < NVD0_DISP_CLASS) { | 1905 | if (push) { |
1902 | u32 ctrl = (depth << 16) | (proto << 8) | owner; | ||
1903 | if (mode->flags & DRM_MODE_FLAG_NHSYNC) | ||
1904 | ctrl |= 0x00001000; | ||
1905 | if (mode->flags & DRM_MODE_FLAG_NVSYNC) | ||
1906 | ctrl |= 0x00002000; | ||
1907 | evo_mthd(push, 0x0600 + (nv_encoder->or * 0x040), 1); | ||
1908 | evo_data(push, ctrl); | ||
1909 | } else { | ||
1910 | u32 magic = 0x31ec6000 | (nv_crtc->index << 25); | 1906 | u32 magic = 0x31ec6000 | (nv_crtc->index << 25); |
1911 | u32 syncs = 0x00000001; | 1907 | u32 syncs = 0x00000001; |
1912 | 1908 | ||
@@ -1921,14 +1917,21 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode, | |||
1921 | evo_mthd(push, 0x0404 + (nv_crtc->index * 0x300), 2); | 1917 | evo_mthd(push, 0x0404 + (nv_crtc->index * 0x300), 2); |
1922 | evo_data(push, syncs | (depth << 6)); | 1918 | evo_data(push, syncs | (depth << 6)); |
1923 | evo_data(push, magic); | 1919 | evo_data(push, magic); |
1924 | evo_mthd(push, 0x0200 + (nv_encoder->or * 0x020), 1); | 1920 | evo_kick(push, mast); |
1925 | evo_data(push, owner | (proto << 8)); | ||
1926 | } | 1921 | } |
1927 | 1922 | ||
1928 | evo_kick(push, mast); | 1923 | ctrl = proto << 8; |
1924 | mask = 0x00000f00; | ||
1925 | } else { | ||
1926 | ctrl = (depth << 16) | (proto << 8); | ||
1927 | if (mode->flags & DRM_MODE_FLAG_NHSYNC) | ||
1928 | ctrl |= 0x00001000; | ||
1929 | if (mode->flags & DRM_MODE_FLAG_NVSYNC) | ||
1930 | ctrl |= 0x00002000; | ||
1931 | mask = 0x000f3f00; | ||
1929 | } | 1932 | } |
1930 | 1933 | ||
1931 | nv_encoder->crtc = encoder->crtc; | 1934 | nv50_sor_ctrl(nv_encoder, mask | owner, ctrl | owner); |
1932 | } | 1935 | } |
1933 | 1936 | ||
1934 | static void | 1937 | static void |