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 <drm/drm_connector.h>
238c2ecf20Sopenharmony_ci#include <drm/drm_mode_config.h>
248c2ecf20Sopenharmony_ci#include <drm/drm_vblank.h>
258c2ecf20Sopenharmony_ci#include "nouveau_drv.h"
268c2ecf20Sopenharmony_ci#include "nouveau_bios.h"
278c2ecf20Sopenharmony_ci#include "nouveau_connector.h"
288c2ecf20Sopenharmony_ci#include "head.h"
298c2ecf20Sopenharmony_ci#include "core.h"
308c2ecf20Sopenharmony_ci#include "crc.h"
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#include <nvif/push507c.h>
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci#include <nvhw/class/cl907d.h>
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ciint
378c2ecf20Sopenharmony_cihead907d_or(struct nv50_head *head, struct nv50_head_atom *asyh)
388c2ecf20Sopenharmony_ci{
398c2ecf20Sopenharmony_ci	struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
408c2ecf20Sopenharmony_ci	const int i = head->base.index;
418c2ecf20Sopenharmony_ci	int ret;
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	if ((ret = PUSH_WAIT(push, 3)))
448c2ecf20Sopenharmony_ci		return ret;
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	PUSH_MTHD(push, NV907D, HEAD_SET_CONTROL_OUTPUT_RESOURCE(i),
478c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_CONTROL_OUTPUT_RESOURCE, CRC_MODE, asyh->or.crc_raster) |
488c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_CONTROL_OUTPUT_RESOURCE, HSYNC_POLARITY, asyh->or.nhsync) |
498c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_CONTROL_OUTPUT_RESOURCE, VSYNC_POLARITY, asyh->or.nvsync) |
508c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_CONTROL_OUTPUT_RESOURCE, PIXEL_DEPTH, asyh->or.depth),
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci				HEAD_SET_CONTROL(i), 0x31ec6000 | head->base.index << 25 |
538c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_CONTROL, STRUCTURE, asyh->mode.interlace));
548c2ecf20Sopenharmony_ci	return 0;
558c2ecf20Sopenharmony_ci}
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ciint
588c2ecf20Sopenharmony_cihead907d_procamp(struct nv50_head *head, struct nv50_head_atom *asyh)
598c2ecf20Sopenharmony_ci{
608c2ecf20Sopenharmony_ci	struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
618c2ecf20Sopenharmony_ci	const int i = head->base.index;
628c2ecf20Sopenharmony_ci	int ret;
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	if ((ret = PUSH_WAIT(push, 2)))
658c2ecf20Sopenharmony_ci		return ret;
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	PUSH_MTHD(push, NV907D, HEAD_SET_PROCAMP(i),
688c2ecf20Sopenharmony_ci		  NVDEF(NV907D, HEAD_SET_PROCAMP, COLOR_SPACE, RGB) |
698c2ecf20Sopenharmony_ci		  NVDEF(NV907D, HEAD_SET_PROCAMP, CHROMA_LPF, AUTO) |
708c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_PROCAMP, SAT_COS, asyh->procamp.sat.cos) |
718c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_PROCAMP, SAT_SINE, asyh->procamp.sat.sin) |
728c2ecf20Sopenharmony_ci		  NVDEF(NV907D, HEAD_SET_PROCAMP, DYNAMIC_RANGE, VESA) |
738c2ecf20Sopenharmony_ci		  NVDEF(NV907D, HEAD_SET_PROCAMP, RANGE_COMPRESSION, DISABLE));
748c2ecf20Sopenharmony_ci	return 0;
758c2ecf20Sopenharmony_ci}
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_cistatic int
788c2ecf20Sopenharmony_cihead907d_dither(struct nv50_head *head, struct nv50_head_atom *asyh)
798c2ecf20Sopenharmony_ci{
808c2ecf20Sopenharmony_ci	struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
818c2ecf20Sopenharmony_ci	const int i = head->base.index;
828c2ecf20Sopenharmony_ci	int ret;
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	if ((ret = PUSH_WAIT(push, 2)))
858c2ecf20Sopenharmony_ci		return ret;
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	PUSH_MTHD(push, NV907D, HEAD_SET_DITHER_CONTROL(i),
888c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_DITHER_CONTROL, ENABLE, asyh->dither.enable) |
898c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_DITHER_CONTROL, BITS, asyh->dither.bits) |
908c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_DITHER_CONTROL, MODE, asyh->dither.mode) |
918c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_DITHER_CONTROL, PHASE, 0));
928c2ecf20Sopenharmony_ci	return 0;
938c2ecf20Sopenharmony_ci}
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ciint
968c2ecf20Sopenharmony_cihead907d_ovly(struct nv50_head *head, struct nv50_head_atom *asyh)
978c2ecf20Sopenharmony_ci{
988c2ecf20Sopenharmony_ci	struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
998c2ecf20Sopenharmony_ci	const int i = head->base.index;
1008c2ecf20Sopenharmony_ci	u32 bounds = 0;
1018c2ecf20Sopenharmony_ci	int ret;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	if (asyh->ovly.cpp) {
1048c2ecf20Sopenharmony_ci		switch (asyh->ovly.cpp) {
1058c2ecf20Sopenharmony_ci		case 8: bounds |= NVDEF(NV907D, HEAD_SET_OVERLAY_USAGE_BOUNDS, PIXEL_DEPTH, BPP_64); break;
1068c2ecf20Sopenharmony_ci		case 4: bounds |= NVDEF(NV907D, HEAD_SET_OVERLAY_USAGE_BOUNDS, PIXEL_DEPTH, BPP_32); break;
1078c2ecf20Sopenharmony_ci		case 2: bounds |= NVDEF(NV907D, HEAD_SET_OVERLAY_USAGE_BOUNDS, PIXEL_DEPTH, BPP_16); break;
1088c2ecf20Sopenharmony_ci		default:
1098c2ecf20Sopenharmony_ci			WARN_ON(1);
1108c2ecf20Sopenharmony_ci			break;
1118c2ecf20Sopenharmony_ci		}
1128c2ecf20Sopenharmony_ci		bounds |= NVDEF(NV907D, HEAD_SET_OVERLAY_USAGE_BOUNDS, USABLE, TRUE);
1138c2ecf20Sopenharmony_ci	} else {
1148c2ecf20Sopenharmony_ci		bounds |= NVDEF(NV907D, HEAD_SET_OVERLAY_USAGE_BOUNDS, PIXEL_DEPTH, BPP_16);
1158c2ecf20Sopenharmony_ci	}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	if ((ret = PUSH_WAIT(push, 2)))
1188c2ecf20Sopenharmony_ci		return ret;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	PUSH_MTHD(push, NV907D, HEAD_SET_OVERLAY_USAGE_BOUNDS(i), bounds);
1218c2ecf20Sopenharmony_ci	return 0;
1228c2ecf20Sopenharmony_ci}
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_cistatic int
1258c2ecf20Sopenharmony_cihead907d_base(struct nv50_head *head, struct nv50_head_atom *asyh)
1268c2ecf20Sopenharmony_ci{
1278c2ecf20Sopenharmony_ci	struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
1288c2ecf20Sopenharmony_ci	const int i = head->base.index;
1298c2ecf20Sopenharmony_ci	u32 bounds = 0;
1308c2ecf20Sopenharmony_ci	int ret;
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	if (asyh->base.cpp) {
1338c2ecf20Sopenharmony_ci		switch (asyh->base.cpp) {
1348c2ecf20Sopenharmony_ci		case 8: bounds |= NVDEF(NV907D, HEAD_SET_BASE_CHANNEL_USAGE_BOUNDS, PIXEL_DEPTH, BPP_64); break;
1358c2ecf20Sopenharmony_ci		case 4: bounds |= NVDEF(NV907D, HEAD_SET_BASE_CHANNEL_USAGE_BOUNDS, PIXEL_DEPTH, BPP_32); break;
1368c2ecf20Sopenharmony_ci		case 2: bounds |= NVDEF(NV907D, HEAD_SET_BASE_CHANNEL_USAGE_BOUNDS, PIXEL_DEPTH, BPP_16); break;
1378c2ecf20Sopenharmony_ci		case 1: bounds |= NVDEF(NV907D, HEAD_SET_BASE_CHANNEL_USAGE_BOUNDS, PIXEL_DEPTH, BPP_8); break;
1388c2ecf20Sopenharmony_ci		default:
1398c2ecf20Sopenharmony_ci			WARN_ON(1);
1408c2ecf20Sopenharmony_ci			break;
1418c2ecf20Sopenharmony_ci		}
1428c2ecf20Sopenharmony_ci		bounds |= NVDEF(NV907D, HEAD_SET_BASE_CHANNEL_USAGE_BOUNDS, USABLE, TRUE);
1438c2ecf20Sopenharmony_ci	}
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	if ((ret = PUSH_WAIT(push, 2)))
1468c2ecf20Sopenharmony_ci		return ret;
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	PUSH_MTHD(push, NV907D, HEAD_SET_BASE_CHANNEL_USAGE_BOUNDS(i), bounds);
1498c2ecf20Sopenharmony_ci	return 0;
1508c2ecf20Sopenharmony_ci}
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ciint
1538c2ecf20Sopenharmony_cihead907d_curs_clr(struct nv50_head *head)
1548c2ecf20Sopenharmony_ci{
1558c2ecf20Sopenharmony_ci	struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
1568c2ecf20Sopenharmony_ci	const int i = head->base.index;
1578c2ecf20Sopenharmony_ci	int ret;
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	if ((ret = PUSH_WAIT(push, 4)))
1608c2ecf20Sopenharmony_ci		return ret;
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	PUSH_MTHD(push, NV907D, HEAD_SET_CONTROL_CURSOR(i),
1638c2ecf20Sopenharmony_ci		  NVDEF(NV907D, HEAD_SET_CONTROL_CURSOR, ENABLE, DISABLE) |
1648c2ecf20Sopenharmony_ci		  NVDEF(NV907D, HEAD_SET_CONTROL_CURSOR, FORMAT, A8R8G8B8) |
1658c2ecf20Sopenharmony_ci		  NVDEF(NV907D, HEAD_SET_CONTROL_CURSOR, SIZE, W64_H64));
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	PUSH_MTHD(push, NV907D, HEAD_SET_CONTEXT_DMA_CURSOR(i), 0x00000000);
1688c2ecf20Sopenharmony_ci	return 0;
1698c2ecf20Sopenharmony_ci}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ciint
1728c2ecf20Sopenharmony_cihead907d_curs_set(struct nv50_head *head, struct nv50_head_atom *asyh)
1738c2ecf20Sopenharmony_ci{
1748c2ecf20Sopenharmony_ci	struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
1758c2ecf20Sopenharmony_ci	const int i = head->base.index;
1768c2ecf20Sopenharmony_ci	int ret;
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	if ((ret = PUSH_WAIT(push, 5)))
1798c2ecf20Sopenharmony_ci		return ret;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	PUSH_MTHD(push, NV907D, HEAD_SET_CONTROL_CURSOR(i),
1828c2ecf20Sopenharmony_ci		  NVDEF(NV907D, HEAD_SET_CONTROL_CURSOR, ENABLE, ENABLE) |
1838c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_CONTROL_CURSOR, FORMAT, asyh->curs.format) |
1848c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_CONTROL_CURSOR, SIZE, asyh->curs.layout) |
1858c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_CONTROL_CURSOR, HOT_SPOT_X, 0) |
1868c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_CONTROL_CURSOR, HOT_SPOT_Y, 0) |
1878c2ecf20Sopenharmony_ci		  NVDEF(NV907D, HEAD_SET_CONTROL_CURSOR, COMPOSITION, ALPHA_BLEND),
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci				HEAD_SET_OFFSET_CURSOR(i), asyh->curs.offset >> 8);
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	PUSH_MTHD(push, NV907D, HEAD_SET_CONTEXT_DMA_CURSOR(i), asyh->curs.handle);
1928c2ecf20Sopenharmony_ci	return 0;
1938c2ecf20Sopenharmony_ci}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ciint
1968c2ecf20Sopenharmony_cihead907d_core_clr(struct nv50_head *head)
1978c2ecf20Sopenharmony_ci{
1988c2ecf20Sopenharmony_ci	struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
1998c2ecf20Sopenharmony_ci	const int i = head->base.index;
2008c2ecf20Sopenharmony_ci	int ret;
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	if ((ret = PUSH_WAIT(push, 2)))
2038c2ecf20Sopenharmony_ci		return ret;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	PUSH_MTHD(push, NV907D, HEAD_SET_CONTEXT_DMAS_ISO(i), 0x00000000);
2068c2ecf20Sopenharmony_ci	return 0;
2078c2ecf20Sopenharmony_ci}
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ciint
2108c2ecf20Sopenharmony_cihead907d_core_set(struct nv50_head *head, struct nv50_head_atom *asyh)
2118c2ecf20Sopenharmony_ci{
2128c2ecf20Sopenharmony_ci	struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
2138c2ecf20Sopenharmony_ci	const int i = head->base.index;
2148c2ecf20Sopenharmony_ci	int ret;
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	if ((ret = PUSH_WAIT(push, 9)))
2178c2ecf20Sopenharmony_ci		return ret;
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	PUSH_MTHD(push, NV907D, HEAD_SET_OFFSET(i),
2208c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_OFFSET, ORIGIN, asyh->core.offset >> 8));
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	PUSH_MTHD(push, NV907D, HEAD_SET_SIZE(i),
2238c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_SIZE, WIDTH, asyh->core.w) |
2248c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_SIZE, HEIGHT, asyh->core.h),
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci				HEAD_SET_STORAGE(i),
2278c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_STORAGE, BLOCK_HEIGHT, asyh->core.blockh) |
2288c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_STORAGE, PITCH, asyh->core.pitch >> 8) |
2298c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_STORAGE, PITCH, asyh->core.blocks) |
2308c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_STORAGE, MEMORY_LAYOUT, asyh->core.layout),
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci				HEAD_SET_PARAMS(i),
2338c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_PARAMS, FORMAT, asyh->core.format) |
2348c2ecf20Sopenharmony_ci		  NVDEF(NV907D, HEAD_SET_PARAMS, SUPER_SAMPLE, X1_AA) |
2358c2ecf20Sopenharmony_ci		  NVDEF(NV907D, HEAD_SET_PARAMS, GAMMA, LINEAR),
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci				HEAD_SET_CONTEXT_DMAS_ISO(i),
2388c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_CONTEXT_DMAS_ISO, HANDLE, asyh->core.handle));
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	PUSH_MTHD(push, NV907D, HEAD_SET_VIEWPORT_POINT_IN(i),
2418c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_VIEWPORT_POINT_IN, X, asyh->core.x) |
2428c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_VIEWPORT_POINT_IN, Y, asyh->core.y));
2438c2ecf20Sopenharmony_ci	return 0;
2448c2ecf20Sopenharmony_ci}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ciint
2478c2ecf20Sopenharmony_cihead907d_olut_clr(struct nv50_head *head)
2488c2ecf20Sopenharmony_ci{
2498c2ecf20Sopenharmony_ci	struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
2508c2ecf20Sopenharmony_ci	const int i = head->base.index;
2518c2ecf20Sopenharmony_ci	int ret;
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	if ((ret = PUSH_WAIT(push, 4)))
2548c2ecf20Sopenharmony_ci		return ret;
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	PUSH_MTHD(push, NV907D, HEAD_SET_OUTPUT_LUT_LO(i),
2578c2ecf20Sopenharmony_ci		  NVDEF(NV907D, HEAD_SET_OUTPUT_LUT_LO, ENABLE, DISABLE));
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	PUSH_MTHD(push, NV907D, HEAD_SET_CONTEXT_DMA_LUT(i), 0x00000000);
2608c2ecf20Sopenharmony_ci	return 0;
2618c2ecf20Sopenharmony_ci}
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ciint
2648c2ecf20Sopenharmony_cihead907d_olut_set(struct nv50_head *head, struct nv50_head_atom *asyh)
2658c2ecf20Sopenharmony_ci{
2668c2ecf20Sopenharmony_ci	struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
2678c2ecf20Sopenharmony_ci	const int i = head->base.index;
2688c2ecf20Sopenharmony_ci	int ret;
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	if ((ret = PUSH_WAIT(push, 5)))
2718c2ecf20Sopenharmony_ci		return ret;
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	PUSH_MTHD(push, NV907D, HEAD_SET_OUTPUT_LUT_LO(i),
2748c2ecf20Sopenharmony_ci		  NVDEF(NV907D, HEAD_SET_OUTPUT_LUT_LO, ENABLE, ENABLE) |
2758c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_OUTPUT_LUT_LO, MODE, asyh->olut.mode) |
2768c2ecf20Sopenharmony_ci		  NVDEF(NV907D, HEAD_SET_OUTPUT_LUT_LO, NEVER_YIELD_TO_BASE, DISABLE),
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci				HEAD_SET_OUTPUT_LUT_HI(i),
2798c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_OUTPUT_LUT_HI, ORIGIN, asyh->olut.offset >> 8));
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	PUSH_MTHD(push, NV907D, HEAD_SET_CONTEXT_DMA_LUT(i), asyh->olut.handle);
2828c2ecf20Sopenharmony_ci	return 0;
2838c2ecf20Sopenharmony_ci}
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_civoid
2868c2ecf20Sopenharmony_cihead907d_olut_load(struct drm_color_lut *in, int size, void __iomem *mem)
2878c2ecf20Sopenharmony_ci{
2888c2ecf20Sopenharmony_ci	for (; size--; in++, mem += 8) {
2898c2ecf20Sopenharmony_ci		writew(drm_color_lut_extract(in->  red, 14) + 0x6000, mem + 0);
2908c2ecf20Sopenharmony_ci		writew(drm_color_lut_extract(in->green, 14) + 0x6000, mem + 2);
2918c2ecf20Sopenharmony_ci		writew(drm_color_lut_extract(in-> blue, 14) + 0x6000, mem + 4);
2928c2ecf20Sopenharmony_ci	}
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	/* INTERPOLATE modes require a "next" entry to interpolate with,
2958c2ecf20Sopenharmony_ci	 * so we replicate the last entry to deal with this for now.
2968c2ecf20Sopenharmony_ci	 */
2978c2ecf20Sopenharmony_ci	writew(readw(mem - 8), mem + 0);
2988c2ecf20Sopenharmony_ci	writew(readw(mem - 6), mem + 2);
2998c2ecf20Sopenharmony_ci	writew(readw(mem - 4), mem + 4);
3008c2ecf20Sopenharmony_ci}
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_cibool
3038c2ecf20Sopenharmony_cihead907d_olut(struct nv50_head *head, struct nv50_head_atom *asyh, int size)
3048c2ecf20Sopenharmony_ci{
3058c2ecf20Sopenharmony_ci	if (size != 256 && size != 1024)
3068c2ecf20Sopenharmony_ci		return false;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	if (size == 1024)
3098c2ecf20Sopenharmony_ci		asyh->olut.mode = NV907D_HEAD_SET_OUTPUT_LUT_LO_MODE_INTERPOLATE_1025_UNITY_RANGE;
3108c2ecf20Sopenharmony_ci	else
3118c2ecf20Sopenharmony_ci		asyh->olut.mode = NV907D_HEAD_SET_OUTPUT_LUT_LO_MODE_INTERPOLATE_257_UNITY_RANGE;
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	asyh->olut.load = head907d_olut_load;
3148c2ecf20Sopenharmony_ci	return true;
3158c2ecf20Sopenharmony_ci}
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ciint
3188c2ecf20Sopenharmony_cihead907d_mode(struct nv50_head *head, struct nv50_head_atom *asyh)
3198c2ecf20Sopenharmony_ci{
3208c2ecf20Sopenharmony_ci	struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
3218c2ecf20Sopenharmony_ci	struct nv50_head_mode *m = &asyh->mode;
3228c2ecf20Sopenharmony_ci	const int i = head->base.index;
3238c2ecf20Sopenharmony_ci	int ret;
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	if ((ret = PUSH_WAIT(push, 14)))
3268c2ecf20Sopenharmony_ci		return ret;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	PUSH_MTHD(push, NV907D, HEAD_SET_OVERSCAN_COLOR(i),
3298c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_OVERSCAN_COLOR, RED, 0) |
3308c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_OVERSCAN_COLOR, GRN, 0) |
3318c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_OVERSCAN_COLOR, BLU, 0),
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci				HEAD_SET_RASTER_SIZE(i),
3348c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_RASTER_SIZE, WIDTH, m->h.active) |
3358c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_RASTER_SIZE, HEIGHT, m->v.active),
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci				HEAD_SET_RASTER_SYNC_END(i),
3388c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_RASTER_SYNC_END, X, m->h.synce) |
3398c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_RASTER_SYNC_END, Y, m->v.synce),
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci				HEAD_SET_RASTER_BLANK_END(i),
3428c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_RASTER_BLANK_END, X, m->h.blanke) |
3438c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_RASTER_BLANK_END, Y, m->v.blanke),
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci				HEAD_SET_RASTER_BLANK_START(i),
3468c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_RASTER_BLANK_START, X, m->h.blanks) |
3478c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_RASTER_BLANK_START, Y, m->v.blanks),
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci				HEAD_SET_RASTER_VERT_BLANK2(i),
3508c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_RASTER_VERT_BLANK2, YSTART, m->v.blank2s) |
3518c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_RASTER_VERT_BLANK2, YEND, m->v.blank2e));
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	PUSH_MTHD(push, NV907D, HEAD_SET_DEFAULT_BASE_COLOR(i),
3548c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_DEFAULT_BASE_COLOR, RED, 0) |
3558c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_DEFAULT_BASE_COLOR, GREEN, 0) |
3568c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_DEFAULT_BASE_COLOR, BLUE, 0),
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci				HEAD_SET_CRC_CONTROL(i),
3598c2ecf20Sopenharmony_ci		  NVDEF(NV907D, HEAD_SET_CRC_CONTROL, CONTROLLING_CHANNEL, CORE) |
3608c2ecf20Sopenharmony_ci		  NVDEF(NV907D, HEAD_SET_CRC_CONTROL, EXPECT_BUFFER_COLLAPSE, FALSE) |
3618c2ecf20Sopenharmony_ci		  NVDEF(NV907D, HEAD_SET_CRC_CONTROL, TIMESTAMP_MODE, FALSE) |
3628c2ecf20Sopenharmony_ci		  NVDEF(NV907D, HEAD_SET_CRC_CONTROL, PRIMARY_OUTPUT, NONE) |
3638c2ecf20Sopenharmony_ci		  NVDEF(NV907D, HEAD_SET_CRC_CONTROL, SECONDARY_OUTPUT, NONE));
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	PUSH_MTHD(push, NV907D, HEAD_SET_PIXEL_CLOCK_FREQUENCY(i),
3668c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_PIXEL_CLOCK_FREQUENCY, HERTZ, m->clock * 1000) |
3678c2ecf20Sopenharmony_ci		  NVDEF(NV907D, HEAD_SET_PIXEL_CLOCK_FREQUENCY, ADJ1000DIV1001, FALSE),
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci				HEAD_SET_PIXEL_CLOCK_CONFIGURATION(i),
3708c2ecf20Sopenharmony_ci		  NVDEF(NV907D, HEAD_SET_PIXEL_CLOCK_CONFIGURATION, MODE, CLK_CUSTOM) |
3718c2ecf20Sopenharmony_ci		  NVDEF(NV907D, HEAD_SET_PIXEL_CLOCK_CONFIGURATION, NOT_DRIVER, FALSE) |
3728c2ecf20Sopenharmony_ci		  NVDEF(NV907D, HEAD_SET_PIXEL_CLOCK_CONFIGURATION, ENABLE_HOPPING, FALSE),
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci				HEAD_SET_PIXEL_CLOCK_FREQUENCY_MAX(i),
3758c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_PIXEL_CLOCK_FREQUENCY_MAX, HERTZ, m->clock * 1000) |
3768c2ecf20Sopenharmony_ci		  NVDEF(NV907D, HEAD_SET_PIXEL_CLOCK_FREQUENCY_MAX, ADJ1000DIV1001, FALSE));
3778c2ecf20Sopenharmony_ci	return 0;
3788c2ecf20Sopenharmony_ci}
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ciint
3818c2ecf20Sopenharmony_cihead907d_view(struct nv50_head *head, struct nv50_head_atom *asyh)
3828c2ecf20Sopenharmony_ci{
3838c2ecf20Sopenharmony_ci	struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
3848c2ecf20Sopenharmony_ci	const int i = head->base.index;
3858c2ecf20Sopenharmony_ci	int ret;
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	if ((ret = PUSH_WAIT(push, 8)))
3888c2ecf20Sopenharmony_ci		return ret;
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	PUSH_MTHD(push, NV907D, HEAD_SET_CONTROL_OUTPUT_SCALER(i),
3918c2ecf20Sopenharmony_ci		  NVDEF(NV907D, HEAD_SET_CONTROL_OUTPUT_SCALER, VERTICAL_TAPS, TAPS_1) |
3928c2ecf20Sopenharmony_ci		  NVDEF(NV907D, HEAD_SET_CONTROL_OUTPUT_SCALER, HORIZONTAL_TAPS, TAPS_1) |
3938c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_CONTROL_OUTPUT_SCALER, HRESPONSE_BIAS, 0) |
3948c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_CONTROL_OUTPUT_SCALER, VRESPONSE_BIAS, 0));
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	PUSH_MTHD(push, NV907D, HEAD_SET_VIEWPORT_SIZE_IN(i),
3978c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_VIEWPORT_SIZE_IN, WIDTH, asyh->view.iW) |
3988c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_VIEWPORT_SIZE_IN, HEIGHT, asyh->view.iH));
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	PUSH_MTHD(push, NV907D, HEAD_SET_VIEWPORT_SIZE_OUT(i),
4018c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_VIEWPORT_SIZE_OUT, WIDTH, asyh->view.oW) |
4028c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_VIEWPORT_SIZE_OUT, HEIGHT, asyh->view.oH),
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci				HEAD_SET_VIEWPORT_SIZE_OUT_MIN(i),
4058c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_VIEWPORT_SIZE_OUT_MIN, WIDTH, asyh->view.oW) |
4068c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_VIEWPORT_SIZE_OUT_MIN, HEIGHT, asyh->view.oH),
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci				HEAD_SET_VIEWPORT_SIZE_OUT_MAX(i),
4098c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_VIEWPORT_SIZE_OUT_MAX, WIDTH, asyh->view.oW) |
4108c2ecf20Sopenharmony_ci		  NVVAL(NV907D, HEAD_SET_VIEWPORT_SIZE_OUT_MAX, HEIGHT, asyh->view.oH));
4118c2ecf20Sopenharmony_ci	return 0;
4128c2ecf20Sopenharmony_ci}
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ciconst struct nv50_head_func
4158c2ecf20Sopenharmony_cihead907d = {
4168c2ecf20Sopenharmony_ci	.view = head907d_view,
4178c2ecf20Sopenharmony_ci	.mode = head907d_mode,
4188c2ecf20Sopenharmony_ci	.olut = head907d_olut,
4198c2ecf20Sopenharmony_ci	.olut_size = 1024,
4208c2ecf20Sopenharmony_ci	.olut_set = head907d_olut_set,
4218c2ecf20Sopenharmony_ci	.olut_clr = head907d_olut_clr,
4228c2ecf20Sopenharmony_ci	.core_calc = head507d_core_calc,
4238c2ecf20Sopenharmony_ci	.core_set = head907d_core_set,
4248c2ecf20Sopenharmony_ci	.core_clr = head907d_core_clr,
4258c2ecf20Sopenharmony_ci	.curs_layout = head507d_curs_layout,
4268c2ecf20Sopenharmony_ci	.curs_format = head507d_curs_format,
4278c2ecf20Sopenharmony_ci	.curs_set = head907d_curs_set,
4288c2ecf20Sopenharmony_ci	.curs_clr = head907d_curs_clr,
4298c2ecf20Sopenharmony_ci	.base = head907d_base,
4308c2ecf20Sopenharmony_ci	.ovly = head907d_ovly,
4318c2ecf20Sopenharmony_ci	.dither = head907d_dither,
4328c2ecf20Sopenharmony_ci	.procamp = head907d_procamp,
4338c2ecf20Sopenharmony_ci	.or = head907d_or,
4348c2ecf20Sopenharmony_ci};
435