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 <drm/drm_connector.h>
23 #include <drm/drm_mode_config.h>
24 #include <drm/drm_vblank.h>
25 #include "nouveau_drv.h"
26 #include "nouveau_bios.h"
27 #include "nouveau_connector.h"
28 #include "head.h"
29 #include "core.h"
30 #include "crc.h"
31
32 #include <nvif/push507c.h>
33
34 #include <nvhw/class/cl907d.h>
35
36 int
head907d_or(struct nv50_head * head,struct nv50_head_atom * asyh)37 head907d_or(struct nv50_head *head, struct nv50_head_atom *asyh)
38 {
39 struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
40 const int i = head->base.index;
41 int ret;
42
43 if ((ret = PUSH_WAIT(push, 3)))
44 return ret;
45
46 PUSH_MTHD(push, NV907D, HEAD_SET_CONTROL_OUTPUT_RESOURCE(i),
47 NVVAL(NV907D, HEAD_SET_CONTROL_OUTPUT_RESOURCE, CRC_MODE, asyh->or.crc_raster) |
48 NVVAL(NV907D, HEAD_SET_CONTROL_OUTPUT_RESOURCE, HSYNC_POLARITY, asyh->or.nhsync) |
49 NVVAL(NV907D, HEAD_SET_CONTROL_OUTPUT_RESOURCE, VSYNC_POLARITY, asyh->or.nvsync) |
50 NVVAL(NV907D, HEAD_SET_CONTROL_OUTPUT_RESOURCE, PIXEL_DEPTH, asyh->or.depth),
51
52 HEAD_SET_CONTROL(i), 0x31ec6000 | head->base.index << 25 |
53 NVVAL(NV907D, HEAD_SET_CONTROL, STRUCTURE, asyh->mode.interlace));
54 return 0;
55 }
56
57 int
head907d_procamp(struct nv50_head * head,struct nv50_head_atom * asyh)58 head907d_procamp(struct nv50_head *head, struct nv50_head_atom *asyh)
59 {
60 struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
61 const int i = head->base.index;
62 int ret;
63
64 if ((ret = PUSH_WAIT(push, 2)))
65 return ret;
66
67 PUSH_MTHD(push, NV907D, HEAD_SET_PROCAMP(i),
68 NVDEF(NV907D, HEAD_SET_PROCAMP, COLOR_SPACE, RGB) |
69 NVDEF(NV907D, HEAD_SET_PROCAMP, CHROMA_LPF, AUTO) |
70 NVVAL(NV907D, HEAD_SET_PROCAMP, SAT_COS, asyh->procamp.sat.cos) |
71 NVVAL(NV907D, HEAD_SET_PROCAMP, SAT_SINE, asyh->procamp.sat.sin) |
72 NVDEF(NV907D, HEAD_SET_PROCAMP, DYNAMIC_RANGE, VESA) |
73 NVDEF(NV907D, HEAD_SET_PROCAMP, RANGE_COMPRESSION, DISABLE));
74 return 0;
75 }
76
77 static int
head907d_dither(struct nv50_head * head,struct nv50_head_atom * asyh)78 head907d_dither(struct nv50_head *head, struct nv50_head_atom *asyh)
79 {
80 struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
81 const int i = head->base.index;
82 int ret;
83
84 if ((ret = PUSH_WAIT(push, 2)))
85 return ret;
86
87 PUSH_MTHD(push, NV907D, HEAD_SET_DITHER_CONTROL(i),
88 NVVAL(NV907D, HEAD_SET_DITHER_CONTROL, ENABLE, asyh->dither.enable) |
89 NVVAL(NV907D, HEAD_SET_DITHER_CONTROL, BITS, asyh->dither.bits) |
90 NVVAL(NV907D, HEAD_SET_DITHER_CONTROL, MODE, asyh->dither.mode) |
91 NVVAL(NV907D, HEAD_SET_DITHER_CONTROL, PHASE, 0));
92 return 0;
93 }
94
95 int
head907d_ovly(struct nv50_head * head,struct nv50_head_atom * asyh)96 head907d_ovly(struct nv50_head *head, struct nv50_head_atom *asyh)
97 {
98 struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
99 const int i = head->base.index;
100 u32 bounds = 0;
101 int ret;
102
103 if (asyh->ovly.cpp) {
104 switch (asyh->ovly.cpp) {
105 case 8: bounds |= NVDEF(NV907D, HEAD_SET_OVERLAY_USAGE_BOUNDS, PIXEL_DEPTH, BPP_64); break;
106 case 4: bounds |= NVDEF(NV907D, HEAD_SET_OVERLAY_USAGE_BOUNDS, PIXEL_DEPTH, BPP_32); break;
107 case 2: bounds |= NVDEF(NV907D, HEAD_SET_OVERLAY_USAGE_BOUNDS, PIXEL_DEPTH, BPP_16); break;
108 default:
109 WARN_ON(1);
110 break;
111 }
112 bounds |= NVDEF(NV907D, HEAD_SET_OVERLAY_USAGE_BOUNDS, USABLE, TRUE);
113 } else {
114 bounds |= NVDEF(NV907D, HEAD_SET_OVERLAY_USAGE_BOUNDS, PIXEL_DEPTH, BPP_16);
115 }
116
117 if ((ret = PUSH_WAIT(push, 2)))
118 return ret;
119
120 PUSH_MTHD(push, NV907D, HEAD_SET_OVERLAY_USAGE_BOUNDS(i), bounds);
121 return 0;
122 }
123
124 static int
head907d_base(struct nv50_head * head,struct nv50_head_atom * asyh)125 head907d_base(struct nv50_head *head, struct nv50_head_atom *asyh)
126 {
127 struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
128 const int i = head->base.index;
129 u32 bounds = 0;
130 int ret;
131
132 if (asyh->base.cpp) {
133 switch (asyh->base.cpp) {
134 case 8: bounds |= NVDEF(NV907D, HEAD_SET_BASE_CHANNEL_USAGE_BOUNDS, PIXEL_DEPTH, BPP_64); break;
135 case 4: bounds |= NVDEF(NV907D, HEAD_SET_BASE_CHANNEL_USAGE_BOUNDS, PIXEL_DEPTH, BPP_32); break;
136 case 2: bounds |= NVDEF(NV907D, HEAD_SET_BASE_CHANNEL_USAGE_BOUNDS, PIXEL_DEPTH, BPP_16); break;
137 case 1: bounds |= NVDEF(NV907D, HEAD_SET_BASE_CHANNEL_USAGE_BOUNDS, PIXEL_DEPTH, BPP_8); break;
138 default:
139 WARN_ON(1);
140 break;
141 }
142 bounds |= NVDEF(NV907D, HEAD_SET_BASE_CHANNEL_USAGE_BOUNDS, USABLE, TRUE);
143 }
144
145 if ((ret = PUSH_WAIT(push, 2)))
146 return ret;
147
148 PUSH_MTHD(push, NV907D, HEAD_SET_BASE_CHANNEL_USAGE_BOUNDS(i), bounds);
149 return 0;
150 }
151
152 int
head907d_curs_clr(struct nv50_head * head)153 head907d_curs_clr(struct nv50_head *head)
154 {
155 struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
156 const int i = head->base.index;
157 int ret;
158
159 if ((ret = PUSH_WAIT(push, 4)))
160 return ret;
161
162 PUSH_MTHD(push, NV907D, HEAD_SET_CONTROL_CURSOR(i),
163 NVDEF(NV907D, HEAD_SET_CONTROL_CURSOR, ENABLE, DISABLE) |
164 NVDEF(NV907D, HEAD_SET_CONTROL_CURSOR, FORMAT, A8R8G8B8) |
165 NVDEF(NV907D, HEAD_SET_CONTROL_CURSOR, SIZE, W64_H64));
166
167 PUSH_MTHD(push, NV907D, HEAD_SET_CONTEXT_DMA_CURSOR(i), 0x00000000);
168 return 0;
169 }
170
171 int
head907d_curs_set(struct nv50_head * head,struct nv50_head_atom * asyh)172 head907d_curs_set(struct nv50_head *head, struct nv50_head_atom *asyh)
173 {
174 struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
175 const int i = head->base.index;
176 int ret;
177
178 if ((ret = PUSH_WAIT(push, 5)))
179 return ret;
180
181 PUSH_MTHD(push, NV907D, HEAD_SET_CONTROL_CURSOR(i),
182 NVDEF(NV907D, HEAD_SET_CONTROL_CURSOR, ENABLE, ENABLE) |
183 NVVAL(NV907D, HEAD_SET_CONTROL_CURSOR, FORMAT, asyh->curs.format) |
184 NVVAL(NV907D, HEAD_SET_CONTROL_CURSOR, SIZE, asyh->curs.layout) |
185 NVVAL(NV907D, HEAD_SET_CONTROL_CURSOR, HOT_SPOT_X, 0) |
186 NVVAL(NV907D, HEAD_SET_CONTROL_CURSOR, HOT_SPOT_Y, 0) |
187 NVDEF(NV907D, HEAD_SET_CONTROL_CURSOR, COMPOSITION, ALPHA_BLEND),
188
189 HEAD_SET_OFFSET_CURSOR(i), asyh->curs.offset >> 8);
190
191 PUSH_MTHD(push, NV907D, HEAD_SET_CONTEXT_DMA_CURSOR(i), asyh->curs.handle);
192 return 0;
193 }
194
195 int
head907d_core_clr(struct nv50_head * head)196 head907d_core_clr(struct nv50_head *head)
197 {
198 struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
199 const int i = head->base.index;
200 int ret;
201
202 if ((ret = PUSH_WAIT(push, 2)))
203 return ret;
204
205 PUSH_MTHD(push, NV907D, HEAD_SET_CONTEXT_DMAS_ISO(i), 0x00000000);
206 return 0;
207 }
208
209 int
head907d_core_set(struct nv50_head * head,struct nv50_head_atom * asyh)210 head907d_core_set(struct nv50_head *head, struct nv50_head_atom *asyh)
211 {
212 struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
213 const int i = head->base.index;
214 int ret;
215
216 if ((ret = PUSH_WAIT(push, 9)))
217 return ret;
218
219 PUSH_MTHD(push, NV907D, HEAD_SET_OFFSET(i),
220 NVVAL(NV907D, HEAD_SET_OFFSET, ORIGIN, asyh->core.offset >> 8));
221
222 PUSH_MTHD(push, NV907D, HEAD_SET_SIZE(i),
223 NVVAL(NV907D, HEAD_SET_SIZE, WIDTH, asyh->core.w) |
224 NVVAL(NV907D, HEAD_SET_SIZE, HEIGHT, asyh->core.h),
225
226 HEAD_SET_STORAGE(i),
227 NVVAL(NV907D, HEAD_SET_STORAGE, BLOCK_HEIGHT, asyh->core.blockh) |
228 NVVAL(NV907D, HEAD_SET_STORAGE, PITCH, asyh->core.pitch >> 8) |
229 NVVAL(NV907D, HEAD_SET_STORAGE, PITCH, asyh->core.blocks) |
230 NVVAL(NV907D, HEAD_SET_STORAGE, MEMORY_LAYOUT, asyh->core.layout),
231
232 HEAD_SET_PARAMS(i),
233 NVVAL(NV907D, HEAD_SET_PARAMS, FORMAT, asyh->core.format) |
234 NVDEF(NV907D, HEAD_SET_PARAMS, SUPER_SAMPLE, X1_AA) |
235 NVDEF(NV907D, HEAD_SET_PARAMS, GAMMA, LINEAR),
236
237 HEAD_SET_CONTEXT_DMAS_ISO(i),
238 NVVAL(NV907D, HEAD_SET_CONTEXT_DMAS_ISO, HANDLE, asyh->core.handle));
239
240 PUSH_MTHD(push, NV907D, HEAD_SET_VIEWPORT_POINT_IN(i),
241 NVVAL(NV907D, HEAD_SET_VIEWPORT_POINT_IN, X, asyh->core.x) |
242 NVVAL(NV907D, HEAD_SET_VIEWPORT_POINT_IN, Y, asyh->core.y));
243 return 0;
244 }
245
246 int
head907d_olut_clr(struct nv50_head * head)247 head907d_olut_clr(struct nv50_head *head)
248 {
249 struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
250 const int i = head->base.index;
251 int ret;
252
253 if ((ret = PUSH_WAIT(push, 4)))
254 return ret;
255
256 PUSH_MTHD(push, NV907D, HEAD_SET_OUTPUT_LUT_LO(i),
257 NVDEF(NV907D, HEAD_SET_OUTPUT_LUT_LO, ENABLE, DISABLE));
258
259 PUSH_MTHD(push, NV907D, HEAD_SET_CONTEXT_DMA_LUT(i), 0x00000000);
260 return 0;
261 }
262
263 int
head907d_olut_set(struct nv50_head * head,struct nv50_head_atom * asyh)264 head907d_olut_set(struct nv50_head *head, struct nv50_head_atom *asyh)
265 {
266 struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
267 const int i = head->base.index;
268 int ret;
269
270 if ((ret = PUSH_WAIT(push, 5)))
271 return ret;
272
273 PUSH_MTHD(push, NV907D, HEAD_SET_OUTPUT_LUT_LO(i),
274 NVDEF(NV907D, HEAD_SET_OUTPUT_LUT_LO, ENABLE, ENABLE) |
275 NVVAL(NV907D, HEAD_SET_OUTPUT_LUT_LO, MODE, asyh->olut.mode) |
276 NVDEF(NV907D, HEAD_SET_OUTPUT_LUT_LO, NEVER_YIELD_TO_BASE, DISABLE),
277
278 HEAD_SET_OUTPUT_LUT_HI(i),
279 NVVAL(NV907D, HEAD_SET_OUTPUT_LUT_HI, ORIGIN, asyh->olut.offset >> 8));
280
281 PUSH_MTHD(push, NV907D, HEAD_SET_CONTEXT_DMA_LUT(i), asyh->olut.handle);
282 return 0;
283 }
284
285 void
head907d_olut_load(struct drm_color_lut * in,int size,void __iomem * mem)286 head907d_olut_load(struct drm_color_lut *in, int size, void __iomem *mem)
287 {
288 for (; size--; in++, mem += 8) {
289 writew(drm_color_lut_extract(in-> red, 14) + 0x6000, mem + 0);
290 writew(drm_color_lut_extract(in->green, 14) + 0x6000, mem + 2);
291 writew(drm_color_lut_extract(in-> blue, 14) + 0x6000, mem + 4);
292 }
293
294 /* INTERPOLATE modes require a "next" entry to interpolate with,
295 * so we replicate the last entry to deal with this for now.
296 */
297 writew(readw(mem - 8), mem + 0);
298 writew(readw(mem - 6), mem + 2);
299 writew(readw(mem - 4), mem + 4);
300 }
301
302 bool
head907d_olut(struct nv50_head * head,struct nv50_head_atom * asyh,int size)303 head907d_olut(struct nv50_head *head, struct nv50_head_atom *asyh, int size)
304 {
305 if (size != 256 && size != 1024)
306 return false;
307
308 if (size == 1024)
309 asyh->olut.mode = NV907D_HEAD_SET_OUTPUT_LUT_LO_MODE_INTERPOLATE_1025_UNITY_RANGE;
310 else
311 asyh->olut.mode = NV907D_HEAD_SET_OUTPUT_LUT_LO_MODE_INTERPOLATE_257_UNITY_RANGE;
312
313 asyh->olut.load = head907d_olut_load;
314 return true;
315 }
316
317 int
head907d_mode(struct nv50_head * head,struct nv50_head_atom * asyh)318 head907d_mode(struct nv50_head *head, struct nv50_head_atom *asyh)
319 {
320 struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
321 struct nv50_head_mode *m = &asyh->mode;
322 const int i = head->base.index;
323 int ret;
324
325 if ((ret = PUSH_WAIT(push, 13)))
326 return ret;
327
328 PUSH_MTHD(push, NV907D, HEAD_SET_OVERSCAN_COLOR(i),
329 NVVAL(NV907D, HEAD_SET_OVERSCAN_COLOR, RED, 0) |
330 NVVAL(NV907D, HEAD_SET_OVERSCAN_COLOR, GRN, 0) |
331 NVVAL(NV907D, HEAD_SET_OVERSCAN_COLOR, BLU, 0),
332
333 HEAD_SET_RASTER_SIZE(i),
334 NVVAL(NV907D, HEAD_SET_RASTER_SIZE, WIDTH, m->h.active) |
335 NVVAL(NV907D, HEAD_SET_RASTER_SIZE, HEIGHT, m->v.active),
336
337 HEAD_SET_RASTER_SYNC_END(i),
338 NVVAL(NV907D, HEAD_SET_RASTER_SYNC_END, X, m->h.synce) |
339 NVVAL(NV907D, HEAD_SET_RASTER_SYNC_END, Y, m->v.synce),
340
341 HEAD_SET_RASTER_BLANK_END(i),
342 NVVAL(NV907D, HEAD_SET_RASTER_BLANK_END, X, m->h.blanke) |
343 NVVAL(NV907D, HEAD_SET_RASTER_BLANK_END, Y, m->v.blanke),
344
345 HEAD_SET_RASTER_BLANK_START(i),
346 NVVAL(NV907D, HEAD_SET_RASTER_BLANK_START, X, m->h.blanks) |
347 NVVAL(NV907D, HEAD_SET_RASTER_BLANK_START, Y, m->v.blanks),
348
349 HEAD_SET_RASTER_VERT_BLANK2(i),
350 NVVAL(NV907D, HEAD_SET_RASTER_VERT_BLANK2, YSTART, m->v.blank2s) |
351 NVVAL(NV907D, HEAD_SET_RASTER_VERT_BLANK2, YEND, m->v.blank2e));
352
353 PUSH_MTHD(push, NV907D, HEAD_SET_DEFAULT_BASE_COLOR(i),
354 NVVAL(NV907D, HEAD_SET_DEFAULT_BASE_COLOR, RED, 0) |
355 NVVAL(NV907D, HEAD_SET_DEFAULT_BASE_COLOR, GREEN, 0) |
356 NVVAL(NV907D, HEAD_SET_DEFAULT_BASE_COLOR, BLUE, 0));
357
358 PUSH_MTHD(push, NV907D, HEAD_SET_PIXEL_CLOCK_FREQUENCY(i),
359 NVVAL(NV907D, HEAD_SET_PIXEL_CLOCK_FREQUENCY, HERTZ, m->clock * 1000) |
360 NVDEF(NV907D, HEAD_SET_PIXEL_CLOCK_FREQUENCY, ADJ1000DIV1001, FALSE),
361
362 HEAD_SET_PIXEL_CLOCK_CONFIGURATION(i),
363 NVDEF(NV907D, HEAD_SET_PIXEL_CLOCK_CONFIGURATION, MODE, CLK_CUSTOM) |
364 NVDEF(NV907D, HEAD_SET_PIXEL_CLOCK_CONFIGURATION, NOT_DRIVER, FALSE) |
365 NVDEF(NV907D, HEAD_SET_PIXEL_CLOCK_CONFIGURATION, ENABLE_HOPPING, FALSE),
366
367 HEAD_SET_PIXEL_CLOCK_FREQUENCY_MAX(i),
368 NVVAL(NV907D, HEAD_SET_PIXEL_CLOCK_FREQUENCY_MAX, HERTZ, m->clock * 1000) |
369 NVDEF(NV907D, HEAD_SET_PIXEL_CLOCK_FREQUENCY_MAX, ADJ1000DIV1001, FALSE));
370 return 0;
371 }
372
373 int
head907d_view(struct nv50_head * head,struct nv50_head_atom * asyh)374 head907d_view(struct nv50_head *head, struct nv50_head_atom *asyh)
375 {
376 struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
377 const int i = head->base.index;
378 int ret;
379
380 if ((ret = PUSH_WAIT(push, 8)))
381 return ret;
382
383 PUSH_MTHD(push, NV907D, HEAD_SET_CONTROL_OUTPUT_SCALER(i),
384 NVDEF(NV907D, HEAD_SET_CONTROL_OUTPUT_SCALER, VERTICAL_TAPS, TAPS_1) |
385 NVDEF(NV907D, HEAD_SET_CONTROL_OUTPUT_SCALER, HORIZONTAL_TAPS, TAPS_1) |
386 NVVAL(NV907D, HEAD_SET_CONTROL_OUTPUT_SCALER, HRESPONSE_BIAS, 0) |
387 NVVAL(NV907D, HEAD_SET_CONTROL_OUTPUT_SCALER, VRESPONSE_BIAS, 0));
388
389 PUSH_MTHD(push, NV907D, HEAD_SET_VIEWPORT_SIZE_IN(i),
390 NVVAL(NV907D, HEAD_SET_VIEWPORT_SIZE_IN, WIDTH, asyh->view.iW) |
391 NVVAL(NV907D, HEAD_SET_VIEWPORT_SIZE_IN, HEIGHT, asyh->view.iH));
392
393 PUSH_MTHD(push, NV907D, HEAD_SET_VIEWPORT_SIZE_OUT(i),
394 NVVAL(NV907D, HEAD_SET_VIEWPORT_SIZE_OUT, WIDTH, asyh->view.oW) |
395 NVVAL(NV907D, HEAD_SET_VIEWPORT_SIZE_OUT, HEIGHT, asyh->view.oH),
396
397 HEAD_SET_VIEWPORT_SIZE_OUT_MIN(i),
398 NVVAL(NV907D, HEAD_SET_VIEWPORT_SIZE_OUT_MIN, WIDTH, asyh->view.oW) |
399 NVVAL(NV907D, HEAD_SET_VIEWPORT_SIZE_OUT_MIN, HEIGHT, asyh->view.oH),
400
401 HEAD_SET_VIEWPORT_SIZE_OUT_MAX(i),
402 NVVAL(NV907D, HEAD_SET_VIEWPORT_SIZE_OUT_MAX, WIDTH, asyh->view.oW) |
403 NVVAL(NV907D, HEAD_SET_VIEWPORT_SIZE_OUT_MAX, HEIGHT, asyh->view.oH));
404 return 0;
405 }
406
407 const struct nv50_head_func
408 head907d = {
409 .view = head907d_view,
410 .mode = head907d_mode,
411 .olut = head907d_olut,
412 .olut_size = 1024,
413 .olut_set = head907d_olut_set,
414 .olut_clr = head907d_olut_clr,
415 .core_calc = head507d_core_calc,
416 .core_set = head907d_core_set,
417 .core_clr = head907d_core_clr,
418 .curs_layout = head507d_curs_layout,
419 .curs_format = head507d_curs_format,
420 .curs_set = head907d_curs_set,
421 .curs_clr = head907d_curs_clr,
422 .base = head907d_base,
423 .ovly = head907d_ovly,
424 .dither = head907d_dither,
425 .procamp = head907d_procamp,
426 .or = head907d_or,
427 };
428