11590700dSBen Skeggs /*
21590700dSBen Skeggs  * Copyright 2018 Red Hat Inc.
31590700dSBen Skeggs  *
41590700dSBen Skeggs  * Permission is hereby granted, free of charge, to any person obtaining a
51590700dSBen Skeggs  * copy of this software and associated documentation files (the "Software"),
61590700dSBen Skeggs  * to deal in the Software without restriction, including without limitation
71590700dSBen Skeggs  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
81590700dSBen Skeggs  * and/or sell copies of the Software, and to permit persons to whom the
91590700dSBen Skeggs  * Software is furnished to do so, subject to the following conditions:
101590700dSBen Skeggs  *
111590700dSBen Skeggs  * The above copyright notice and this permission notice shall be included in
121590700dSBen Skeggs  * all copies or substantial portions of the Software.
131590700dSBen Skeggs  *
141590700dSBen Skeggs  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
151590700dSBen Skeggs  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
161590700dSBen Skeggs  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
171590700dSBen Skeggs  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
181590700dSBen Skeggs  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
191590700dSBen Skeggs  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
201590700dSBen Skeggs  * OTHER DEALINGS IN THE SOFTWARE.
211590700dSBen Skeggs  */
221590700dSBen Skeggs #include "head.h"
231590700dSBen Skeggs #include "core.h"
241590700dSBen Skeggs 
251f772f5aSBen Skeggs #include <nvif/push507c.h>
261f772f5aSBen Skeggs 
27fb3939e2SBen Skeggs #include <nvhw/class/cl507d.h>
28fb3939e2SBen Skeggs 
29246db5fdSBen Skeggs int
head507d_procamp(struct nv50_head * head,struct nv50_head_atom * asyh)301590700dSBen Skeggs head507d_procamp(struct nv50_head *head, struct nv50_head_atom *asyh)
311590700dSBen Skeggs {
32246db5fdSBen Skeggs 	struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
33246db5fdSBen Skeggs 	const int i = head->base.index;
34246db5fdSBen Skeggs 	int ret;
35246db5fdSBen Skeggs 
36246db5fdSBen Skeggs 	if ((ret = PUSH_WAIT(push, 2)))
37246db5fdSBen Skeggs 		return ret;
38246db5fdSBen Skeggs 
3929ace860SBen Skeggs 	PUSH_MTHD(push, NV507D, HEAD_SET_PROCAMP(i),
4029ace860SBen Skeggs 		  NVDEF(NV507D, HEAD_SET_PROCAMP, COLOR_SPACE, RGB) |
4129ace860SBen Skeggs 		  NVDEF(NV507D, HEAD_SET_PROCAMP, CHROMA_LPF, AUTO) |
4229ace860SBen Skeggs 		  NVVAL(NV507D, HEAD_SET_PROCAMP, SAT_COS, asyh->procamp.sat.cos) |
4329ace860SBen Skeggs 		  NVVAL(NV507D, HEAD_SET_PROCAMP, SAT_SINE, asyh->procamp.sat.sin) |
4429ace860SBen Skeggs 		  NVDEF(NV507D, HEAD_SET_PROCAMP, TRANSITION, HARD));
45246db5fdSBen Skeggs 	return 0;
461590700dSBen Skeggs }
471590700dSBen Skeggs 
482f819f2bSBen Skeggs int
head507d_dither(struct nv50_head * head,struct nv50_head_atom * asyh)491590700dSBen Skeggs head507d_dither(struct nv50_head *head, struct nv50_head_atom *asyh)
501590700dSBen Skeggs {
512f819f2bSBen Skeggs 	struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
522f819f2bSBen Skeggs 	const int i = head->base.index;
532f819f2bSBen Skeggs 	int ret;
542f819f2bSBen Skeggs 
552f819f2bSBen Skeggs 	if ((ret = PUSH_WAIT(push, 2)))
562f819f2bSBen Skeggs 		return ret;
572f819f2bSBen Skeggs 
58f801efb1SBen Skeggs 	PUSH_MTHD(push, NV507D, HEAD_SET_DITHER_CONTROL(i),
59f801efb1SBen Skeggs 		  NVVAL(NV507D, HEAD_SET_DITHER_CONTROL, ENABLE, asyh->dither.enable) |
60f801efb1SBen Skeggs 		  NVVAL(NV507D, HEAD_SET_DITHER_CONTROL, BITS, asyh->dither.bits) |
61f801efb1SBen Skeggs 		  NVVAL(NV507D, HEAD_SET_DITHER_CONTROL, MODE, asyh->dither.mode) |
62f801efb1SBen Skeggs 		  NVVAL(NV507D, HEAD_SET_DITHER_CONTROL, PHASE, 0));
632f819f2bSBen Skeggs 	return 0;
641590700dSBen Skeggs }
651590700dSBen Skeggs 
66db2a2069SBen Skeggs int
head507d_ovly(struct nv50_head * head,struct nv50_head_atom * asyh)671590700dSBen Skeggs head507d_ovly(struct nv50_head *head, struct nv50_head_atom *asyh)
681590700dSBen Skeggs {
69db2a2069SBen Skeggs 	struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
70db2a2069SBen Skeggs 	const int i = head->base.index;
711590700dSBen Skeggs 	u32 bounds = 0;
72db2a2069SBen Skeggs 	int ret;
731590700dSBen Skeggs 
741590700dSBen Skeggs 	if (asyh->ovly.cpp) {
751590700dSBen Skeggs 		switch (asyh->ovly.cpp) {
7635cefc53SBen Skeggs 		case 4: bounds |= NVDEF(NV507D, HEAD_SET_BASE_CHANNEL_USAGE_BOUNDS, PIXEL_DEPTH, BPP_32); break;
7735cefc53SBen Skeggs 		case 2: bounds |= NVDEF(NV507D, HEAD_SET_BASE_CHANNEL_USAGE_BOUNDS, PIXEL_DEPTH, BPP_16); break;
781590700dSBen Skeggs 		default:
791590700dSBen Skeggs 			WARN_ON(1);
801590700dSBen Skeggs 			break;
811590700dSBen Skeggs 		}
8235cefc53SBen Skeggs 		bounds |= NVDEF(NV507D, HEAD_SET_BASE_CHANNEL_USAGE_BOUNDS, USABLE, TRUE);
832ce7f386SBen Skeggs 	} else {
8435cefc53SBen Skeggs 		bounds |= NVDEF(NV507D, HEAD_SET_BASE_CHANNEL_USAGE_BOUNDS, PIXEL_DEPTH, BPP_16);
851590700dSBen Skeggs 	}
861590700dSBen Skeggs 
87db2a2069SBen Skeggs 	if ((ret = PUSH_WAIT(push, 2)))
88db2a2069SBen Skeggs 		return ret;
89db2a2069SBen Skeggs 
9035cefc53SBen Skeggs 	PUSH_MTHD(push, NV507D, HEAD_SET_BASE_CHANNEL_USAGE_BOUNDS(i), bounds);
91db2a2069SBen Skeggs 	return 0;
921590700dSBen Skeggs }
931590700dSBen Skeggs 
9493f7f054SBen Skeggs int
head507d_base(struct nv50_head * head,struct nv50_head_atom * asyh)951590700dSBen Skeggs head507d_base(struct nv50_head *head, struct nv50_head_atom *asyh)
961590700dSBen Skeggs {
9793f7f054SBen Skeggs 	struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
9893f7f054SBen Skeggs 	const int i = head->base.index;
991590700dSBen Skeggs 	u32 bounds = 0;
10093f7f054SBen Skeggs 	int ret;
1011590700dSBen Skeggs 
1021590700dSBen Skeggs 	if (asyh->base.cpp) {
1031590700dSBen Skeggs 		switch (asyh->base.cpp) {
1042aa934caSBen Skeggs 		case 8: bounds |= NVDEF(NV507D, HEAD_SET_BASE_CHANNEL_USAGE_BOUNDS, PIXEL_DEPTH, BPP_64); break;
1052aa934caSBen Skeggs 		case 4: bounds |= NVDEF(NV507D, HEAD_SET_BASE_CHANNEL_USAGE_BOUNDS, PIXEL_DEPTH, BPP_32); break;
1062aa934caSBen Skeggs 		case 2: bounds |= NVDEF(NV507D, HEAD_SET_BASE_CHANNEL_USAGE_BOUNDS, PIXEL_DEPTH, BPP_16); break;
1072aa934caSBen Skeggs 		case 1: bounds |= NVDEF(NV507D, HEAD_SET_BASE_CHANNEL_USAGE_BOUNDS, PIXEL_DEPTH, BPP_8); break;
1081590700dSBen Skeggs 		default:
1091590700dSBen Skeggs 			WARN_ON(1);
1101590700dSBen Skeggs 			break;
1111590700dSBen Skeggs 		}
1122aa934caSBen Skeggs 		bounds |= NVDEF(NV507D, HEAD_SET_BASE_CHANNEL_USAGE_BOUNDS, USABLE, TRUE);
1131590700dSBen Skeggs 	}
1141590700dSBen Skeggs 
11593f7f054SBen Skeggs 	if ((ret = PUSH_WAIT(push, 2)))
11693f7f054SBen Skeggs 		return ret;
11793f7f054SBen Skeggs 
1182aa934caSBen Skeggs 	PUSH_MTHD(push, NV507D, HEAD_SET_BASE_CHANNEL_USAGE_BOUNDS(i), bounds);
11993f7f054SBen Skeggs 	return 0;
1201590700dSBen Skeggs }
1211590700dSBen Skeggs 
122bc5af56aSBen Skeggs static int
head507d_curs_clr(struct nv50_head * head)1231590700dSBen Skeggs head507d_curs_clr(struct nv50_head *head)
1241590700dSBen Skeggs {
125bc5af56aSBen Skeggs 	struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
126bc5af56aSBen Skeggs 	const int i = head->base.index;
127bc5af56aSBen Skeggs 	int ret;
128bc5af56aSBen Skeggs 
129bc5af56aSBen Skeggs 	if ((ret = PUSH_WAIT(push, 2)))
130bc5af56aSBen Skeggs 		return ret;
131bc5af56aSBen Skeggs 
132916722fcSBen Skeggs 	PUSH_MTHD(push, NV507D, HEAD_SET_CONTROL_CURSOR(i),
133916722fcSBen Skeggs 		  NVDEF(NV507D, HEAD_SET_CONTROL_CURSOR, ENABLE, DISABLE) |
134916722fcSBen Skeggs 		  NVDEF(NV507D, HEAD_SET_CONTROL_CURSOR, FORMAT, A8R8G8B8) |
135916722fcSBen Skeggs 		  NVDEF(NV507D, HEAD_SET_CONTROL_CURSOR, SIZE, W64_H64));
136bc5af56aSBen Skeggs 	return 0;
1371590700dSBen Skeggs }
1381590700dSBen Skeggs 
1399549c14bSBen Skeggs static int
head507d_curs_set(struct nv50_head * head,struct nv50_head_atom * asyh)1401590700dSBen Skeggs head507d_curs_set(struct nv50_head *head, struct nv50_head_atom *asyh)
1411590700dSBen Skeggs {
1429549c14bSBen Skeggs 	struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
1439549c14bSBen Skeggs 	const int i = head->base.index;
1449549c14bSBen Skeggs 	int ret;
1459549c14bSBen Skeggs 
1469549c14bSBen Skeggs 	if ((ret = PUSH_WAIT(push, 3)))
1479549c14bSBen Skeggs 		return ret;
1489549c14bSBen Skeggs 
149ed0b86a9SBen Skeggs 	PUSH_MTHD(push, NV507D, HEAD_SET_CONTROL_CURSOR(i),
150ed0b86a9SBen Skeggs 		  NVDEF(NV507D, HEAD_SET_CONTROL_CURSOR, ENABLE, ENABLE) |
151ed0b86a9SBen Skeggs 		  NVVAL(NV507D, HEAD_SET_CONTROL_CURSOR, FORMAT, asyh->curs.format) |
152ed0b86a9SBen Skeggs 		  NVVAL(NV507D, HEAD_SET_CONTROL_CURSOR, SIZE, asyh->curs.layout) |
153ed0b86a9SBen Skeggs 		  NVVAL(NV507D, HEAD_SET_CONTROL_CURSOR, HOT_SPOT_X, 0) |
154ed0b86a9SBen Skeggs 		  NVVAL(NV507D, HEAD_SET_CONTROL_CURSOR, HOT_SPOT_Y, 0) |
155ed0b86a9SBen Skeggs 		  NVDEF(NV507D, HEAD_SET_CONTROL_CURSOR, COMPOSITION, ALPHA_BLEND) |
156ed0b86a9SBen Skeggs 		  NVDEF(NV507D, HEAD_SET_CONTROL_CURSOR, SUB_OWNER, NONE),
157ed0b86a9SBen Skeggs 
158ed0b86a9SBen Skeggs 				HEAD_SET_OFFSET_CURSOR(i), asyh->curs.offset >> 8);
1599549c14bSBen Skeggs 	return 0;
1601590700dSBen Skeggs }
1611590700dSBen Skeggs 
16201d380abSBen Skeggs int
head507d_curs_format(struct nv50_head * head,struct nv50_wndw_atom * asyw,struct nv50_head_atom * asyh)16301d380abSBen Skeggs head507d_curs_format(struct nv50_head *head, struct nv50_wndw_atom *asyw,
16401d380abSBen Skeggs 		     struct nv50_head_atom *asyh)
16501d380abSBen Skeggs {
16601d380abSBen Skeggs 	switch (asyw->image.format) {
167ed0b86a9SBen Skeggs 	case 0xcf: asyh->curs.format = NV507D_HEAD_SET_CONTROL_CURSOR_FORMAT_A8R8G8B8; break;
16801d380abSBen Skeggs 	default:
16901d380abSBen Skeggs 		WARN_ON(1);
17001d380abSBen Skeggs 		return -EINVAL;
17101d380abSBen Skeggs 	}
17201d380abSBen Skeggs 	return 0;
17301d380abSBen Skeggs }
17401d380abSBen Skeggs 
17501d380abSBen Skeggs int
head507d_curs_layout(struct nv50_head * head,struct nv50_wndw_atom * asyw,struct nv50_head_atom * asyh)17601d380abSBen Skeggs head507d_curs_layout(struct nv50_head *head, struct nv50_wndw_atom *asyw,
17701d380abSBen Skeggs 		     struct nv50_head_atom *asyh)
17801d380abSBen Skeggs {
17901d380abSBen Skeggs 	switch (asyw->image.w) {
180ed0b86a9SBen Skeggs 	case 32: asyh->curs.layout = NV507D_HEAD_SET_CONTROL_CURSOR_SIZE_W32_H32; break;
181ed0b86a9SBen Skeggs 	case 64: asyh->curs.layout = NV507D_HEAD_SET_CONTROL_CURSOR_SIZE_W64_H64; break;
18201d380abSBen Skeggs 	default:
18301d380abSBen Skeggs 		return -EINVAL;
18401d380abSBen Skeggs 	}
18501d380abSBen Skeggs 	return 0;
18601d380abSBen Skeggs }
18701d380abSBen Skeggs 
188aabe253eSBen Skeggs int
head507d_core_clr(struct nv50_head * head)1891590700dSBen Skeggs head507d_core_clr(struct nv50_head *head)
1901590700dSBen Skeggs {
191aabe253eSBen Skeggs 	struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
192aabe253eSBen Skeggs 	const int i = head->base.index;
193aabe253eSBen Skeggs 	int ret;
194aabe253eSBen Skeggs 
195aabe253eSBen Skeggs 	if ((ret = PUSH_WAIT(push, 2)))
196aabe253eSBen Skeggs 		return ret;
197aabe253eSBen Skeggs 
198dbb23f54SBen Skeggs 	PUSH_MTHD(push, NV507D, HEAD_SET_CONTEXT_DMA_ISO(i), 0x00000000);
199aabe253eSBen Skeggs 	return 0;
2001590700dSBen Skeggs }
2011590700dSBen Skeggs 
202a38870a2SBen Skeggs static int
head507d_core_set(struct nv50_head * head,struct nv50_head_atom * asyh)2031590700dSBen Skeggs head507d_core_set(struct nv50_head *head, struct nv50_head_atom *asyh)
2041590700dSBen Skeggs {
205a38870a2SBen Skeggs 	struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
206a38870a2SBen Skeggs 	const int i = head->base.index;
207a38870a2SBen Skeggs 	int ret;
208a38870a2SBen Skeggs 
209a38870a2SBen Skeggs 	if ((ret = PUSH_WAIT(push, 9)))
210a38870a2SBen Skeggs 		return ret;
211a38870a2SBen Skeggs 
2121302634fSBen Skeggs 	PUSH_MTHD(push, NV507D, HEAD_SET_OFFSET(i, 0),
2131302634fSBen Skeggs 		  NVVAL(NV507D, HEAD_SET_OFFSET, ORIGIN, asyh->core.offset >> 8));
2141302634fSBen Skeggs 
2151302634fSBen Skeggs 	PUSH_MTHD(push, NV507D, HEAD_SET_SIZE(i),
2161302634fSBen Skeggs 		  NVVAL(NV507D, HEAD_SET_SIZE, WIDTH, asyh->core.w) |
2171302634fSBen Skeggs 		  NVVAL(NV507D, HEAD_SET_SIZE, HEIGHT, asyh->core.h),
2181302634fSBen Skeggs 
2191302634fSBen Skeggs 				HEAD_SET_STORAGE(i),
2201302634fSBen Skeggs 		  NVVAL(NV507D, HEAD_SET_STORAGE, BLOCK_HEIGHT, asyh->core.blockh) |
2211302634fSBen Skeggs 		  NVVAL(NV507D, HEAD_SET_STORAGE, PITCH, asyh->core.pitch >> 8) |
2221302634fSBen Skeggs 		  NVVAL(NV507D, HEAD_SET_STORAGE, PITCH, asyh->core.blocks) |
2231302634fSBen Skeggs 		  NVVAL(NV507D, HEAD_SET_STORAGE, MEMORY_LAYOUT, asyh->core.layout),
2241302634fSBen Skeggs 
2251302634fSBen Skeggs 				HEAD_SET_PARAMS(i),
2261302634fSBen Skeggs 		  NVVAL(NV507D, HEAD_SET_PARAMS, FORMAT, asyh->core.format) |
2271302634fSBen Skeggs 		  NVVAL(NV507D, HEAD_SET_PARAMS, KIND, asyh->core.kind) |
2281302634fSBen Skeggs 		  NVDEF(NV507D, HEAD_SET_PARAMS, PART_STRIDE, PARTSTRIDE_256),
2291302634fSBen Skeggs 
2301302634fSBen Skeggs 				HEAD_SET_CONTEXT_DMA_ISO(i),
2311302634fSBen Skeggs 		  NVVAL(NV507D, HEAD_SET_CONTEXT_DMA_ISO, HANDLE, asyh->core.handle));
2321302634fSBen Skeggs 
2331302634fSBen Skeggs 	PUSH_MTHD(push, NV507D, HEAD_SET_VIEWPORT_POINT_IN(i, 0),
2341302634fSBen Skeggs 		  NVVAL(NV507D, HEAD_SET_VIEWPORT_POINT_IN, X, asyh->core.x) |
2351302634fSBen Skeggs 		  NVVAL(NV507D, HEAD_SET_VIEWPORT_POINT_IN, Y, asyh->core.y));
23609e1b78aSBen Skeggs 
2371590700dSBen Skeggs 	/* EVO will complain with INVALID_STATE if we have an
2381590700dSBen Skeggs 	 * active cursor and (re)specify HeadSetContextDmaIso
2391590700dSBen Skeggs 	 * without also updating HeadSetOffsetCursor.
2401590700dSBen Skeggs 	 */
2411590700dSBen Skeggs 	asyh->set.curs = asyh->curs.visible;
242119608a7SBen Skeggs 	asyh->set.olut = asyh->olut.handle != 0;
243a38870a2SBen Skeggs 	return 0;
24409e1b78aSBen Skeggs }
24509e1b78aSBen Skeggs 
24609e1b78aSBen Skeggs void
head507d_core_calc(struct nv50_head * head,struct nv50_head_atom * asyh)24709e1b78aSBen Skeggs head507d_core_calc(struct nv50_head *head, struct nv50_head_atom *asyh)
24809e1b78aSBen Skeggs {
24909e1b78aSBen Skeggs 	struct nv50_disp *disp = nv50_disp(head->base.base.dev);
25009e1b78aSBen Skeggs 	if ((asyh->core.visible = (asyh->base.cpp != 0))) {
25109e1b78aSBen Skeggs 		asyh->core.x = asyh->base.x;
25209e1b78aSBen Skeggs 		asyh->core.y = asyh->base.y;
25309e1b78aSBen Skeggs 		asyh->core.w = asyh->base.w;
25409e1b78aSBen Skeggs 		asyh->core.h = asyh->base.h;
2551590700dSBen Skeggs 	} else
256119608a7SBen Skeggs 	if ((asyh->core.visible = (asyh->ovly.cpp != 0)) ||
257119608a7SBen Skeggs 	    (asyh->core.visible = asyh->curs.visible)) {
25809e1b78aSBen Skeggs 		/*XXX: We need to either find some way of having the
25909e1b78aSBen Skeggs 		 *     primary base layer appear black, while still
26009e1b78aSBen Skeggs 		 *     being able to display the other layers, or we
26109e1b78aSBen Skeggs 		 *     need to allocate a dummy black surface here.
26209e1b78aSBen Skeggs 		 */
26309e1b78aSBen Skeggs 		asyh->core.x = 0;
26409e1b78aSBen Skeggs 		asyh->core.y = 0;
26509e1b78aSBen Skeggs 		asyh->core.w = asyh->state.mode.hdisplay;
26609e1b78aSBen Skeggs 		asyh->core.h = asyh->state.mode.vdisplay;
2671590700dSBen Skeggs 	}
26809e1b78aSBen Skeggs 	asyh->core.handle = disp->core->chan.vram.handle;
26909e1b78aSBen Skeggs 	asyh->core.offset = 0;
2701302634fSBen Skeggs 	asyh->core.format = NV507D_HEAD_SET_PARAMS_FORMAT_A8R8G8B8;
2711302634fSBen Skeggs 	asyh->core.kind = NV507D_HEAD_SET_PARAMS_KIND_KIND_PITCH;
2721302634fSBen Skeggs 	asyh->core.layout = NV507D_HEAD_SET_STORAGE_MEMORY_LAYOUT_PITCH;
2731302634fSBen Skeggs 	asyh->core.blockh = NV507D_HEAD_SET_STORAGE_BLOCK_HEIGHT_ONE_GOB;
274b05d8738SBen Skeggs 	asyh->core.blocks = 0;
27509e1b78aSBen Skeggs 	asyh->core.pitch = ALIGN(asyh->core.w, 64) * 4;
2761590700dSBen Skeggs }
2771590700dSBen Skeggs 
2784fbf03a3SBen Skeggs static int
head507d_olut_clr(struct nv50_head * head)279119608a7SBen Skeggs head507d_olut_clr(struct nv50_head *head)
2801590700dSBen Skeggs {
2814fbf03a3SBen Skeggs 	struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
2824fbf03a3SBen Skeggs 	const int i = head->base.index;
2834fbf03a3SBen Skeggs 	int ret;
2844fbf03a3SBen Skeggs 
2854fbf03a3SBen Skeggs 	if ((ret = PUSH_WAIT(push, 2)))
2864fbf03a3SBen Skeggs 		return ret;
2874fbf03a3SBen Skeggs 
288a66a096dSBen Skeggs 	PUSH_MTHD(push, NV507D, HEAD_SET_BASE_LUT_LO(i),
289a66a096dSBen Skeggs 		  NVDEF(NV507D, HEAD_SET_BASE_LUT_LO, ENABLE, DISABLE));
2904fbf03a3SBen Skeggs 	return 0;
2911590700dSBen Skeggs }
2921590700dSBen Skeggs 
293a5df7630SBen Skeggs static int
head507d_olut_set(struct nv50_head * head,struct nv50_head_atom * asyh)294119608a7SBen Skeggs head507d_olut_set(struct nv50_head *head, struct nv50_head_atom *asyh)
2951590700dSBen Skeggs {
296a5df7630SBen Skeggs 	struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
297a5df7630SBen Skeggs 	const int i = head->base.index;
298a5df7630SBen Skeggs 	int ret;
299a5df7630SBen Skeggs 
300a5df7630SBen Skeggs 	if ((ret = PUSH_WAIT(push, 3)))
301a5df7630SBen Skeggs 		return ret;
302a5df7630SBen Skeggs 
303a41ef363SBen Skeggs 	PUSH_MTHD(push, NV507D, HEAD_SET_BASE_LUT_LO(i),
304a41ef363SBen Skeggs 		  NVDEF(NV507D, HEAD_SET_BASE_LUT_LO, ENABLE, ENABLE) |
305a41ef363SBen Skeggs 		  NVVAL(NV507D, HEAD_SET_BASE_LUT_LO, MODE, asyh->olut.mode) |
306a41ef363SBen Skeggs 		  NVVAL(NV507D, HEAD_SET_BASE_LUT_LO, ORIGIN, 0),
307a41ef363SBen Skeggs 
308a41ef363SBen Skeggs 				HEAD_SET_BASE_LUT_HI(i),
309a41ef363SBen Skeggs 		  NVVAL(NV507D, HEAD_SET_BASE_LUT_HI, ORIGIN, asyh->olut.offset >> 8));
310a5df7630SBen Skeggs 	return 0;
3111590700dSBen Skeggs }
3121590700dSBen Skeggs 
313cb55cd0cSBen Skeggs static void
head507d_olut_load(struct drm_color_lut * in,int size,void __iomem * mem)314cb55cd0cSBen Skeggs head507d_olut_load(struct drm_color_lut *in, int size, void __iomem *mem)
315cb55cd0cSBen Skeggs {
316cb55cd0cSBen Skeggs 	for (; size--; in++, mem += 8) {
317cb55cd0cSBen Skeggs 		writew(drm_color_lut_extract(in->  red, 11) << 3, mem + 0);
318cb55cd0cSBen Skeggs 		writew(drm_color_lut_extract(in->green, 11) << 3, mem + 2);
319cb55cd0cSBen Skeggs 		writew(drm_color_lut_extract(in-> blue, 11) << 3, mem + 4);
320cb55cd0cSBen Skeggs 	}
321cb55cd0cSBen Skeggs 
322cb55cd0cSBen Skeggs 	/* INTERPOLATE modes require a "next" entry to interpolate with,
323cb55cd0cSBen Skeggs 	 * so we replicate the last entry to deal with this for now.
324cb55cd0cSBen Skeggs 	 */
325cb55cd0cSBen Skeggs 	writew(readw(mem - 8), mem + 0);
326cb55cd0cSBen Skeggs 	writew(readw(mem - 6), mem + 2);
327cb55cd0cSBen Skeggs 	writew(readw(mem - 4), mem + 4);
328cb55cd0cSBen Skeggs }
329cb55cd0cSBen Skeggs 
33013199270SIlia Mirkin bool
head507d_olut(struct nv50_head * head,struct nv50_head_atom * asyh,int size)33113199270SIlia Mirkin head507d_olut(struct nv50_head *head, struct nv50_head_atom *asyh, int size)
332119608a7SBen Skeggs {
33313199270SIlia Mirkin 	if (size != 256)
33413199270SIlia Mirkin 		return false;
33513199270SIlia Mirkin 
336119608a7SBen Skeggs 	if (asyh->base.cpp == 1)
337a41ef363SBen Skeggs 		asyh->olut.mode = NV507D_HEAD_SET_BASE_LUT_LO_MODE_LORES;
338119608a7SBen Skeggs 	else
339a41ef363SBen Skeggs 		asyh->olut.mode = NV507D_HEAD_SET_BASE_LUT_LO_MODE_HIRES;
340cb55cd0cSBen Skeggs 
341cb55cd0cSBen Skeggs 	asyh->olut.load = head507d_olut_load;
34213199270SIlia Mirkin 	return true;
343119608a7SBen Skeggs }
344119608a7SBen Skeggs 
345caa966a7SBen Skeggs int
head507d_mode(struct nv50_head * head,struct nv50_head_atom * asyh)3461590700dSBen Skeggs head507d_mode(struct nv50_head *head, struct nv50_head_atom *asyh)
3471590700dSBen Skeggs {
348caa966a7SBen Skeggs 	struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
3491590700dSBen Skeggs 	struct nv50_head_mode *m = &asyh->mode;
350caa966a7SBen Skeggs 	const int i = head->base.index;
351caa966a7SBen Skeggs 	int ret;
352caa966a7SBen Skeggs 
353caa966a7SBen Skeggs 	if ((ret = PUSH_WAIT(push, 13)))
354caa966a7SBen Skeggs 		return ret;
355caa966a7SBen Skeggs 
356c4c75188SBen Skeggs 	PUSH_MTHD(push, NV507D, HEAD_SET_PIXEL_CLOCK(i),
357c4c75188SBen Skeggs 		  NVVAL(NV507D, HEAD_SET_PIXEL_CLOCK, FREQUENCY, m->clock) |
358c4c75188SBen Skeggs 		  NVDEF(NV507D, HEAD_SET_PIXEL_CLOCK, MODE, CLK_CUSTOM) |
359c4c75188SBen Skeggs 		  NVDEF(NV507D, HEAD_SET_PIXEL_CLOCK, ADJ1000DIV1001, FALSE) |
360c4c75188SBen Skeggs 		  NVDEF(NV507D, HEAD_SET_PIXEL_CLOCK, NOT_DRIVER, FALSE),
361c4c75188SBen Skeggs 
362c4c75188SBen Skeggs 				HEAD_SET_CONTROL(i),
363c4c75188SBen Skeggs 		  NVVAL(NV507D, HEAD_SET_CONTROL, STRUCTURE, m->interlace));
364c4c75188SBen Skeggs 
365c4c75188SBen Skeggs 	PUSH_MTHD(push, NV507D, HEAD_SET_OVERSCAN_COLOR(i),
366c4c75188SBen Skeggs 		  NVVAL(NV507D, HEAD_SET_OVERSCAN_COLOR, RED, 0) |
367c4c75188SBen Skeggs 		  NVVAL(NV507D, HEAD_SET_OVERSCAN_COLOR, GRN, 0) |
368c4c75188SBen Skeggs 		  NVVAL(NV507D, HEAD_SET_OVERSCAN_COLOR, BLU, 0),
369c4c75188SBen Skeggs 
370c4c75188SBen Skeggs 				HEAD_SET_RASTER_SIZE(i),
371c4c75188SBen Skeggs 		  NVVAL(NV507D, HEAD_SET_RASTER_SIZE, WIDTH, m->h.active) |
372c4c75188SBen Skeggs 		  NVVAL(NV507D, HEAD_SET_RASTER_SIZE, HEIGHT, m->v.active),
373c4c75188SBen Skeggs 
374c4c75188SBen Skeggs 				HEAD_SET_RASTER_SYNC_END(i),
375c4c75188SBen Skeggs 		  NVVAL(NV507D, HEAD_SET_RASTER_SYNC_END, X, m->h.synce) |
376c4c75188SBen Skeggs 		  NVVAL(NV507D, HEAD_SET_RASTER_SYNC_END, Y, m->v.synce),
377c4c75188SBen Skeggs 
378c4c75188SBen Skeggs 				HEAD_SET_RASTER_BLANK_END(i),
379c4c75188SBen Skeggs 		  NVVAL(NV507D, HEAD_SET_RASTER_BLANK_END, X, m->h.blanke) |
380c4c75188SBen Skeggs 		  NVVAL(NV507D, HEAD_SET_RASTER_BLANK_END, Y, m->v.blanke),
381c4c75188SBen Skeggs 
382c4c75188SBen Skeggs 				HEAD_SET_RASTER_BLANK_START(i),
383c4c75188SBen Skeggs 		  NVVAL(NV507D, HEAD_SET_RASTER_BLANK_START, X, m->h.blanks) |
384c4c75188SBen Skeggs 		  NVVAL(NV507D, HEAD_SET_RASTER_BLANK_START, Y, m->v.blanks),
385c4c75188SBen Skeggs 
386c4c75188SBen Skeggs 				HEAD_SET_RASTER_VERT_BLANK2(i),
387c4c75188SBen Skeggs 		  NVVAL(NV507D, HEAD_SET_RASTER_VERT_BLANK2, YSTART, m->v.blank2s) |
388c4c75188SBen Skeggs 		  NVVAL(NV507D, HEAD_SET_RASTER_VERT_BLANK2, YEND, m->v.blank2e),
389c4c75188SBen Skeggs 
390c4c75188SBen Skeggs 				HEAD_SET_RASTER_VERT_BLANK_DMI(i),
391c4c75188SBen Skeggs 		  NVVAL(NV507D, HEAD_SET_RASTER_VERT_BLANK_DMI, DURATION, m->v.blankus));
392c4c75188SBen Skeggs 
393c4c75188SBen Skeggs 	PUSH_MTHD(push, NV507D, HEAD_SET_DEFAULT_BASE_COLOR(i),
394c4c75188SBen Skeggs 		  NVVAL(NV507D, HEAD_SET_DEFAULT_BASE_COLOR, RED, 0) |
395c4c75188SBen Skeggs 		  NVVAL(NV507D, HEAD_SET_DEFAULT_BASE_COLOR, GREEN, 0) |
396c4c75188SBen Skeggs 		  NVVAL(NV507D, HEAD_SET_DEFAULT_BASE_COLOR, BLUE, 0));
397caa966a7SBen Skeggs 	return 0;
3981590700dSBen Skeggs }
3991590700dSBen Skeggs 
4001f772f5aSBen Skeggs int
head507d_view(struct nv50_head * head,struct nv50_head_atom * asyh)4011590700dSBen Skeggs head507d_view(struct nv50_head *head, struct nv50_head_atom *asyh)
4021590700dSBen Skeggs {
4031f772f5aSBen Skeggs 	struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
4041f772f5aSBen Skeggs 	const int i = head->base.index;
4051f772f5aSBen Skeggs 	int ret;
4061f772f5aSBen Skeggs 
4071f772f5aSBen Skeggs 	if ((ret = PUSH_WAIT(push, 7)))
4081f772f5aSBen Skeggs 		return ret;
4091f772f5aSBen Skeggs 
410fb3939e2SBen Skeggs 	PUSH_MTHD(push, NV507D, HEAD_SET_CONTROL_OUTPUT_SCALER(i),
411fb3939e2SBen Skeggs 		  NVDEF(NV507D, HEAD_SET_CONTROL_OUTPUT_SCALER, VERTICAL_TAPS, TAPS_1) |
412fb3939e2SBen Skeggs 		  NVDEF(NV507D, HEAD_SET_CONTROL_OUTPUT_SCALER, HORIZONTAL_TAPS, TAPS_1) |
413fb3939e2SBen Skeggs 		  NVVAL(NV507D, HEAD_SET_CONTROL_OUTPUT_SCALER, HRESPONSE_BIAS, 0) |
414fb3939e2SBen Skeggs 		  NVVAL(NV507D, HEAD_SET_CONTROL_OUTPUT_SCALER, VRESPONSE_BIAS, 0));
415fb3939e2SBen Skeggs 
416fb3939e2SBen Skeggs 	PUSH_MTHD(push, NV507D, HEAD_SET_VIEWPORT_SIZE_IN(i),
417fb3939e2SBen Skeggs 		  NVVAL(NV507D, HEAD_SET_VIEWPORT_SIZE_IN, WIDTH, asyh->view.iW) |
418fb3939e2SBen Skeggs 		  NVVAL(NV507D, HEAD_SET_VIEWPORT_SIZE_IN, HEIGHT, asyh->view.iH));
419fb3939e2SBen Skeggs 
420fb3939e2SBen Skeggs 	PUSH_MTHD(push, NV507D, HEAD_SET_VIEWPORT_SIZE_OUT(i),
421fb3939e2SBen Skeggs 		  NVVAL(NV507D, HEAD_SET_VIEWPORT_SIZE_OUT, WIDTH, asyh->view.oW) |
422fb3939e2SBen Skeggs 		  NVVAL(NV507D, HEAD_SET_VIEWPORT_SIZE_OUT, HEIGHT, asyh->view.oH),
423fb3939e2SBen Skeggs 
424fb3939e2SBen Skeggs 				HEAD_SET_VIEWPORT_SIZE_OUT_MIN(i),
425fb3939e2SBen Skeggs 		  NVVAL(NV507D, HEAD_SET_VIEWPORT_SIZE_OUT_MIN, WIDTH, asyh->view.oW) |
426fb3939e2SBen Skeggs 		  NVVAL(NV507D, HEAD_SET_VIEWPORT_SIZE_OUT_MIN, HEIGHT, asyh->view.oH));
4271f772f5aSBen Skeggs 	return 0;
4281590700dSBen Skeggs }
4291590700dSBen Skeggs 
4301590700dSBen Skeggs const struct nv50_head_func
4311590700dSBen Skeggs head507d = {
4321590700dSBen Skeggs 	.view = head507d_view,
4331590700dSBen Skeggs 	.mode = head507d_mode,
434119608a7SBen Skeggs 	.olut = head507d_olut,
43513199270SIlia Mirkin 	.olut_size = 256,
436119608a7SBen Skeggs 	.olut_set = head507d_olut_set,
437119608a7SBen Skeggs 	.olut_clr = head507d_olut_clr,
43809e1b78aSBen Skeggs 	.core_calc = head507d_core_calc,
4391590700dSBen Skeggs 	.core_set = head507d_core_set,
4401590700dSBen Skeggs 	.core_clr = head507d_core_clr,
44101d380abSBen Skeggs 	.curs_layout = head507d_curs_layout,
44201d380abSBen Skeggs 	.curs_format = head507d_curs_format,
4431590700dSBen Skeggs 	.curs_set = head507d_curs_set,
4441590700dSBen Skeggs 	.curs_clr = head507d_curs_clr,
4451590700dSBen Skeggs 	.base = head507d_base,
4461590700dSBen Skeggs 	.ovly = head507d_ovly,
4471590700dSBen Skeggs 	.dither = head507d_dither,
4481590700dSBen Skeggs 	.procamp = head507d_procamp,
4491590700dSBen Skeggs };
450