1 /*
2  * Copyright 2018 Red Hat Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20  * OTHER DEALINGS IN THE SOFTWARE.
21  */
22 #include "head.h"
23 #include "atom.h"
24 #include "core.h"
25 
26 static void
27 headc37d_or(struct nv50_head *head, struct nv50_head_atom *asyh)
28 {
29 	struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
30 	u8 depth;
31 	u32 *push;
32 
33 	if ((push = evo_wait(core, 2))) {
34 		/*XXX: This is a dirty hack until OR depth handling is
35 		 *     improved later for deep colour etc.
36 		 */
37 		switch (asyh->or.depth) {
38 		case 6: depth = 5; break;
39 		case 5: depth = 4; break;
40 		case 2: depth = 1; break;
41 		case 0:	depth = 4; break;
42 		default:
43 			depth = asyh->or.depth;
44 			WARN_ON(1);
45 			break;
46 		}
47 
48 		evo_mthd(push, 0x2004 + (head->base.index * 0x400), 1);
49 		evo_data(push, depth << 4 |
50 			       asyh->or.nvsync << 3 |
51 			       asyh->or.nhsync << 2 |
52 			       asyh->or.crc_raster);
53 		evo_kick(push, core);
54 	}
55 }
56 
57 static void
58 headc37d_procamp(struct nv50_head *head, struct nv50_head_atom *asyh)
59 {
60 	struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
61 	u32 *push;
62 	if ((push = evo_wait(core, 2))) {
63 		evo_mthd(push, 0x2000 + (head->base.index * 0x400), 1);
64 		evo_data(push, 0x80000000 |
65 			       asyh->procamp.sat.sin << 16 |
66 			       asyh->procamp.sat.cos << 4);
67 		evo_kick(push, core);
68 	}
69 }
70 
71 void
72 headc37d_dither(struct nv50_head *head, struct nv50_head_atom *asyh)
73 {
74 	struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
75 	u32 *push;
76 	if ((push = evo_wait(core, 2))) {
77 		evo_mthd(push, 0x2018 + (head->base.index * 0x0400), 1);
78 		evo_data(push, asyh->dither.mode << 8 |
79 			       asyh->dither.bits << 4 |
80 			       asyh->dither.enable);
81 		evo_kick(push, core);
82 	}
83 }
84 
85 void
86 headc37d_curs_clr(struct nv50_head *head)
87 {
88 	struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
89 	u32 *push;
90 	if ((push = evo_wait(core, 4))) {
91 		evo_mthd(push, 0x209c + head->base.index * 0x400, 1);
92 		evo_data(push, 0x000000cf);
93 		evo_mthd(push, 0x2088 + head->base.index * 0x400, 1);
94 		evo_data(push, 0x00000000);
95 		evo_kick(push, core);
96 	}
97 }
98 
99 void
100 headc37d_curs_set(struct nv50_head *head, struct nv50_head_atom *asyh)
101 {
102 	struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
103 	u32 *push;
104 	if ((push = evo_wait(core, 7))) {
105 		evo_mthd(push, 0x209c + head->base.index * 0x400, 2);
106 		evo_data(push, 0x80000000 |
107 			       asyh->curs.layout << 8 |
108 			       asyh->curs.format << 0);
109 		evo_data(push, 0x000072ff);
110 		evo_mthd(push, 0x2088 + head->base.index * 0x400, 1);
111 		evo_data(push, asyh->curs.handle);
112 		evo_mthd(push, 0x2090 + head->base.index * 0x400, 1);
113 		evo_data(push, asyh->curs.offset >> 8);
114 		evo_kick(push, core);
115 	}
116 }
117 
118 int
119 headc37d_curs_format(struct nv50_head *head, struct nv50_wndw_atom *asyw,
120 		     struct nv50_head_atom *asyh)
121 {
122 	asyh->curs.format = asyw->image.format;
123 	return 0;
124 }
125 
126 static void
127 headc37d_olut_clr(struct nv50_head *head)
128 {
129 	struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
130 	u32 *push;
131 	if ((push = evo_wait(core, 2))) {
132 		evo_mthd(push, 0x20ac + (head->base.index * 0x400), 1);
133 		evo_data(push, 0x00000000);
134 		evo_kick(push, core);
135 	}
136 }
137 
138 static void
139 headc37d_olut_set(struct nv50_head *head, struct nv50_head_atom *asyh)
140 {
141 	struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
142 	u32 *push;
143 	if ((push = evo_wait(core, 4))) {
144 		evo_mthd(push, 0x20a4 + (head->base.index * 0x400), 3);
145 		evo_data(push, asyh->olut.output_mode << 8 |
146 			       asyh->olut.range << 4 |
147 			       asyh->olut.size);
148 		evo_data(push, asyh->olut.offset >> 8);
149 		evo_data(push, asyh->olut.handle);
150 		evo_kick(push, core);
151 	}
152 }
153 
154 static bool
155 headc37d_olut(struct nv50_head *head, struct nv50_head_atom *asyh, int size)
156 {
157 	if (size != 256 && size != 1024)
158 		return false;
159 
160 	asyh->olut.mode = 2;
161 	asyh->olut.size = size == 1024 ? 2 : 0;
162 	asyh->olut.range = 0;
163 	asyh->olut.output_mode = 1;
164 	asyh->olut.load = head907d_olut_load;
165 	return true;
166 }
167 
168 static void
169 headc37d_mode(struct nv50_head *head, struct nv50_head_atom *asyh)
170 {
171 	struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
172 	struct nv50_head_mode *m = &asyh->mode;
173 	u32 *push;
174 	if ((push = evo_wait(core, 13))) {
175 		evo_mthd(push, 0x2064 + (head->base.index * 0x400), 5);
176 		evo_data(push, (m->v.active  << 16) | m->h.active );
177 		evo_data(push, (m->v.synce   << 16) | m->h.synce  );
178 		evo_data(push, (m->v.blanke  << 16) | m->h.blanke );
179 		evo_data(push, (m->v.blanks  << 16) | m->h.blanks );
180 		evo_data(push, (m->v.blank2e << 16) | m->v.blank2s);
181 		evo_mthd(push, 0x2008 + (head->base.index * 0x400), 2);
182 		evo_data(push, m->interlace);
183 		evo_data(push, m->clock * 1000);
184 		evo_mthd(push, 0x2028 + (head->base.index * 0x400), 1);
185 		evo_data(push, m->clock * 1000);
186 		/*XXX: HEAD_USAGE_BOUNDS, doesn't belong here. */
187 		evo_mthd(push, 0x2030 + (head->base.index * 0x400), 1);
188 		evo_data(push, 0x00000124);
189 		evo_kick(push, core);
190 	}
191 }
192 
193 void
194 headc37d_view(struct nv50_head *head, struct nv50_head_atom *asyh)
195 {
196 	struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->core->chan;
197 	u32 *push;
198 	if ((push = evo_wait(core, 4))) {
199 		evo_mthd(push, 0x204c + (head->base.index * 0x400), 1);
200 		evo_data(push, (asyh->view.iH << 16) | asyh->view.iW);
201 		evo_mthd(push, 0x2058 + (head->base.index * 0x400), 1);
202 		evo_data(push, (asyh->view.oH << 16) | asyh->view.oW);
203 		evo_kick(push, core);
204 	}
205 }
206 
207 void
208 headc37d_static_wndw_map(struct nv50_head *head, struct nv50_head_atom *asyh)
209 {
210 	int i, end;
211 
212 	for (i = head->base.index * 2, end = i + 2; i < end; i++)
213 		asyh->wndw.owned |= BIT(i);
214 }
215 
216 const struct nv50_head_func
217 headc37d = {
218 	.view = headc37d_view,
219 	.mode = headc37d_mode,
220 	.olut = headc37d_olut,
221 	.olut_size = 1024,
222 	.olut_set = headc37d_olut_set,
223 	.olut_clr = headc37d_olut_clr,
224 	.curs_layout = head917d_curs_layout,
225 	.curs_format = headc37d_curs_format,
226 	.curs_set = headc37d_curs_set,
227 	.curs_clr = headc37d_curs_clr,
228 	.dither = headc37d_dither,
229 	.procamp = headc37d_procamp,
230 	.or = headc37d_or,
231 	.static_wndw_map = headc37d_static_wndw_map,
232 };
233