aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2018-01-12 02:05:33 -0500
committerBen Skeggs <bskeggs@redhat.com>2018-02-02 00:24:07 -0500
commitf4778f08a038d48ab8528416a51bf7ad231f9cc1 (patch)
tree19fe61d3191c05f81eb84ffca885045b116a93ff
parent90df522912ac1fa88836fa1b1b9fa102a48d1f33 (diff)
drm/nouveau/kms/nv50: fix handling of gamma since atomic conversion
We've still been directly using the legacy crtc gamma_set() hook even after conversion to atomic modesetting. For userspace clients this was fine, however, fbcon will use the atomic property when it's running on an atomic driver, which means we miss its colormap updates - which is particularly bad for 8bpp framebuffers! This commit converts the driver to use the atomic property + the helper function implementing the legacy hook on top of atomic. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=80675 Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
-rw-r--r--drivers/gpu/drm/nouveau/nv50_display.c162
1 files changed, 109 insertions, 53 deletions
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index 973a41262139..dd8d4352ed99 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -137,8 +137,10 @@ struct nv50_head_atom {
137 } mode; 137 } mode;
138 138
139 struct { 139 struct {
140 bool visible;
140 u32 handle; 141 u32 handle;
141 u64 offset:40; 142 u64 offset:40;
143 u8 mode:4;
142 } lut; 144 } lut;
143 145
144 struct { 146 struct {
@@ -192,6 +194,7 @@ struct nv50_head_atom {
192 194
193 union { 195 union {
194 struct { 196 struct {
197 bool ilut:1;
195 bool core:1; 198 bool core:1;
196 bool curs:1; 199 bool curs:1;
197 }; 200 };
@@ -200,6 +203,7 @@ struct nv50_head_atom {
200 203
201 union { 204 union {
202 struct { 205 struct {
206 bool ilut:1;
203 bool core:1; 207 bool core:1;
204 bool curs:1; 208 bool curs:1;
205 bool view:1; 209 bool view:1;
@@ -661,7 +665,8 @@ nv50_ovly_create(struct nvif_device *device, struct nvif_object *disp,
661struct nv50_head { 665struct nv50_head {
662 struct nouveau_crtc base; 666 struct nouveau_crtc base;
663 struct { 667 struct {
664 struct nouveau_bo *nvbo[1]; 668 struct nouveau_bo *nvbo[2];
669 int next;
665 } lut; 670 } lut;
666 struct nv50_ovly ovly; 671 struct nv50_ovly ovly;
667 struct nv50_oimm oimm; 672 struct nv50_oimm oimm;
@@ -1798,6 +1803,54 @@ nv50_head_lut_clr(struct nv50_head *head)
1798} 1803}
1799 1804
1800static void 1805static void
1806nv50_head_lut_load(struct drm_property_blob *blob, int mode,
1807 struct nouveau_bo *nvbo)
1808{
1809 struct drm_color_lut *in = (struct drm_color_lut *)blob->data;
1810 void __iomem *lut = (u8 *)nvbo_kmap_obj_iovirtual(nvbo);
1811 const int size = blob->length / sizeof(*in);
1812 int bits, shift, i;
1813 u16 zero, r, g, b;
1814
1815 /* This can't happen.. But it shuts the compiler up. */
1816 if (WARN_ON(size != 256))
1817 return;
1818
1819 switch (mode) {
1820 case 0: /* LORES. */
1821 case 1: /* HIRES. */
1822 bits = 11;
1823 shift = 3;
1824 zero = 0x0000;
1825 break;
1826 case 7: /* INTERPOLATE_257_UNITY_RANGE. */
1827 bits = 14;
1828 shift = 0;
1829 zero = 0x6000;
1830 break;
1831 default:
1832 WARN_ON(1);
1833 return;
1834 }
1835
1836 for (i = 0; i < size; i++) {
1837 r = (drm_color_lut_extract(in[i]. red, bits) + zero) << shift;
1838 g = (drm_color_lut_extract(in[i].green, bits) + zero) << shift;
1839 b = (drm_color_lut_extract(in[i]. blue, bits) + zero) << shift;
1840 writew(r, lut + (i * 0x08) + 0);
1841 writew(g, lut + (i * 0x08) + 2);
1842 writew(b, lut + (i * 0x08) + 4);
1843 }
1844
1845 /* INTERPOLATE modes require a "next" entry to interpolate with,
1846 * so we replicate the last entry to deal with this for now.
1847 */
1848 writew(r, lut + (i * 0x08) + 0);
1849 writew(g, lut + (i * 0x08) + 2);
1850 writew(b, lut + (i * 0x08) + 4);
1851}
1852
1853static void
1801nv50_head_lut_set(struct nv50_head *head, struct nv50_head_atom *asyh) 1854nv50_head_lut_set(struct nv50_head *head, struct nv50_head_atom *asyh)
1802{ 1855{
1803 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base; 1856 struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base;
@@ -1805,20 +1858,18 @@ nv50_head_lut_set(struct nv50_head *head, struct nv50_head_atom *asyh)
1805 if ((push = evo_wait(core, 7))) { 1858 if ((push = evo_wait(core, 7))) {
1806 if (core->base.user.oclass < G82_DISP_CORE_CHANNEL_DMA) { 1859 if (core->base.user.oclass < G82_DISP_CORE_CHANNEL_DMA) {
1807 evo_mthd(push, 0x0840 + (head->base.index * 0x400), 2); 1860 evo_mthd(push, 0x0840 + (head->base.index * 0x400), 2);
1808 evo_data(push, asyh->base.depth == 8 ? 1861 evo_data(push, 0x80000000 | asyh->lut.mode << 30);
1809 0x80000000 : 0xc0000000);
1810 evo_data(push, asyh->lut.offset >> 8); 1862 evo_data(push, asyh->lut.offset >> 8);
1811 } else 1863 } else
1812 if (core->base.user.oclass < GF110_DISP_CORE_CHANNEL_DMA) { 1864 if (core->base.user.oclass < GF110_DISP_CORE_CHANNEL_DMA) {
1813 evo_mthd(push, 0x0840 + (head->base.index * 0x400), 2); 1865 evo_mthd(push, 0x0840 + (head->base.index * 0x400), 2);
1814 evo_data(push, asyh->base.depth == 8 ? 1866 evo_data(push, 0x80000000 | asyh->lut.mode << 30);
1815 0x80000000 : 0xc0000000);
1816 evo_data(push, asyh->lut.offset >> 8); 1867 evo_data(push, asyh->lut.offset >> 8);
1817 evo_mthd(push, 0x085c + (head->base.index * 0x400), 1); 1868 evo_mthd(push, 0x085c + (head->base.index * 0x400), 1);
1818 evo_data(push, asyh->lut.handle); 1869 evo_data(push, asyh->lut.handle);
1819 } else { 1870 } else {
1820 evo_mthd(push, 0x0440 + (head->base.index * 0x300), 4); 1871 evo_mthd(push, 0x0440 + (head->base.index * 0x300), 4);
1821 evo_data(push, 0x87000000); 1872 evo_data(push, 0x80000000 | asyh->lut.mode << 24);
1822 evo_data(push, asyh->lut.offset >> 8); 1873 evo_data(push, asyh->lut.offset >> 8);
1823 evo_data(push, 0x00000000); 1874 evo_data(push, 0x00000000);
1824 evo_data(push, 0x00000000); 1875 evo_data(push, 0x00000000);
@@ -1901,7 +1952,7 @@ nv50_head_view(struct nv50_head *head, struct nv50_head_atom *asyh)
1901static void 1952static void
1902nv50_head_flush_clr(struct nv50_head *head, struct nv50_head_atom *asyh, bool y) 1953nv50_head_flush_clr(struct nv50_head *head, struct nv50_head_atom *asyh, bool y)
1903{ 1954{
1904 if (asyh->clr.core && (!asyh->set.core || y)) 1955 if (asyh->clr.ilut && (!asyh->set.ilut || y))
1905 nv50_head_lut_clr(head); 1956 nv50_head_lut_clr(head);
1906 if (asyh->clr.core && (!asyh->set.core || y)) 1957 if (asyh->clr.core && (!asyh->set.core || y))
1907 nv50_head_core_clr(head); 1958 nv50_head_core_clr(head);
@@ -1914,7 +1965,15 @@ nv50_head_flush_set(struct nv50_head *head, struct nv50_head_atom *asyh)
1914{ 1965{
1915 if (asyh->set.view ) nv50_head_view (head, asyh); 1966 if (asyh->set.view ) nv50_head_view (head, asyh);
1916 if (asyh->set.mode ) nv50_head_mode (head, asyh); 1967 if (asyh->set.mode ) nv50_head_mode (head, asyh);
1917 if (asyh->set.core ) nv50_head_lut_set (head, asyh); 1968 if (asyh->set.ilut ) {
1969 struct nouveau_bo *nvbo = head->lut.nvbo[head->lut.next];
1970 struct drm_property_blob *blob = asyh->state.gamma_lut;
1971 if (blob)
1972 nv50_head_lut_load(blob, asyh->lut.mode, nvbo);
1973 asyh->lut.offset = nvbo->bo.offset;
1974 head->lut.next ^= 1;
1975 nv50_head_lut_set(head, asyh);
1976 }
1918 if (asyh->set.core ) nv50_head_core_set(head, asyh); 1977 if (asyh->set.core ) nv50_head_core_set(head, asyh);
1919 if (asyh->set.curs ) nv50_head_curs_set(head, asyh); 1978 if (asyh->set.curs ) nv50_head_curs_set(head, asyh);
1920 if (asyh->set.base ) nv50_head_base (head, asyh); 1979 if (asyh->set.base ) nv50_head_base (head, asyh);
@@ -2049,6 +2108,37 @@ nv50_head_atomic_check_view(struct nv50_head_atom *armh,
2049} 2108}
2050 2109
2051static void 2110static void
2111nv50_head_atomic_check_lut(struct nv50_head *head,
2112 struct nv50_head_atom *armh,
2113 struct nv50_head_atom *asyh)
2114{
2115 struct nv50_disp *disp = nv50_disp(head->base.base.dev);
2116
2117 /* An I8 surface without an input LUT makes no sense, and
2118 * EVO will throw an error if you try.
2119 *
2120 * Legacy clients actually cause this due to the order in
2121 * which they call ioctls, so we will enable the LUT with
2122 * whatever contents the buffer already contains to avoid
2123 * triggering the error check.
2124 */
2125 if (!asyh->state.gamma_lut && asyh->base.cpp != 1) {
2126 asyh->lut.handle = 0;
2127 asyh->clr.ilut = armh->lut.visible;
2128 return;
2129 }
2130
2131 if (disp->disp->oclass < GF110_DISP) {
2132 asyh->lut.mode = (asyh->base.cpp == 1) ? 0 : 1;
2133 asyh->set.ilut = true;
2134 } else {
2135 asyh->lut.mode = 7;
2136 asyh->set.ilut = asyh->state.color_mgmt_changed;
2137 }
2138 asyh->lut.handle = disp->mast.base.vram.handle;
2139}
2140
2141static void
2052nv50_head_atomic_check_mode(struct nv50_head *head, struct nv50_head_atom *asyh) 2142nv50_head_atomic_check_mode(struct nv50_head *head, struct nv50_head_atom *asyh)
2053{ 2143{
2054 struct drm_display_mode *mode = &asyh->state.adjusted_mode; 2144 struct drm_display_mode *mode = &asyh->state.adjusted_mode;
@@ -2133,6 +2223,11 @@ nv50_head_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state)
2133 if (asyh->state.mode_changed) 2223 if (asyh->state.mode_changed)
2134 nv50_head_atomic_check_mode(head, asyh); 2224 nv50_head_atomic_check_mode(head, asyh);
2135 2225
2226 if (asyh->state.color_mgmt_changed ||
2227 asyh->base.cpp != armh->base.cpp)
2228 nv50_head_atomic_check_lut(head, armh, asyh);
2229 asyh->lut.visible = asyh->lut.handle != 0;
2230
2136 if (asyc) { 2231 if (asyc) {
2137 if (asyc->set.scaler) 2232 if (asyc->set.scaler)
2138 nv50_head_atomic_check_view(armh, asyh, asyc); 2233 nv50_head_atomic_check_view(armh, asyh, asyc);
@@ -2148,7 +2243,8 @@ nv50_head_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state)
2148 asyh->core.w = asyh->base.w; 2243 asyh->core.w = asyh->base.w;
2149 asyh->core.h = asyh->base.h; 2244 asyh->core.h = asyh->base.h;
2150 } else 2245 } else
2151 if ((asyh->core.visible = asyh->curs.visible)) { 2246 if ((asyh->core.visible = asyh->curs.visible) ||
2247 (asyh->core.visible = asyh->lut.visible)) {
2152 /*XXX: We need to either find some way of having the 2248 /*XXX: We need to either find some way of having the
2153 * primary base layer appear black, while still 2249 * primary base layer appear black, while still
2154 * being able to display the other layers, or we 2250 * being able to display the other layers, or we
@@ -2166,11 +2262,10 @@ nv50_head_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state)
2166 asyh->core.layout = 1; 2262 asyh->core.layout = 1;
2167 asyh->core.block = 0; 2263 asyh->core.block = 0;
2168 asyh->core.pitch = ALIGN(asyh->core.w, 64) * 4; 2264 asyh->core.pitch = ALIGN(asyh->core.w, 64) * 4;
2169 asyh->lut.handle = disp->mast.base.vram.handle;
2170 asyh->lut.offset = head->lut.nvbo[0]->bo.offset;
2171 asyh->set.base = armh->base.cpp != asyh->base.cpp; 2265 asyh->set.base = armh->base.cpp != asyh->base.cpp;
2172 asyh->set.ovly = armh->ovly.cpp != asyh->ovly.cpp; 2266 asyh->set.ovly = armh->ovly.cpp != asyh->ovly.cpp;
2173 } else { 2267 } else {
2268 asyh->lut.visible = false;
2174 asyh->core.visible = false; 2269 asyh->core.visible = false;
2175 asyh->curs.visible = false; 2270 asyh->curs.visible = false;
2176 asyh->base.cpp = 0; 2271 asyh->base.cpp = 0;
@@ -2194,8 +2289,10 @@ nv50_head_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state)
2194 asyh->clr.curs = true; 2289 asyh->clr.curs = true;
2195 } 2290 }
2196 } else { 2291 } else {
2292 asyh->clr.ilut = armh->lut.visible;
2197 asyh->clr.core = armh->core.visible; 2293 asyh->clr.core = armh->core.visible;
2198 asyh->clr.curs = armh->curs.visible; 2294 asyh->clr.curs = armh->curs.visible;
2295 asyh->set.ilut = asyh->lut.visible;
2199 asyh->set.core = asyh->core.visible; 2296 asyh->set.core = asyh->core.visible;
2200 asyh->set.curs = asyh->curs.visible; 2297 asyh->set.curs = asyh->curs.visible;
2201 } 2298 }
@@ -2205,47 +2302,11 @@ nv50_head_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state)
2205 return 0; 2302 return 0;
2206} 2303}
2207 2304
2208static void
2209nv50_head_lut_load(struct drm_crtc *crtc)
2210{
2211 struct nv50_disp *disp = nv50_disp(crtc->dev);
2212 struct nv50_head *head = nv50_head(crtc);
2213 void __iomem *lut = nvbo_kmap_obj_iovirtual(head->lut.nvbo[0]);
2214 u16 *r, *g, *b;
2215 int i;
2216
2217 r = crtc->gamma_store;
2218 g = r + crtc->gamma_size;
2219 b = g + crtc->gamma_size;
2220
2221 for (i = 0; i < 256; i++) {
2222 if (disp->disp->oclass < GF110_DISP) {
2223 writew((*r++ >> 2) + 0x0000, lut + (i * 0x08) + 0);
2224 writew((*g++ >> 2) + 0x0000, lut + (i * 0x08) + 2);
2225 writew((*b++ >> 2) + 0x0000, lut + (i * 0x08) + 4);
2226 } else {
2227 /* 0x6000 interferes with the 14-bit color??? */
2228 writew((*r++ >> 2) + 0x6000, lut + (i * 0x08) + 0);
2229 writew((*g++ >> 2) + 0x6000, lut + (i * 0x08) + 2);
2230 writew((*b++ >> 2) + 0x6000, lut + (i * 0x08) + 4);
2231 }
2232 }
2233}
2234
2235static const struct drm_crtc_helper_funcs 2305static const struct drm_crtc_helper_funcs
2236nv50_head_help = { 2306nv50_head_help = {
2237 .atomic_check = nv50_head_atomic_check, 2307 .atomic_check = nv50_head_atomic_check,
2238}; 2308};
2239 2309
2240static int
2241nv50_head_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b,
2242 uint32_t size,
2243 struct drm_modeset_acquire_ctx *ctx)
2244{
2245 nv50_head_lut_load(crtc);
2246 return 0;
2247}
2248
2249static void 2310static void
2250nv50_head_atomic_destroy_state(struct drm_crtc *crtc, 2311nv50_head_atomic_destroy_state(struct drm_crtc *crtc,
2251 struct drm_crtc_state *state) 2312 struct drm_crtc_state *state)
@@ -2318,7 +2379,7 @@ nv50_head_destroy(struct drm_crtc *crtc)
2318static const struct drm_crtc_funcs 2379static const struct drm_crtc_funcs
2319nv50_head_func = { 2380nv50_head_func = {
2320 .reset = nv50_head_reset, 2381 .reset = nv50_head_reset,
2321 .gamma_set = nv50_head_gamma_set, 2382 .gamma_set = drm_atomic_helper_legacy_gamma_set,
2322 .destroy = nv50_head_destroy, 2383 .destroy = nv50_head_destroy,
2323 .set_config = drm_atomic_helper_set_config, 2384 .set_config = drm_atomic_helper_set_config,
2324 .page_flip = drm_atomic_helper_page_flip, 2385 .page_flip = drm_atomic_helper_page_flip,
@@ -4345,7 +4406,6 @@ nv50_display_init(struct drm_device *dev)
4345{ 4406{
4346 struct drm_encoder *encoder; 4407 struct drm_encoder *encoder;
4347 struct drm_plane *plane; 4408 struct drm_plane *plane;
4348 struct drm_crtc *crtc;
4349 u32 *push; 4409 u32 *push;
4350 4410
4351 push = evo_wait(nv50_mast(dev), 32); 4411 push = evo_wait(nv50_mast(dev), 32);
@@ -4364,10 +4424,6 @@ nv50_display_init(struct drm_device *dev)
4364 } 4424 }
4365 } 4425 }
4366 4426
4367 drm_for_each_crtc(crtc, dev) {
4368 nv50_head_lut_load(crtc);
4369 }
4370
4371 drm_for_each_plane(plane, dev) { 4427 drm_for_each_plane(plane, dev) {
4372 struct nv50_wndw *wndw = nv50_wndw(plane); 4428 struct nv50_wndw *wndw = nv50_wndw(plane);
4373 if (plane->funcs != &nv50_wndw) 4429 if (plane->funcs != &nv50_wndw)