xref: /netbsd-src/sys/external/bsd/drm2/dist/drm/nouveau/dispnv50/nouveau_dispnv50_headc57d.c (revision 1b592f33a70528671836bfa092de3e80d93631f4)
1 /*	$NetBSD: nouveau_dispnv50_headc57d.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_headc57d.c,v 1.4 2021/12/19 10:49:47 riastradh Exp $");
26 
27 #include "head.h"
28 #include "atom.h"
29 #include "core.h"
30 
31 static void
headc57d_or(struct nv50_head * head,struct nv50_head_atom * asyh)32 headc57d_or(struct nv50_head *head, struct nv50_head_atom *asyh)
33 {
34 	struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
35 	u32 *push;
36 	if ((push = evo_wait(core, 2))) {
37 		/*XXX: This is a dirty hack until OR depth handling is
38 		 *     improved later for deep colour etc.
39 		 */
40 		switch (asyh->or.depth) {
41 		case 6: asyh->or.depth = 5; break;
42 		case 5: asyh->or.depth = 4; break;
43 		case 2: asyh->or.depth = 1; break;
44 		case 0:	asyh->or.depth = 4; break;
45 		default:
46 			WARN_ON(1);
47 			break;
48 		}
49 
50 		evo_mthd(push, 0x2004 + (head->base.index * 0x400), 1);
51 		evo_data(push, 0xfc000001 |
52 			       asyh->or.depth << 4 |
53 			       asyh->or.nvsync << 3 |
54 			       asyh->or.nhsync << 2);
55 		evo_kick(push, core);
56 	}
57 }
58 
59 static void
headc57d_procamp(struct nv50_head * head,struct nv50_head_atom * asyh)60 headc57d_procamp(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 *push;
64 	if ((push = evo_wait(core, 2))) {
65 		evo_mthd(push, 0x2000 + (head->base.index * 0x400), 1);
66 #if 0
67 		evo_data(push, 0x80000000 |
68 			       asyh->procamp.sat.sin << 16 |
69 			       asyh->procamp.sat.cos << 4);
70 #else
71 		evo_data(push, 0);
72 #endif
73 		evo_kick(push, core);
74 	}
75 }
76 
77 static void
headc57d_olut_clr(struct nv50_head * head)78 headc57d_olut_clr(struct nv50_head *head)
79 {
80 	struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
81 	u32 *push;
82 	if ((push = evo_wait(core, 2))) {
83 		evo_mthd(push, 0x2288 + (head->base.index * 0x400), 1);
84 		evo_data(push, 0x00000000);
85 		evo_kick(push, core);
86 	}
87 }
88 
89 static void
headc57d_olut_set(struct nv50_head * head,struct nv50_head_atom * asyh)90 headc57d_olut_set(struct nv50_head *head, struct nv50_head_atom *asyh)
91 {
92 	struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
93 	u32 *push;
94 	if ((push = evo_wait(core, 4))) {
95 		evo_mthd(push, 0x2280 + (head->base.index * 0x400), 4);
96 		evo_data(push, asyh->olut.size << 8 |
97 			       asyh->olut.mode << 2 |
98 			       asyh->olut.output_mode);
99 		evo_data(push, 0xffffffff); /* FP_NORM_SCALE. */
100 		evo_data(push, asyh->olut.handle);
101 		evo_data(push, asyh->olut.offset >> 8);
102 		evo_kick(push, core);
103 	}
104 }
105 
106 #ifdef __NetBSD__
107 #define	__iomem		__lut_iomem
108 #define	readw(p)	atomic_load_relaxed((const __iomem uint16_t *)(p))
109 #define	writew(v,p)	atomic_store_relaxed((__iomem uint16_t *)(p), (v))
110 #endif
111 
112 static void
headc57d_olut_load_8(struct drm_color_lut * in,int size,void __iomem * mem)113 headc57d_olut_load_8(struct drm_color_lut *in, int size, void __iomem *mem)
114 {
115 	memset_io(mem, 0x00, 0x20); /* VSS header. */
116 	mem += 0x20;
117 
118 	while (size--) {
119 		u16 r = drm_color_lut_extract(in->  red + 0, 16);
120 		u16 g = drm_color_lut_extract(in->green + 0, 16);
121 		u16 b = drm_color_lut_extract(in-> blue + 0, 16);
122 		u16 ri = 0, gi = 0, bi = 0, i;
123 
124 		if (in++, size) {
125 			ri = (drm_color_lut_extract(in->  red, 16) - r) / 4;
126 			gi = (drm_color_lut_extract(in->green, 16) - g) / 4;
127 			bi = (drm_color_lut_extract(in-> blue, 16) - b) / 4;
128 		}
129 
130 		for (i = 0; i < 4; i++, mem += 8) {
131 			writew(r + ri * i, mem + 0);
132 			writew(g + gi * i, mem + 2);
133 			writew(b + bi * i, mem + 4);
134 		}
135 	}
136 
137 	/* INTERPOLATE modes require a "next" entry to interpolate with,
138 	 * so we replicate the last entry to deal with this for now.
139 	 */
140 	writew(readw(mem - 8), mem + 0);
141 	writew(readw(mem - 6), mem + 2);
142 	writew(readw(mem - 4), mem + 4);
143 }
144 
145 static void
headc57d_olut_load(struct drm_color_lut * in,int size,void __iomem * mem)146 headc57d_olut_load(struct drm_color_lut *in, int size, void __iomem *mem)
147 {
148 	memset_io(mem, 0x00, 0x20); /* VSS header. */
149 	mem += 0x20;
150 
151 	for (; size--; in++, mem += 0x08) {
152 		writew(drm_color_lut_extract(in->  red, 16), mem + 0);
153 		writew(drm_color_lut_extract(in->green, 16), mem + 2);
154 		writew(drm_color_lut_extract(in-> blue, 16), mem + 4);
155 	}
156 
157 	/* INTERPOLATE modes require a "next" entry to interpolate with,
158 	 * so we replicate the last entry to deal with this for now.
159 	 */
160 	writew(readw(mem - 8), mem + 0);
161 	writew(readw(mem - 6), mem + 2);
162 	writew(readw(mem - 4), mem + 4);
163 }
164 
165 static bool
headc57d_olut(struct nv50_head * head,struct nv50_head_atom * asyh,int size)166 headc57d_olut(struct nv50_head *head, struct nv50_head_atom *asyh, int size)
167 {
168 	if (size != 0 && size != 256 && size != 1024)
169 		return false;
170 
171 	asyh->olut.mode = 2; /* DIRECT10 */
172 	asyh->olut.size = 4 /* VSS header. */ + 1024 + 1 /* Entries. */;
173 	asyh->olut.output_mode = 1; /* INTERPOLATE_ENABLE. */
174 	if (size == 256)
175 		asyh->olut.load = headc57d_olut_load_8;
176 	else
177 		asyh->olut.load = headc57d_olut_load;
178 	return true;
179 }
180 
181 static void
headc57d_mode(struct nv50_head * head,struct nv50_head_atom * asyh)182 headc57d_mode(struct nv50_head *head, struct nv50_head_atom *asyh)
183 {
184 	struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
185 	struct nv50_head_mode *m = &asyh->mode;
186 	u32 *push;
187 	if ((push = evo_wait(core, 12))) {
188 		evo_mthd(push, 0x2064 + (head->base.index * 0x400), 5);
189 		evo_data(push, (m->v.active  << 16) | m->h.active );
190 		evo_data(push, (m->v.synce   << 16) | m->h.synce  );
191 		evo_data(push, (m->v.blanke  << 16) | m->h.blanke );
192 		evo_data(push, (m->v.blanks  << 16) | m->h.blanks );
193 		evo_data(push, (m->v.blank2e << 16) | m->v.blank2s);
194 		evo_mthd(push, 0x200c + (head->base.index * 0x400), 1);
195 		evo_data(push, m->clock * 1000);
196 		evo_mthd(push, 0x2028 + (head->base.index * 0x400), 1);
197 		evo_data(push, m->clock * 1000);
198 		/*XXX: HEAD_USAGE_BOUNDS, doesn't belong here. */
199 		evo_mthd(push, 0x2030 + (head->base.index * 0x400), 1);
200 		evo_data(push, 0x00001014);
201 		evo_kick(push, core);
202 	}
203 }
204 
205 const struct nv50_head_func
206 headc57d = {
207 	.view = headc37d_view,
208 	.mode = headc57d_mode,
209 	.olut = headc57d_olut,
210 	.olut_identity = true,
211 	.olut_size = 1024,
212 	.olut_set = headc57d_olut_set,
213 	.olut_clr = headc57d_olut_clr,
214 	.curs_layout = head917d_curs_layout,
215 	.curs_format = headc37d_curs_format,
216 	.curs_set = headc37d_curs_set,
217 	.curs_clr = headc37d_curs_clr,
218 	.dither = headc37d_dither,
219 	.procamp = headc57d_procamp,
220 	.or = headc57d_or,
221 };
222