1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright 2018 Red Hat Inc.
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Permission is hereby granted, free of charge, to any person obtaining a
5*4882a593Smuzhiyun * copy of this software and associated documentation files (the "Software"),
6*4882a593Smuzhiyun * to deal in the Software without restriction, including without limitation
7*4882a593Smuzhiyun * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8*4882a593Smuzhiyun * and/or sell copies of the Software, and to permit persons to whom the
9*4882a593Smuzhiyun * Software is furnished to do so, subject to the following conditions:
10*4882a593Smuzhiyun *
11*4882a593Smuzhiyun * The above copyright notice and this permission notice shall be included in
12*4882a593Smuzhiyun * all copies or substantial portions of the Software.
13*4882a593Smuzhiyun *
14*4882a593Smuzhiyun * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15*4882a593Smuzhiyun * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16*4882a593Smuzhiyun * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17*4882a593Smuzhiyun * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18*4882a593Smuzhiyun * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19*4882a593Smuzhiyun * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20*4882a593Smuzhiyun * OTHER DEALINGS IN THE SOFTWARE.
21*4882a593Smuzhiyun */
22*4882a593Smuzhiyun #include "head.h"
23*4882a593Smuzhiyun #include "atom.h"
24*4882a593Smuzhiyun #include "core.h"
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun #include <nvif/pushc37b.h>
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun #include <nvhw/class/clc57d.h>
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun static int
headc57d_or(struct nv50_head * head,struct nv50_head_atom * asyh)31*4882a593Smuzhiyun headc57d_or(struct nv50_head *head, struct nv50_head_atom *asyh)
32*4882a593Smuzhiyun {
33*4882a593Smuzhiyun struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
34*4882a593Smuzhiyun const int i = head->base.index;
35*4882a593Smuzhiyun u8 depth;
36*4882a593Smuzhiyun int ret;
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun /*XXX: This is a dirty hack until OR depth handling is
39*4882a593Smuzhiyun * improved later for deep colour etc.
40*4882a593Smuzhiyun */
41*4882a593Smuzhiyun switch (asyh->or.depth) {
42*4882a593Smuzhiyun case 6: depth = 5; break;
43*4882a593Smuzhiyun case 5: depth = 4; break;
44*4882a593Smuzhiyun case 2: depth = 1; break;
45*4882a593Smuzhiyun case 0: depth = 4; break;
46*4882a593Smuzhiyun default:
47*4882a593Smuzhiyun depth = asyh->or.depth;
48*4882a593Smuzhiyun WARN_ON(1);
49*4882a593Smuzhiyun break;
50*4882a593Smuzhiyun }
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun if ((ret = PUSH_WAIT(push, 2)))
53*4882a593Smuzhiyun return ret;
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun PUSH_MTHD(push, NVC57D, HEAD_SET_CONTROL_OUTPUT_RESOURCE(i),
56*4882a593Smuzhiyun NVVAL(NVC57D, HEAD_SET_CONTROL_OUTPUT_RESOURCE, CRC_MODE, asyh->or.crc_raster) |
57*4882a593Smuzhiyun NVVAL(NVC57D, HEAD_SET_CONTROL_OUTPUT_RESOURCE, HSYNC_POLARITY, asyh->or.nhsync) |
58*4882a593Smuzhiyun NVVAL(NVC57D, HEAD_SET_CONTROL_OUTPUT_RESOURCE, VSYNC_POLARITY, asyh->or.nvsync) |
59*4882a593Smuzhiyun NVVAL(NVC57D, HEAD_SET_CONTROL_OUTPUT_RESOURCE, PIXEL_DEPTH, depth) |
60*4882a593Smuzhiyun NVDEF(NVC57D, HEAD_SET_CONTROL_OUTPUT_RESOURCE, COLOR_SPACE_OVERRIDE, DISABLE) |
61*4882a593Smuzhiyun NVDEF(NVC57D, HEAD_SET_CONTROL_OUTPUT_RESOURCE, EXT_PACKET_WIN, NONE));
62*4882a593Smuzhiyun return 0;
63*4882a593Smuzhiyun }
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun static int
headc57d_procamp(struct nv50_head * head,struct nv50_head_atom * asyh)66*4882a593Smuzhiyun headc57d_procamp(struct nv50_head *head, struct nv50_head_atom *asyh)
67*4882a593Smuzhiyun {
68*4882a593Smuzhiyun struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
69*4882a593Smuzhiyun const int i = head->base.index;
70*4882a593Smuzhiyun int ret;
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun if ((ret = PUSH_WAIT(push, 2)))
73*4882a593Smuzhiyun return ret;
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun //TODO:
76*4882a593Smuzhiyun PUSH_MTHD(push, NVC57D, HEAD_SET_PROCAMP(i),
77*4882a593Smuzhiyun NVDEF(NVC57D, HEAD_SET_PROCAMP, COLOR_SPACE, RGB) |
78*4882a593Smuzhiyun NVDEF(NVC57D, HEAD_SET_PROCAMP, CHROMA_LPF, DISABLE) |
79*4882a593Smuzhiyun NVDEF(NVC57D, HEAD_SET_PROCAMP, DYNAMIC_RANGE, VESA));
80*4882a593Smuzhiyun return 0;
81*4882a593Smuzhiyun }
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun static int
headc57d_olut_clr(struct nv50_head * head)84*4882a593Smuzhiyun headc57d_olut_clr(struct nv50_head *head)
85*4882a593Smuzhiyun {
86*4882a593Smuzhiyun struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
87*4882a593Smuzhiyun const int i = head->base.index;
88*4882a593Smuzhiyun int ret;
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun if ((ret = PUSH_WAIT(push, 2)))
91*4882a593Smuzhiyun return ret;
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun PUSH_MTHD(push, NVC57D, HEAD_SET_CONTEXT_DMA_OLUT(i), 0x00000000);
94*4882a593Smuzhiyun return 0;
95*4882a593Smuzhiyun }
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun static int
headc57d_olut_set(struct nv50_head * head,struct nv50_head_atom * asyh)98*4882a593Smuzhiyun headc57d_olut_set(struct nv50_head *head, struct nv50_head_atom *asyh)
99*4882a593Smuzhiyun {
100*4882a593Smuzhiyun struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
101*4882a593Smuzhiyun const int i = head->base.index;
102*4882a593Smuzhiyun int ret;
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun if ((ret = PUSH_WAIT(push, 5)))
105*4882a593Smuzhiyun return ret;
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun PUSH_MTHD(push, NVC57D, HEAD_SET_OLUT_CONTROL(i),
108*4882a593Smuzhiyun NVVAL(NVC57D, HEAD_SET_OLUT_CONTROL, INTERPOLATE, asyh->olut.output_mode) |
109*4882a593Smuzhiyun NVDEF(NVC57D, HEAD_SET_OLUT_CONTROL, MIRROR, DISABLE) |
110*4882a593Smuzhiyun NVVAL(NVC57D, HEAD_SET_OLUT_CONTROL, MODE, asyh->olut.mode) |
111*4882a593Smuzhiyun NVVAL(NVC57D, HEAD_SET_OLUT_CONTROL, SIZE, asyh->olut.size),
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun HEAD_SET_OLUT_FP_NORM_SCALE(i), 0xffffffff,
114*4882a593Smuzhiyun HEAD_SET_CONTEXT_DMA_OLUT(i), asyh->olut.handle,
115*4882a593Smuzhiyun HEAD_SET_OFFSET_OLUT(i), asyh->olut.offset >> 8);
116*4882a593Smuzhiyun return 0;
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun static void
headc57d_olut_load_8(struct drm_color_lut * in,int size,void __iomem * mem)120*4882a593Smuzhiyun headc57d_olut_load_8(struct drm_color_lut *in, int size, void __iomem *mem)
121*4882a593Smuzhiyun {
122*4882a593Smuzhiyun memset_io(mem, 0x00, 0x20); /* VSS header. */
123*4882a593Smuzhiyun mem += 0x20;
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun while (size--) {
126*4882a593Smuzhiyun u16 r = drm_color_lut_extract(in-> red + 0, 16);
127*4882a593Smuzhiyun u16 g = drm_color_lut_extract(in->green + 0, 16);
128*4882a593Smuzhiyun u16 b = drm_color_lut_extract(in-> blue + 0, 16);
129*4882a593Smuzhiyun u16 ri = 0, gi = 0, bi = 0, i;
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun if (in++, size) {
132*4882a593Smuzhiyun ri = (drm_color_lut_extract(in-> red, 16) - r) / 4;
133*4882a593Smuzhiyun gi = (drm_color_lut_extract(in->green, 16) - g) / 4;
134*4882a593Smuzhiyun bi = (drm_color_lut_extract(in-> blue, 16) - b) / 4;
135*4882a593Smuzhiyun }
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun for (i = 0; i < 4; i++, mem += 8) {
138*4882a593Smuzhiyun writew(r + ri * i, mem + 0);
139*4882a593Smuzhiyun writew(g + gi * i, mem + 2);
140*4882a593Smuzhiyun writew(b + bi * i, mem + 4);
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun /* INTERPOLATE modes require a "next" entry to interpolate with,
145*4882a593Smuzhiyun * so we replicate the last entry to deal with this for now.
146*4882a593Smuzhiyun */
147*4882a593Smuzhiyun writew(readw(mem - 8), mem + 0);
148*4882a593Smuzhiyun writew(readw(mem - 6), mem + 2);
149*4882a593Smuzhiyun writew(readw(mem - 4), mem + 4);
150*4882a593Smuzhiyun }
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun static void
headc57d_olut_load(struct drm_color_lut * in,int size,void __iomem * mem)153*4882a593Smuzhiyun headc57d_olut_load(struct drm_color_lut *in, int size, void __iomem *mem)
154*4882a593Smuzhiyun {
155*4882a593Smuzhiyun memset_io(mem, 0x00, 0x20); /* VSS header. */
156*4882a593Smuzhiyun mem += 0x20;
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun for (; size--; in++, mem += 0x08) {
159*4882a593Smuzhiyun writew(drm_color_lut_extract(in-> red, 16), mem + 0);
160*4882a593Smuzhiyun writew(drm_color_lut_extract(in->green, 16), mem + 2);
161*4882a593Smuzhiyun writew(drm_color_lut_extract(in-> blue, 16), mem + 4);
162*4882a593Smuzhiyun }
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun /* INTERPOLATE modes require a "next" entry to interpolate with,
165*4882a593Smuzhiyun * so we replicate the last entry to deal with this for now.
166*4882a593Smuzhiyun */
167*4882a593Smuzhiyun writew(readw(mem - 8), mem + 0);
168*4882a593Smuzhiyun writew(readw(mem - 6), mem + 2);
169*4882a593Smuzhiyun writew(readw(mem - 4), mem + 4);
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun bool
headc57d_olut(struct nv50_head * head,struct nv50_head_atom * asyh,int size)173*4882a593Smuzhiyun headc57d_olut(struct nv50_head *head, struct nv50_head_atom *asyh, int size)
174*4882a593Smuzhiyun {
175*4882a593Smuzhiyun if (size != 0 && size != 256 && size != 1024)
176*4882a593Smuzhiyun return false;
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun asyh->olut.mode = NVC57D_HEAD_SET_OLUT_CONTROL_MODE_DIRECT10;
179*4882a593Smuzhiyun asyh->olut.size = 4 /* VSS header. */ + 1024 + 1 /* Entries. */;
180*4882a593Smuzhiyun asyh->olut.output_mode = NVC57D_HEAD_SET_OLUT_CONTROL_INTERPOLATE_ENABLE;
181*4882a593Smuzhiyun if (size == 256)
182*4882a593Smuzhiyun asyh->olut.load = headc57d_olut_load_8;
183*4882a593Smuzhiyun else
184*4882a593Smuzhiyun asyh->olut.load = headc57d_olut_load;
185*4882a593Smuzhiyun return true;
186*4882a593Smuzhiyun }
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun static int
headc57d_mode(struct nv50_head * head,struct nv50_head_atom * asyh)189*4882a593Smuzhiyun headc57d_mode(struct nv50_head *head, struct nv50_head_atom *asyh)
190*4882a593Smuzhiyun {
191*4882a593Smuzhiyun struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
192*4882a593Smuzhiyun struct nv50_head_mode *m = &asyh->mode;
193*4882a593Smuzhiyun const int i = head->base.index;
194*4882a593Smuzhiyun int ret;
195*4882a593Smuzhiyun
196*4882a593Smuzhiyun if ((ret = PUSH_WAIT(push, 15)))
197*4882a593Smuzhiyun return ret;
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun PUSH_MTHD(push, NVC57D, HEAD_SET_RASTER_SIZE(i),
200*4882a593Smuzhiyun NVVAL(NVC57D, HEAD_SET_RASTER_SIZE, WIDTH, m->h.active) |
201*4882a593Smuzhiyun NVVAL(NVC57D, HEAD_SET_RASTER_SIZE, HEIGHT, m->v.active),
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun HEAD_SET_RASTER_SYNC_END(i),
204*4882a593Smuzhiyun NVVAL(NVC57D, HEAD_SET_RASTER_SYNC_END, X, m->h.synce) |
205*4882a593Smuzhiyun NVVAL(NVC57D, HEAD_SET_RASTER_SYNC_END, Y, m->v.synce),
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun HEAD_SET_RASTER_BLANK_END(i),
208*4882a593Smuzhiyun NVVAL(NVC57D, HEAD_SET_RASTER_BLANK_END, X, m->h.blanke) |
209*4882a593Smuzhiyun NVVAL(NVC57D, HEAD_SET_RASTER_BLANK_END, Y, m->v.blanke),
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun HEAD_SET_RASTER_BLANK_START(i),
212*4882a593Smuzhiyun NVVAL(NVC57D, HEAD_SET_RASTER_BLANK_START, X, m->h.blanks) |
213*4882a593Smuzhiyun NVVAL(NVC57D, HEAD_SET_RASTER_BLANK_START, Y, m->v.blanks));
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun //XXX:
216*4882a593Smuzhiyun PUSH_NVSQ(push, NVC57D, 0x2074 + (i * 0x400), m->v.blank2e << 16 | m->v.blank2s);
217*4882a593Smuzhiyun PUSH_NVSQ(push, NVC57D, 0x2008 + (i * 0x400), m->interlace);
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun PUSH_MTHD(push, NVC57D, HEAD_SET_PIXEL_CLOCK_FREQUENCY(i),
220*4882a593Smuzhiyun NVVAL(NVC57D, HEAD_SET_PIXEL_CLOCK_FREQUENCY, HERTZ, m->clock * 1000));
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun PUSH_MTHD(push, NVC57D, HEAD_SET_PIXEL_CLOCK_FREQUENCY_MAX(i),
223*4882a593Smuzhiyun NVVAL(NVC57D, HEAD_SET_PIXEL_CLOCK_FREQUENCY_MAX, HERTZ, m->clock * 1000));
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun /*XXX: HEAD_USAGE_BOUNDS, doesn't belong here. */
226*4882a593Smuzhiyun PUSH_MTHD(push, NVC57D, HEAD_SET_HEAD_USAGE_BOUNDS(i),
227*4882a593Smuzhiyun NVDEF(NVC57D, HEAD_SET_HEAD_USAGE_BOUNDS, CURSOR, USAGE_W256_H256) |
228*4882a593Smuzhiyun NVDEF(NVC57D, HEAD_SET_HEAD_USAGE_BOUNDS, OLUT_ALLOWED, TRUE) |
229*4882a593Smuzhiyun NVDEF(NVC57D, HEAD_SET_HEAD_USAGE_BOUNDS, OUTPUT_SCALER_TAPS, TAPS_2) |
230*4882a593Smuzhiyun NVDEF(NVC57D, HEAD_SET_HEAD_USAGE_BOUNDS, UPSCALING_ALLOWED, TRUE));
231*4882a593Smuzhiyun return 0;
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun const struct nv50_head_func
235*4882a593Smuzhiyun headc57d = {
236*4882a593Smuzhiyun .view = headc37d_view,
237*4882a593Smuzhiyun .mode = headc57d_mode,
238*4882a593Smuzhiyun .olut = headc57d_olut,
239*4882a593Smuzhiyun .olut_identity = true,
240*4882a593Smuzhiyun .olut_size = 1024,
241*4882a593Smuzhiyun .olut_set = headc57d_olut_set,
242*4882a593Smuzhiyun .olut_clr = headc57d_olut_clr,
243*4882a593Smuzhiyun .curs_layout = head917d_curs_layout,
244*4882a593Smuzhiyun .curs_format = headc37d_curs_format,
245*4882a593Smuzhiyun .curs_set = headc37d_curs_set,
246*4882a593Smuzhiyun .curs_clr = headc37d_curs_clr,
247*4882a593Smuzhiyun .dither = headc37d_dither,
248*4882a593Smuzhiyun .procamp = headc57d_procamp,
249*4882a593Smuzhiyun .or = headc57d_or,
250*4882a593Smuzhiyun /* TODO: flexible window mappings */
251*4882a593Smuzhiyun .static_wndw_map = headc37d_static_wndw_map,
252*4882a593Smuzhiyun };
253