18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright 2018 Red Hat Inc.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
58c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
68c2ecf20Sopenharmony_ci * to deal in the Software without restriction, including without limitation
78c2ecf20Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
88c2ecf20Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
98c2ecf20Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice shall be included in
128c2ecf20Sopenharmony_ci * all copies or substantial portions of the Software.
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
158c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
168c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
178c2ecf20Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
188c2ecf20Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
198c2ecf20Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
208c2ecf20Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE.
218c2ecf20Sopenharmony_ci */
228c2ecf20Sopenharmony_ci#include "head.h"
238c2ecf20Sopenharmony_ci#include "core.h"
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#include <nvif/push507c.h>
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#include <nvhw/class/cl507d.h>
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ciint
308c2ecf20Sopenharmony_cihead507d_procamp(struct nv50_head *head, struct nv50_head_atom *asyh)
318c2ecf20Sopenharmony_ci{
328c2ecf20Sopenharmony_ci	struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
338c2ecf20Sopenharmony_ci	const int i = head->base.index;
348c2ecf20Sopenharmony_ci	int ret;
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	if ((ret = PUSH_WAIT(push, 2)))
378c2ecf20Sopenharmony_ci		return ret;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	PUSH_MTHD(push, NV507D, HEAD_SET_PROCAMP(i),
408c2ecf20Sopenharmony_ci		  NVDEF(NV507D, HEAD_SET_PROCAMP, COLOR_SPACE, RGB) |
418c2ecf20Sopenharmony_ci		  NVDEF(NV507D, HEAD_SET_PROCAMP, CHROMA_LPF, AUTO) |
428c2ecf20Sopenharmony_ci		  NVVAL(NV507D, HEAD_SET_PROCAMP, SAT_COS, asyh->procamp.sat.cos) |
438c2ecf20Sopenharmony_ci		  NVVAL(NV507D, HEAD_SET_PROCAMP, SAT_SINE, asyh->procamp.sat.sin) |
448c2ecf20Sopenharmony_ci		  NVDEF(NV507D, HEAD_SET_PROCAMP, TRANSITION, HARD));
458c2ecf20Sopenharmony_ci	return 0;
468c2ecf20Sopenharmony_ci}
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ciint
498c2ecf20Sopenharmony_cihead507d_dither(struct nv50_head *head, struct nv50_head_atom *asyh)
508c2ecf20Sopenharmony_ci{
518c2ecf20Sopenharmony_ci	struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
528c2ecf20Sopenharmony_ci	const int i = head->base.index;
538c2ecf20Sopenharmony_ci	int ret;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	if ((ret = PUSH_WAIT(push, 2)))
568c2ecf20Sopenharmony_ci		return ret;
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	PUSH_MTHD(push, NV507D, HEAD_SET_DITHER_CONTROL(i),
598c2ecf20Sopenharmony_ci		  NVVAL(NV507D, HEAD_SET_DITHER_CONTROL, ENABLE, asyh->dither.enable) |
608c2ecf20Sopenharmony_ci		  NVVAL(NV507D, HEAD_SET_DITHER_CONTROL, BITS, asyh->dither.bits) |
618c2ecf20Sopenharmony_ci		  NVVAL(NV507D, HEAD_SET_DITHER_CONTROL, MODE, asyh->dither.mode) |
628c2ecf20Sopenharmony_ci		  NVVAL(NV507D, HEAD_SET_DITHER_CONTROL, PHASE, 0));
638c2ecf20Sopenharmony_ci	return 0;
648c2ecf20Sopenharmony_ci}
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ciint
678c2ecf20Sopenharmony_cihead507d_ovly(struct nv50_head *head, struct nv50_head_atom *asyh)
688c2ecf20Sopenharmony_ci{
698c2ecf20Sopenharmony_ci	struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
708c2ecf20Sopenharmony_ci	const int i = head->base.index;
718c2ecf20Sopenharmony_ci	u32 bounds = 0;
728c2ecf20Sopenharmony_ci	int ret;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	if (asyh->ovly.cpp) {
758c2ecf20Sopenharmony_ci		switch (asyh->ovly.cpp) {
768c2ecf20Sopenharmony_ci		case 4: bounds |= NVDEF(NV507D, HEAD_SET_BASE_CHANNEL_USAGE_BOUNDS, PIXEL_DEPTH, BPP_32); break;
778c2ecf20Sopenharmony_ci		case 2: bounds |= NVDEF(NV507D, HEAD_SET_BASE_CHANNEL_USAGE_BOUNDS, PIXEL_DEPTH, BPP_16); break;
788c2ecf20Sopenharmony_ci		default:
798c2ecf20Sopenharmony_ci			WARN_ON(1);
808c2ecf20Sopenharmony_ci			break;
818c2ecf20Sopenharmony_ci		}
828c2ecf20Sopenharmony_ci		bounds |= NVDEF(NV507D, HEAD_SET_BASE_CHANNEL_USAGE_BOUNDS, USABLE, TRUE);
838c2ecf20Sopenharmony_ci	} else {
848c2ecf20Sopenharmony_ci		bounds |= NVDEF(NV507D, HEAD_SET_BASE_CHANNEL_USAGE_BOUNDS, PIXEL_DEPTH, BPP_16);
858c2ecf20Sopenharmony_ci	}
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	if ((ret = PUSH_WAIT(push, 2)))
888c2ecf20Sopenharmony_ci		return ret;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	PUSH_MTHD(push, NV507D, HEAD_SET_BASE_CHANNEL_USAGE_BOUNDS(i), bounds);
918c2ecf20Sopenharmony_ci	return 0;
928c2ecf20Sopenharmony_ci}
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ciint
958c2ecf20Sopenharmony_cihead507d_base(struct nv50_head *head, struct nv50_head_atom *asyh)
968c2ecf20Sopenharmony_ci{
978c2ecf20Sopenharmony_ci	struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
988c2ecf20Sopenharmony_ci	const int i = head->base.index;
998c2ecf20Sopenharmony_ci	u32 bounds = 0;
1008c2ecf20Sopenharmony_ci	int ret;
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	if (asyh->base.cpp) {
1038c2ecf20Sopenharmony_ci		switch (asyh->base.cpp) {
1048c2ecf20Sopenharmony_ci		case 8: bounds |= NVDEF(NV507D, HEAD_SET_BASE_CHANNEL_USAGE_BOUNDS, PIXEL_DEPTH, BPP_64); break;
1058c2ecf20Sopenharmony_ci		case 4: bounds |= NVDEF(NV507D, HEAD_SET_BASE_CHANNEL_USAGE_BOUNDS, PIXEL_DEPTH, BPP_32); break;
1068c2ecf20Sopenharmony_ci		case 2: bounds |= NVDEF(NV507D, HEAD_SET_BASE_CHANNEL_USAGE_BOUNDS, PIXEL_DEPTH, BPP_16); break;
1078c2ecf20Sopenharmony_ci		case 1: bounds |= NVDEF(NV507D, HEAD_SET_BASE_CHANNEL_USAGE_BOUNDS, PIXEL_DEPTH, BPP_8); break;
1088c2ecf20Sopenharmony_ci		default:
1098c2ecf20Sopenharmony_ci			WARN_ON(1);
1108c2ecf20Sopenharmony_ci			break;
1118c2ecf20Sopenharmony_ci		}
1128c2ecf20Sopenharmony_ci		bounds |= NVDEF(NV507D, HEAD_SET_BASE_CHANNEL_USAGE_BOUNDS, USABLE, TRUE);
1138c2ecf20Sopenharmony_ci	}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	if ((ret = PUSH_WAIT(push, 2)))
1168c2ecf20Sopenharmony_ci		return ret;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	PUSH_MTHD(push, NV507D, HEAD_SET_BASE_CHANNEL_USAGE_BOUNDS(i), bounds);
1198c2ecf20Sopenharmony_ci	return 0;
1208c2ecf20Sopenharmony_ci}
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_cistatic int
1238c2ecf20Sopenharmony_cihead507d_curs_clr(struct nv50_head *head)
1248c2ecf20Sopenharmony_ci{
1258c2ecf20Sopenharmony_ci	struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
1268c2ecf20Sopenharmony_ci	const int i = head->base.index;
1278c2ecf20Sopenharmony_ci	int ret;
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	if ((ret = PUSH_WAIT(push, 2)))
1308c2ecf20Sopenharmony_ci		return ret;
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	PUSH_MTHD(push, NV507D, HEAD_SET_CONTROL_CURSOR(i),
1338c2ecf20Sopenharmony_ci		  NVDEF(NV507D, HEAD_SET_CONTROL_CURSOR, ENABLE, DISABLE) |
1348c2ecf20Sopenharmony_ci		  NVDEF(NV507D, HEAD_SET_CONTROL_CURSOR, FORMAT, A8R8G8B8) |
1358c2ecf20Sopenharmony_ci		  NVDEF(NV507D, HEAD_SET_CONTROL_CURSOR, SIZE, W64_H64));
1368c2ecf20Sopenharmony_ci	return 0;
1378c2ecf20Sopenharmony_ci}
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_cistatic int
1408c2ecf20Sopenharmony_cihead507d_curs_set(struct nv50_head *head, struct nv50_head_atom *asyh)
1418c2ecf20Sopenharmony_ci{
1428c2ecf20Sopenharmony_ci	struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
1438c2ecf20Sopenharmony_ci	const int i = head->base.index;
1448c2ecf20Sopenharmony_ci	int ret;
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	if ((ret = PUSH_WAIT(push, 3)))
1478c2ecf20Sopenharmony_ci		return ret;
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	PUSH_MTHD(push, NV507D, HEAD_SET_CONTROL_CURSOR(i),
1508c2ecf20Sopenharmony_ci		  NVDEF(NV507D, HEAD_SET_CONTROL_CURSOR, ENABLE, ENABLE) |
1518c2ecf20Sopenharmony_ci		  NVVAL(NV507D, HEAD_SET_CONTROL_CURSOR, FORMAT, asyh->curs.format) |
1528c2ecf20Sopenharmony_ci		  NVVAL(NV507D, HEAD_SET_CONTROL_CURSOR, SIZE, asyh->curs.layout) |
1538c2ecf20Sopenharmony_ci		  NVVAL(NV507D, HEAD_SET_CONTROL_CURSOR, HOT_SPOT_X, 0) |
1548c2ecf20Sopenharmony_ci		  NVVAL(NV507D, HEAD_SET_CONTROL_CURSOR, HOT_SPOT_Y, 0) |
1558c2ecf20Sopenharmony_ci		  NVDEF(NV507D, HEAD_SET_CONTROL_CURSOR, COMPOSITION, ALPHA_BLEND) |
1568c2ecf20Sopenharmony_ci		  NVDEF(NV507D, HEAD_SET_CONTROL_CURSOR, SUB_OWNER, NONE),
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci				HEAD_SET_OFFSET_CURSOR(i), asyh->curs.offset >> 8);
1598c2ecf20Sopenharmony_ci	return 0;
1608c2ecf20Sopenharmony_ci}
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ciint
1638c2ecf20Sopenharmony_cihead507d_curs_format(struct nv50_head *head, struct nv50_wndw_atom *asyw,
1648c2ecf20Sopenharmony_ci		     struct nv50_head_atom *asyh)
1658c2ecf20Sopenharmony_ci{
1668c2ecf20Sopenharmony_ci	switch (asyw->image.format) {
1678c2ecf20Sopenharmony_ci	case 0xcf: asyh->curs.format = NV507D_HEAD_SET_CONTROL_CURSOR_FORMAT_A8R8G8B8; break;
1688c2ecf20Sopenharmony_ci	default:
1698c2ecf20Sopenharmony_ci		WARN_ON(1);
1708c2ecf20Sopenharmony_ci		return -EINVAL;
1718c2ecf20Sopenharmony_ci	}
1728c2ecf20Sopenharmony_ci	return 0;
1738c2ecf20Sopenharmony_ci}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ciint
1768c2ecf20Sopenharmony_cihead507d_curs_layout(struct nv50_head *head, struct nv50_wndw_atom *asyw,
1778c2ecf20Sopenharmony_ci		     struct nv50_head_atom *asyh)
1788c2ecf20Sopenharmony_ci{
1798c2ecf20Sopenharmony_ci	switch (asyw->image.w) {
1808c2ecf20Sopenharmony_ci	case 32: asyh->curs.layout = NV507D_HEAD_SET_CONTROL_CURSOR_SIZE_W32_H32; break;
1818c2ecf20Sopenharmony_ci	case 64: asyh->curs.layout = NV507D_HEAD_SET_CONTROL_CURSOR_SIZE_W64_H64; break;
1828c2ecf20Sopenharmony_ci	default:
1838c2ecf20Sopenharmony_ci		return -EINVAL;
1848c2ecf20Sopenharmony_ci	}
1858c2ecf20Sopenharmony_ci	return 0;
1868c2ecf20Sopenharmony_ci}
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ciint
1898c2ecf20Sopenharmony_cihead507d_core_clr(struct nv50_head *head)
1908c2ecf20Sopenharmony_ci{
1918c2ecf20Sopenharmony_ci	struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
1928c2ecf20Sopenharmony_ci	const int i = head->base.index;
1938c2ecf20Sopenharmony_ci	int ret;
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	if ((ret = PUSH_WAIT(push, 2)))
1968c2ecf20Sopenharmony_ci		return ret;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	PUSH_MTHD(push, NV507D, HEAD_SET_CONTEXT_DMA_ISO(i), 0x00000000);
1998c2ecf20Sopenharmony_ci	return 0;
2008c2ecf20Sopenharmony_ci}
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_cistatic int
2038c2ecf20Sopenharmony_cihead507d_core_set(struct nv50_head *head, struct nv50_head_atom *asyh)
2048c2ecf20Sopenharmony_ci{
2058c2ecf20Sopenharmony_ci	struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
2068c2ecf20Sopenharmony_ci	const int i = head->base.index;
2078c2ecf20Sopenharmony_ci	int ret;
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	if ((ret = PUSH_WAIT(push, 9)))
2108c2ecf20Sopenharmony_ci		return ret;
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	PUSH_MTHD(push, NV507D, HEAD_SET_OFFSET(i, 0),
2138c2ecf20Sopenharmony_ci		  NVVAL(NV507D, HEAD_SET_OFFSET, ORIGIN, asyh->core.offset >> 8));
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	PUSH_MTHD(push, NV507D, HEAD_SET_SIZE(i),
2168c2ecf20Sopenharmony_ci		  NVVAL(NV507D, HEAD_SET_SIZE, WIDTH, asyh->core.w) |
2178c2ecf20Sopenharmony_ci		  NVVAL(NV507D, HEAD_SET_SIZE, HEIGHT, asyh->core.h),
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci				HEAD_SET_STORAGE(i),
2208c2ecf20Sopenharmony_ci		  NVVAL(NV507D, HEAD_SET_STORAGE, BLOCK_HEIGHT, asyh->core.blockh) |
2218c2ecf20Sopenharmony_ci		  NVVAL(NV507D, HEAD_SET_STORAGE, PITCH, asyh->core.pitch >> 8) |
2228c2ecf20Sopenharmony_ci		  NVVAL(NV507D, HEAD_SET_STORAGE, PITCH, asyh->core.blocks) |
2238c2ecf20Sopenharmony_ci		  NVVAL(NV507D, HEAD_SET_STORAGE, MEMORY_LAYOUT, asyh->core.layout),
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci				HEAD_SET_PARAMS(i),
2268c2ecf20Sopenharmony_ci		  NVVAL(NV507D, HEAD_SET_PARAMS, FORMAT, asyh->core.format) |
2278c2ecf20Sopenharmony_ci		  NVVAL(NV507D, HEAD_SET_PARAMS, KIND, asyh->core.kind) |
2288c2ecf20Sopenharmony_ci		  NVDEF(NV507D, HEAD_SET_PARAMS, PART_STRIDE, PARTSTRIDE_256),
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci				HEAD_SET_CONTEXT_DMA_ISO(i),
2318c2ecf20Sopenharmony_ci		  NVVAL(NV507D, HEAD_SET_CONTEXT_DMA_ISO, HANDLE, asyh->core.handle));
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	PUSH_MTHD(push, NV507D, HEAD_SET_VIEWPORT_POINT_IN(i, 0),
2348c2ecf20Sopenharmony_ci		  NVVAL(NV507D, HEAD_SET_VIEWPORT_POINT_IN, X, asyh->core.x) |
2358c2ecf20Sopenharmony_ci		  NVVAL(NV507D, HEAD_SET_VIEWPORT_POINT_IN, Y, asyh->core.y));
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	/* EVO will complain with INVALID_STATE if we have an
2388c2ecf20Sopenharmony_ci	 * active cursor and (re)specify HeadSetContextDmaIso
2398c2ecf20Sopenharmony_ci	 * without also updating HeadSetOffsetCursor.
2408c2ecf20Sopenharmony_ci	 */
2418c2ecf20Sopenharmony_ci	asyh->set.curs = asyh->curs.visible;
2428c2ecf20Sopenharmony_ci	asyh->set.olut = asyh->olut.handle != 0;
2438c2ecf20Sopenharmony_ci	return 0;
2448c2ecf20Sopenharmony_ci}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_civoid
2478c2ecf20Sopenharmony_cihead507d_core_calc(struct nv50_head *head, struct nv50_head_atom *asyh)
2488c2ecf20Sopenharmony_ci{
2498c2ecf20Sopenharmony_ci	struct nv50_disp *disp = nv50_disp(head->base.base.dev);
2508c2ecf20Sopenharmony_ci	if ((asyh->core.visible = (asyh->base.cpp != 0))) {
2518c2ecf20Sopenharmony_ci		asyh->core.x = asyh->base.x;
2528c2ecf20Sopenharmony_ci		asyh->core.y = asyh->base.y;
2538c2ecf20Sopenharmony_ci		asyh->core.w = asyh->base.w;
2548c2ecf20Sopenharmony_ci		asyh->core.h = asyh->base.h;
2558c2ecf20Sopenharmony_ci	} else
2568c2ecf20Sopenharmony_ci	if ((asyh->core.visible = (asyh->ovly.cpp != 0)) ||
2578c2ecf20Sopenharmony_ci	    (asyh->core.visible = asyh->curs.visible)) {
2588c2ecf20Sopenharmony_ci		/*XXX: We need to either find some way of having the
2598c2ecf20Sopenharmony_ci		 *     primary base layer appear black, while still
2608c2ecf20Sopenharmony_ci		 *     being able to display the other layers, or we
2618c2ecf20Sopenharmony_ci		 *     need to allocate a dummy black surface here.
2628c2ecf20Sopenharmony_ci		 */
2638c2ecf20Sopenharmony_ci		asyh->core.x = 0;
2648c2ecf20Sopenharmony_ci		asyh->core.y = 0;
2658c2ecf20Sopenharmony_ci		asyh->core.w = asyh->state.mode.hdisplay;
2668c2ecf20Sopenharmony_ci		asyh->core.h = asyh->state.mode.vdisplay;
2678c2ecf20Sopenharmony_ci	}
2688c2ecf20Sopenharmony_ci	asyh->core.handle = disp->core->chan.vram.handle;
2698c2ecf20Sopenharmony_ci	asyh->core.offset = 0;
2708c2ecf20Sopenharmony_ci	asyh->core.format = NV507D_HEAD_SET_PARAMS_FORMAT_A8R8G8B8;
2718c2ecf20Sopenharmony_ci	asyh->core.kind = NV507D_HEAD_SET_PARAMS_KIND_KIND_PITCH;
2728c2ecf20Sopenharmony_ci	asyh->core.layout = NV507D_HEAD_SET_STORAGE_MEMORY_LAYOUT_PITCH;
2738c2ecf20Sopenharmony_ci	asyh->core.blockh = NV507D_HEAD_SET_STORAGE_BLOCK_HEIGHT_ONE_GOB;
2748c2ecf20Sopenharmony_ci	asyh->core.blocks = 0;
2758c2ecf20Sopenharmony_ci	asyh->core.pitch = ALIGN(asyh->core.w, 64) * 4;
2768c2ecf20Sopenharmony_ci}
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_cistatic int
2798c2ecf20Sopenharmony_cihead507d_olut_clr(struct nv50_head *head)
2808c2ecf20Sopenharmony_ci{
2818c2ecf20Sopenharmony_ci	struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
2828c2ecf20Sopenharmony_ci	const int i = head->base.index;
2838c2ecf20Sopenharmony_ci	int ret;
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	if ((ret = PUSH_WAIT(push, 2)))
2868c2ecf20Sopenharmony_ci		return ret;
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	PUSH_MTHD(push, NV507D, HEAD_SET_BASE_LUT_LO(i),
2898c2ecf20Sopenharmony_ci		  NVDEF(NV507D, HEAD_SET_BASE_LUT_LO, ENABLE, DISABLE));
2908c2ecf20Sopenharmony_ci	return 0;
2918c2ecf20Sopenharmony_ci}
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_cistatic int
2948c2ecf20Sopenharmony_cihead507d_olut_set(struct nv50_head *head, struct nv50_head_atom *asyh)
2958c2ecf20Sopenharmony_ci{
2968c2ecf20Sopenharmony_ci	struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
2978c2ecf20Sopenharmony_ci	const int i = head->base.index;
2988c2ecf20Sopenharmony_ci	int ret;
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	if ((ret = PUSH_WAIT(push, 3)))
3018c2ecf20Sopenharmony_ci		return ret;
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	PUSH_MTHD(push, NV507D, HEAD_SET_BASE_LUT_LO(i),
3048c2ecf20Sopenharmony_ci		  NVDEF(NV507D, HEAD_SET_BASE_LUT_LO, ENABLE, ENABLE) |
3058c2ecf20Sopenharmony_ci		  NVVAL(NV507D, HEAD_SET_BASE_LUT_LO, MODE, asyh->olut.mode) |
3068c2ecf20Sopenharmony_ci		  NVVAL(NV507D, HEAD_SET_BASE_LUT_LO, ORIGIN, 0),
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci				HEAD_SET_BASE_LUT_HI(i),
3098c2ecf20Sopenharmony_ci		  NVVAL(NV507D, HEAD_SET_BASE_LUT_HI, ORIGIN, asyh->olut.offset >> 8));
3108c2ecf20Sopenharmony_ci	return 0;
3118c2ecf20Sopenharmony_ci}
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_cistatic void
3148c2ecf20Sopenharmony_cihead507d_olut_load(struct drm_color_lut *in, int size, void __iomem *mem)
3158c2ecf20Sopenharmony_ci{
3168c2ecf20Sopenharmony_ci	for (; size--; in++, mem += 8) {
3178c2ecf20Sopenharmony_ci		writew(drm_color_lut_extract(in->  red, 11) << 3, mem + 0);
3188c2ecf20Sopenharmony_ci		writew(drm_color_lut_extract(in->green, 11) << 3, mem + 2);
3198c2ecf20Sopenharmony_ci		writew(drm_color_lut_extract(in-> blue, 11) << 3, mem + 4);
3208c2ecf20Sopenharmony_ci	}
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	/* INTERPOLATE modes require a "next" entry to interpolate with,
3238c2ecf20Sopenharmony_ci	 * so we replicate the last entry to deal with this for now.
3248c2ecf20Sopenharmony_ci	 */
3258c2ecf20Sopenharmony_ci	writew(readw(mem - 8), mem + 0);
3268c2ecf20Sopenharmony_ci	writew(readw(mem - 6), mem + 2);
3278c2ecf20Sopenharmony_ci	writew(readw(mem - 4), mem + 4);
3288c2ecf20Sopenharmony_ci}
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_cibool
3318c2ecf20Sopenharmony_cihead507d_olut(struct nv50_head *head, struct nv50_head_atom *asyh, int size)
3328c2ecf20Sopenharmony_ci{
3338c2ecf20Sopenharmony_ci	if (size != 256)
3348c2ecf20Sopenharmony_ci		return false;
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	if (asyh->base.cpp == 1)
3378c2ecf20Sopenharmony_ci		asyh->olut.mode = NV507D_HEAD_SET_BASE_LUT_LO_MODE_LORES;
3388c2ecf20Sopenharmony_ci	else
3398c2ecf20Sopenharmony_ci		asyh->olut.mode = NV507D_HEAD_SET_BASE_LUT_LO_MODE_HIRES;
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	asyh->olut.load = head507d_olut_load;
3428c2ecf20Sopenharmony_ci	return true;
3438c2ecf20Sopenharmony_ci}
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ciint
3468c2ecf20Sopenharmony_cihead507d_mode(struct nv50_head *head, struct nv50_head_atom *asyh)
3478c2ecf20Sopenharmony_ci{
3488c2ecf20Sopenharmony_ci	struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
3498c2ecf20Sopenharmony_ci	struct nv50_head_mode *m = &asyh->mode;
3508c2ecf20Sopenharmony_ci	const int i = head->base.index;
3518c2ecf20Sopenharmony_ci	int ret;
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	if ((ret = PUSH_WAIT(push, 13)))
3548c2ecf20Sopenharmony_ci		return ret;
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	PUSH_MTHD(push, NV507D, HEAD_SET_PIXEL_CLOCK(i),
3578c2ecf20Sopenharmony_ci		  NVVAL(NV507D, HEAD_SET_PIXEL_CLOCK, FREQUENCY, m->clock) |
3588c2ecf20Sopenharmony_ci		  NVDEF(NV507D, HEAD_SET_PIXEL_CLOCK, MODE, CLK_CUSTOM) |
3598c2ecf20Sopenharmony_ci		  NVDEF(NV507D, HEAD_SET_PIXEL_CLOCK, ADJ1000DIV1001, FALSE) |
3608c2ecf20Sopenharmony_ci		  NVDEF(NV507D, HEAD_SET_PIXEL_CLOCK, NOT_DRIVER, FALSE),
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci				HEAD_SET_CONTROL(i),
3638c2ecf20Sopenharmony_ci		  NVVAL(NV507D, HEAD_SET_CONTROL, STRUCTURE, m->interlace));
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	PUSH_MTHD(push, NV507D, HEAD_SET_OVERSCAN_COLOR(i),
3668c2ecf20Sopenharmony_ci		  NVVAL(NV507D, HEAD_SET_OVERSCAN_COLOR, RED, 0) |
3678c2ecf20Sopenharmony_ci		  NVVAL(NV507D, HEAD_SET_OVERSCAN_COLOR, GRN, 0) |
3688c2ecf20Sopenharmony_ci		  NVVAL(NV507D, HEAD_SET_OVERSCAN_COLOR, BLU, 0),
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci				HEAD_SET_RASTER_SIZE(i),
3718c2ecf20Sopenharmony_ci		  NVVAL(NV507D, HEAD_SET_RASTER_SIZE, WIDTH, m->h.active) |
3728c2ecf20Sopenharmony_ci		  NVVAL(NV507D, HEAD_SET_RASTER_SIZE, HEIGHT, m->v.active),
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci				HEAD_SET_RASTER_SYNC_END(i),
3758c2ecf20Sopenharmony_ci		  NVVAL(NV507D, HEAD_SET_RASTER_SYNC_END, X, m->h.synce) |
3768c2ecf20Sopenharmony_ci		  NVVAL(NV507D, HEAD_SET_RASTER_SYNC_END, Y, m->v.synce),
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci				HEAD_SET_RASTER_BLANK_END(i),
3798c2ecf20Sopenharmony_ci		  NVVAL(NV507D, HEAD_SET_RASTER_BLANK_END, X, m->h.blanke) |
3808c2ecf20Sopenharmony_ci		  NVVAL(NV507D, HEAD_SET_RASTER_BLANK_END, Y, m->v.blanke),
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci				HEAD_SET_RASTER_BLANK_START(i),
3838c2ecf20Sopenharmony_ci		  NVVAL(NV507D, HEAD_SET_RASTER_BLANK_START, X, m->h.blanks) |
3848c2ecf20Sopenharmony_ci		  NVVAL(NV507D, HEAD_SET_RASTER_BLANK_START, Y, m->v.blanks),
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci				HEAD_SET_RASTER_VERT_BLANK2(i),
3878c2ecf20Sopenharmony_ci		  NVVAL(NV507D, HEAD_SET_RASTER_VERT_BLANK2, YSTART, m->v.blank2s) |
3888c2ecf20Sopenharmony_ci		  NVVAL(NV507D, HEAD_SET_RASTER_VERT_BLANK2, YEND, m->v.blank2e),
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci				HEAD_SET_RASTER_VERT_BLANK_DMI(i),
3918c2ecf20Sopenharmony_ci		  NVVAL(NV507D, HEAD_SET_RASTER_VERT_BLANK_DMI, DURATION, m->v.blankus));
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	PUSH_MTHD(push, NV507D, HEAD_SET_DEFAULT_BASE_COLOR(i),
3948c2ecf20Sopenharmony_ci		  NVVAL(NV507D, HEAD_SET_DEFAULT_BASE_COLOR, RED, 0) |
3958c2ecf20Sopenharmony_ci		  NVVAL(NV507D, HEAD_SET_DEFAULT_BASE_COLOR, GREEN, 0) |
3968c2ecf20Sopenharmony_ci		  NVVAL(NV507D, HEAD_SET_DEFAULT_BASE_COLOR, BLUE, 0));
3978c2ecf20Sopenharmony_ci	return 0;
3988c2ecf20Sopenharmony_ci}
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ciint
4018c2ecf20Sopenharmony_cihead507d_view(struct nv50_head *head, struct nv50_head_atom *asyh)
4028c2ecf20Sopenharmony_ci{
4038c2ecf20Sopenharmony_ci	struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
4048c2ecf20Sopenharmony_ci	const int i = head->base.index;
4058c2ecf20Sopenharmony_ci	int ret;
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	if ((ret = PUSH_WAIT(push, 7)))
4088c2ecf20Sopenharmony_ci		return ret;
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	PUSH_MTHD(push, NV507D, HEAD_SET_CONTROL_OUTPUT_SCALER(i),
4118c2ecf20Sopenharmony_ci		  NVDEF(NV507D, HEAD_SET_CONTROL_OUTPUT_SCALER, VERTICAL_TAPS, TAPS_1) |
4128c2ecf20Sopenharmony_ci		  NVDEF(NV507D, HEAD_SET_CONTROL_OUTPUT_SCALER, HORIZONTAL_TAPS, TAPS_1) |
4138c2ecf20Sopenharmony_ci		  NVVAL(NV507D, HEAD_SET_CONTROL_OUTPUT_SCALER, HRESPONSE_BIAS, 0) |
4148c2ecf20Sopenharmony_ci		  NVVAL(NV507D, HEAD_SET_CONTROL_OUTPUT_SCALER, VRESPONSE_BIAS, 0));
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	PUSH_MTHD(push, NV507D, HEAD_SET_VIEWPORT_SIZE_IN(i),
4178c2ecf20Sopenharmony_ci		  NVVAL(NV507D, HEAD_SET_VIEWPORT_SIZE_IN, WIDTH, asyh->view.iW) |
4188c2ecf20Sopenharmony_ci		  NVVAL(NV507D, HEAD_SET_VIEWPORT_SIZE_IN, HEIGHT, asyh->view.iH));
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci	PUSH_MTHD(push, NV507D, HEAD_SET_VIEWPORT_SIZE_OUT(i),
4218c2ecf20Sopenharmony_ci		  NVVAL(NV507D, HEAD_SET_VIEWPORT_SIZE_OUT, WIDTH, asyh->view.oW) |
4228c2ecf20Sopenharmony_ci		  NVVAL(NV507D, HEAD_SET_VIEWPORT_SIZE_OUT, HEIGHT, asyh->view.oH),
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci				HEAD_SET_VIEWPORT_SIZE_OUT_MIN(i),
4258c2ecf20Sopenharmony_ci		  NVVAL(NV507D, HEAD_SET_VIEWPORT_SIZE_OUT_MIN, WIDTH, asyh->view.oW) |
4268c2ecf20Sopenharmony_ci		  NVVAL(NV507D, HEAD_SET_VIEWPORT_SIZE_OUT_MIN, HEIGHT, asyh->view.oH));
4278c2ecf20Sopenharmony_ci	return 0;
4288c2ecf20Sopenharmony_ci}
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ciconst struct nv50_head_func
4318c2ecf20Sopenharmony_cihead507d = {
4328c2ecf20Sopenharmony_ci	.view = head507d_view,
4338c2ecf20Sopenharmony_ci	.mode = head507d_mode,
4348c2ecf20Sopenharmony_ci	.olut = head507d_olut,
4358c2ecf20Sopenharmony_ci	.olut_size = 256,
4368c2ecf20Sopenharmony_ci	.olut_set = head507d_olut_set,
4378c2ecf20Sopenharmony_ci	.olut_clr = head507d_olut_clr,
4388c2ecf20Sopenharmony_ci	.core_calc = head507d_core_calc,
4398c2ecf20Sopenharmony_ci	.core_set = head507d_core_set,
4408c2ecf20Sopenharmony_ci	.core_clr = head507d_core_clr,
4418c2ecf20Sopenharmony_ci	.curs_layout = head507d_curs_layout,
4428c2ecf20Sopenharmony_ci	.curs_format = head507d_curs_format,
4438c2ecf20Sopenharmony_ci	.curs_set = head507d_curs_set,
4448c2ecf20Sopenharmony_ci	.curs_clr = head507d_curs_clr,
4458c2ecf20Sopenharmony_ci	.base = head507d_base,
4468c2ecf20Sopenharmony_ci	.ovly = head507d_ovly,
4478c2ecf20Sopenharmony_ci	.dither = head507d_dither,
4488c2ecf20Sopenharmony_ci	.procamp = head507d_procamp,
4498c2ecf20Sopenharmony_ci};
450