xref: /netbsd-src/sys/external/bsd/drm2/dist/drm/nouveau/dispnv50/nouveau_dispnv50_head507d.c (revision 1b592f33a70528671836bfa092de3e80d93631f4)
1 /*	$NetBSD: nouveau_dispnv50_head507d.c,v 1.4 2021/12/19 10:49:47 riastradh Exp $	*/
2 
3 /*
4  * Copyright 2018 Red Hat Inc.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22  * OTHER DEALINGS IN THE SOFTWARE.
23  */
24 #include <sys/cdefs.h>
25 __KERNEL_RCSID(0, "$NetBSD: nouveau_dispnv50_head507d.c,v 1.4 2021/12/19 10:49:47 riastradh Exp $");
26 
27 #include "head.h"
28 #include "core.h"
29 
30 #include <linux/nbsd-namespace.h>
31 
32 void
head507d_procamp(struct nv50_head * head,struct nv50_head_atom * asyh)33 head507d_procamp(struct nv50_head *head, struct nv50_head_atom *asyh)
34 {
35 	struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
36 	u32 *push;
37 	if ((push = evo_wait(core, 2))) {
38 		evo_mthd(push, 0x08a8 + (head->base.index * 0x400), 1);
39 		evo_data(push, asyh->procamp.sat.sin << 20 |
40 			       asyh->procamp.sat.cos << 8);
41 		evo_kick(push, core);
42 	}
43 }
44 
45 void
head507d_dither(struct nv50_head * head,struct nv50_head_atom * asyh)46 head507d_dither(struct nv50_head *head, struct nv50_head_atom *asyh)
47 {
48 	struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
49 	u32 *push;
50 	if ((push = evo_wait(core, 2))) {
51 		evo_mthd(push, 0x08a0 + (head->base.index * 0x0400), 1);
52 		evo_data(push, asyh->dither.mode << 3 |
53 			       asyh->dither.bits << 1 |
54 			       asyh->dither.enable);
55 		evo_kick(push, core);
56 	}
57 }
58 
59 void
head507d_ovly(struct nv50_head * head,struct nv50_head_atom * asyh)60 head507d_ovly(struct nv50_head *head, struct nv50_head_atom *asyh)
61 {
62 	struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
63 	u32 bounds = 0;
64 	u32 *push;
65 
66 	if (asyh->ovly.cpp) {
67 		switch (asyh->ovly.cpp) {
68 		case 4: bounds |= 0x00000300; break;
69 		case 2: bounds |= 0x00000100; break;
70 		default:
71 			WARN_ON(1);
72 			break;
73 		}
74 		bounds |= 0x00000001;
75 	} else {
76 		bounds |= 0x00000100;
77 	}
78 
79 	if ((push = evo_wait(core, 2))) {
80 		evo_mthd(push, 0x0904 + head->base.index * 0x400, 1);
81 		evo_data(push, bounds);
82 		evo_kick(push, core);
83 	}
84 }
85 
86 void
head507d_base(struct nv50_head * head,struct nv50_head_atom * asyh)87 head507d_base(struct nv50_head *head, struct nv50_head_atom *asyh)
88 {
89 	struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
90 	u32 bounds = 0;
91 	u32 *push;
92 
93 	if (asyh->base.cpp) {
94 		switch (asyh->base.cpp) {
95 		case 8: bounds |= 0x00000500; break;
96 		case 4: bounds |= 0x00000300; break;
97 		case 2: bounds |= 0x00000100; break;
98 		case 1: bounds |= 0x00000000; break;
99 		default:
100 			WARN_ON(1);
101 			break;
102 		}
103 		bounds |= 0x00000001;
104 	}
105 
106 	if ((push = evo_wait(core, 2))) {
107 		evo_mthd(push, 0x0900 + head->base.index * 0x400, 1);
108 		evo_data(push, bounds);
109 		evo_kick(push, core);
110 	}
111 }
112 
113 static void
head507d_curs_clr(struct nv50_head * head)114 head507d_curs_clr(struct nv50_head *head)
115 {
116 	struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
117 	u32 *push;
118 	if ((push = evo_wait(core, 2))) {
119 		evo_mthd(push, 0x0880 + head->base.index * 0x400, 1);
120 		evo_data(push, 0x05000000);
121 		evo_kick(push, core);
122 	}
123 }
124 
125 static void
head507d_curs_set(struct nv50_head * head,struct nv50_head_atom * asyh)126 head507d_curs_set(struct nv50_head *head, struct nv50_head_atom *asyh)
127 {
128 	struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
129 	u32 *push;
130 	if ((push = evo_wait(core, 3))) {
131 		evo_mthd(push, 0x0880 + head->base.index * 0x400, 2);
132 		evo_data(push, 0x80000000 | asyh->curs.layout << 26 |
133 					    asyh->curs.format << 24);
134 		evo_data(push, asyh->curs.offset >> 8);
135 		evo_kick(push, core);
136 	}
137 }
138 
139 int
head507d_curs_format(struct nv50_head * head,struct nv50_wndw_atom * asyw,struct nv50_head_atom * asyh)140 head507d_curs_format(struct nv50_head *head, struct nv50_wndw_atom *asyw,
141 		     struct nv50_head_atom *asyh)
142 {
143 	switch (asyw->image.format) {
144 	case 0xcf: asyh->curs.format = 1; break;
145 	default:
146 		WARN_ON(1);
147 		return -EINVAL;
148 	}
149 	return 0;
150 }
151 
152 int
head507d_curs_layout(struct nv50_head * head,struct nv50_wndw_atom * asyw,struct nv50_head_atom * asyh)153 head507d_curs_layout(struct nv50_head *head, struct nv50_wndw_atom *asyw,
154 		     struct nv50_head_atom *asyh)
155 {
156 	switch (asyw->image.w) {
157 	case 32: asyh->curs.layout = 0; break;
158 	case 64: asyh->curs.layout = 1; break;
159 	default:
160 		return -EINVAL;
161 	}
162 	return 0;
163 }
164 
165 void
head507d_core_clr(struct nv50_head * head)166 head507d_core_clr(struct nv50_head *head)
167 {
168 	struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
169 	u32 *push;
170 	if ((push = evo_wait(core, 2))) {
171 		evo_mthd(push, 0x0874 + head->base.index * 0x400, 1);
172 		evo_data(push, 0x00000000);
173 		evo_kick(push, core);
174 	}
175 }
176 
177 static void
head507d_core_set(struct nv50_head * head,struct nv50_head_atom * asyh)178 head507d_core_set(struct nv50_head *head, struct nv50_head_atom *asyh)
179 {
180 	struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
181 	u32 *push;
182 	if ((push = evo_wait(core, 9))) {
183 		evo_mthd(push, 0x0860 + head->base.index * 0x400, 1);
184 		evo_data(push, asyh->core.offset >> 8);
185 		evo_mthd(push, 0x0868 + head->base.index * 0x400, 4);
186 		evo_data(push, asyh->core.h << 16 | asyh->core.w);
187 		evo_data(push, asyh->core.layout << 20 |
188 			       (asyh->core.pitch >> 8) << 8 |
189 			       asyh->core.blocks << 8 |
190 			       asyh->core.blockh);
191 		evo_data(push, asyh->core.kind << 16 |
192 			       asyh->core.format << 8);
193 		evo_data(push, asyh->core.handle);
194 		evo_mthd(push, 0x08c0 + head->base.index * 0x400, 1);
195 		evo_data(push, asyh->core.y << 16 | asyh->core.x);
196 		evo_kick(push, core);
197 
198 		/* EVO will complain with INVALID_STATE if we have an
199 		 * active cursor and (re)specify HeadSetContextDmaIso
200 		 * without also updating HeadSetOffsetCursor.
201 		 */
202 		asyh->set.curs = asyh->curs.visible;
203 		asyh->set.olut = asyh->olut.handle != 0;
204 	}
205 }
206 
207 void
head507d_core_calc(struct nv50_head * head,struct nv50_head_atom * asyh)208 head507d_core_calc(struct nv50_head *head, struct nv50_head_atom *asyh)
209 {
210 	struct nv50_disp *disp = nv50_disp(head->base.base.dev);
211 	if ((asyh->core.visible = (asyh->base.cpp != 0))) {
212 		asyh->core.x = asyh->base.x;
213 		asyh->core.y = asyh->base.y;
214 		asyh->core.w = asyh->base.w;
215 		asyh->core.h = asyh->base.h;
216 	} else
217 	if ((asyh->core.visible = (asyh->ovly.cpp != 0)) ||
218 	    (asyh->core.visible = asyh->curs.visible)) {
219 		/*XXX: We need to either find some way of having the
220 		 *     primary base layer appear black, while still
221 		 *     being able to display the other layers, or we
222 		 *     need to allocate a dummy black surface here.
223 		 */
224 		asyh->core.x = 0;
225 		asyh->core.y = 0;
226 		asyh->core.w = asyh->state.mode.hdisplay;
227 		asyh->core.h = asyh->state.mode.vdisplay;
228 	}
229 	asyh->core.handle = disp->core->chan.vram.handle;
230 	asyh->core.offset = 0;
231 	asyh->core.format = 0xcf;
232 	asyh->core.kind = 0;
233 	asyh->core.layout = 1;
234 	asyh->core.blockh = 0;
235 	asyh->core.blocks = 0;
236 	asyh->core.pitch = ALIGN(asyh->core.w, 64) * 4;
237 }
238 
239 static void
head507d_olut_clr(struct nv50_head * head)240 head507d_olut_clr(struct nv50_head *head)
241 {
242 	struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
243 	u32 *push;
244 	if ((push = evo_wait(core, 2))) {
245 		evo_mthd(push, 0x0840 + (head->base.index * 0x400), 1);
246 		evo_data(push, 0x00000000);
247 		evo_kick(push, core);
248 	}
249 }
250 
251 static void
head507d_olut_set(struct nv50_head * head,struct nv50_head_atom * asyh)252 head507d_olut_set(struct nv50_head *head, struct nv50_head_atom *asyh)
253 {
254 	struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
255 	u32 *push;
256 	if ((push = evo_wait(core, 3))) {
257 		evo_mthd(push, 0x0840 + (head->base.index * 0x400), 2);
258 		evo_data(push, 0x80000000 | asyh->olut.mode << 30);
259 		evo_data(push, asyh->olut.offset >> 8);
260 		evo_kick(push, core);
261 	}
262 }
263 
264 #ifdef __NetBSD__
265 #define	__iomem		__lut_iomem
266 #define	readw(p)	atomic_load_relaxed((const __iomem uint16_t *)(p))
267 #define	writew(v,p)	atomic_store_relaxed((__iomem uint16_t *)(p), (v))
268 #endif
269 
270 static void
head507d_olut_load(struct drm_color_lut * in,int size,void __iomem * mem)271 head507d_olut_load(struct drm_color_lut *in, int size, void __iomem *mem)
272 {
273 	for (; size--; in++, mem += 8) {
274 		writew(drm_color_lut_extract(in->  red, 11) << 3, mem + 0);
275 		writew(drm_color_lut_extract(in->green, 11) << 3, mem + 2);
276 		writew(drm_color_lut_extract(in-> blue, 11) << 3, mem + 4);
277 	}
278 
279 	/* INTERPOLATE modes require a "next" entry to interpolate with,
280 	 * so we replicate the last entry to deal with this for now.
281 	 */
282 	writew(readw(mem - 8), mem + 0);
283 	writew(readw(mem - 6), mem + 2);
284 	writew(readw(mem - 4), mem + 4);
285 }
286 
287 bool
head507d_olut(struct nv50_head * head,struct nv50_head_atom * asyh,int size)288 head507d_olut(struct nv50_head *head, struct nv50_head_atom *asyh, int size)
289 {
290 	if (size != 256)
291 		return false;
292 
293 	if (asyh->base.cpp == 1)
294 		asyh->olut.mode = 0;
295 	else
296 		asyh->olut.mode = 1;
297 
298 	asyh->olut.load = head507d_olut_load;
299 	return true;
300 }
301 
302 void
head507d_mode(struct nv50_head * head,struct nv50_head_atom * asyh)303 head507d_mode(struct nv50_head *head, struct nv50_head_atom *asyh)
304 {
305 	struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
306 	struct nv50_head_mode *m = &asyh->mode;
307 	u32 *push;
308 	if ((push = evo_wait(core, 13))) {
309 		evo_mthd(push, 0x0804 + (head->base.index * 0x400), 2);
310 		evo_data(push, 0x00800000 | m->clock);
311 		evo_data(push, m->interlace ? 0x00000002 : 0x00000000);
312 		evo_mthd(push, 0x0810 + (head->base.index * 0x400), 7);
313 		evo_data(push, 0x00000000);
314 		evo_data(push, m->v.active  << 16 | m->h.active );
315 		evo_data(push, m->v.synce   << 16 | m->h.synce  );
316 		evo_data(push, m->v.blanke  << 16 | m->h.blanke );
317 		evo_data(push, m->v.blanks  << 16 | m->h.blanks );
318 		evo_data(push, m->v.blank2e << 16 | m->v.blank2s);
319 		evo_data(push, asyh->mode.v.blankus);
320 		evo_mthd(push, 0x082c + (head->base.index * 0x400), 1);
321 		evo_data(push, 0x00000000);
322 		evo_kick(push, core);
323 	}
324 }
325 
326 void
head507d_view(struct nv50_head * head,struct nv50_head_atom * asyh)327 head507d_view(struct nv50_head *head, struct nv50_head_atom *asyh)
328 {
329 	struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
330 	u32 *push;
331 	if ((push = evo_wait(core, 7))) {
332 		evo_mthd(push, 0x08a4 + (head->base.index * 0x400), 1);
333 		evo_data(push, 0x00000000);
334 		evo_mthd(push, 0x08c8 + (head->base.index * 0x400), 1);
335 		evo_data(push, asyh->view.iH << 16 | asyh->view.iW);
336 		evo_mthd(push, 0x08d8 + (head->base.index * 0x400), 2);
337 		evo_data(push, asyh->view.oH << 16 | asyh->view.oW);
338 		evo_data(push, asyh->view.oH << 16 | asyh->view.oW);
339 		evo_kick(push, core);
340 	}
341 }
342 
343 const struct nv50_head_func
344 head507d = {
345 	.view = head507d_view,
346 	.mode = head507d_mode,
347 	.olut = head507d_olut,
348 	.olut_size = 256,
349 	.olut_set = head507d_olut_set,
350 	.olut_clr = head507d_olut_clr,
351 	.core_calc = head507d_core_calc,
352 	.core_set = head507d_core_set,
353 	.core_clr = head507d_core_clr,
354 	.curs_layout = head507d_curs_layout,
355 	.curs_format = head507d_curs_format,
356 	.curs_set = head507d_curs_set,
357 	.curs_clr = head507d_curs_clr,
358 	.base = head507d_base,
359 	.ovly = head507d_ovly,
360 	.dither = head507d_dither,
361 	.procamp = head507d_procamp,
362 };
363