162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright 2018 Red Hat Inc.
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
562306a36Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
662306a36Sopenharmony_ci * to deal in the Software without restriction, including without limitation
762306a36Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
862306a36Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
962306a36Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * The above copyright notice and this permission notice shall be included in
1262306a36Sopenharmony_ci * all copies or substantial portions of the Software.
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1562306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1662306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1762306a36Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
1862306a36Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
1962306a36Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2062306a36Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE.
2162306a36Sopenharmony_ci */
2262306a36Sopenharmony_ci#include "base.h"
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#include <nvif/push507c.h>
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#include <nvhw/class/cl907c.h>
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistatic int
2962306a36Sopenharmony_cibase907c_image_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
3062306a36Sopenharmony_ci{
3162306a36Sopenharmony_ci	struct nvif_push *push = wndw->wndw.push;
3262306a36Sopenharmony_ci	int ret;
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	if ((ret = PUSH_WAIT(push, 10)))
3562306a36Sopenharmony_ci		return ret;
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	PUSH_MTHD(push, NV907C, SET_PRESENT_CONTROL,
3862306a36Sopenharmony_ci		  NVVAL(NV907C, SET_PRESENT_CONTROL, BEGIN_MODE, asyw->image.mode) |
3962306a36Sopenharmony_ci		  NVDEF(NV907C, SET_PRESENT_CONTROL, TIMESTAMP_MODE, DISABLE) |
4062306a36Sopenharmony_ci		  NVVAL(NV907C, SET_PRESENT_CONTROL, MIN_PRESENT_INTERVAL, asyw->image.interval));
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	PUSH_MTHD(push, NV907C, SET_CONTEXT_DMAS_ISO(0), asyw->image.handle, 1);
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	PUSH_MTHD(push, NV907C, SURFACE_SET_OFFSET(0, 0), asyw->image.offset[0] >> 8,
4562306a36Sopenharmony_ci				SURFACE_SET_OFFSET(0, 1), 0x00000000,
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci				SURFACE_SET_SIZE(0),
4862306a36Sopenharmony_ci		  NVVAL(NV907C, SURFACE_SET_SIZE, WIDTH, asyw->image.w) |
4962306a36Sopenharmony_ci		  NVVAL(NV907C, SURFACE_SET_SIZE, HEIGHT, asyw->image.h),
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci				SURFACE_SET_STORAGE(0),
5262306a36Sopenharmony_ci		  NVVAL(NV907C, SURFACE_SET_STORAGE, BLOCK_HEIGHT, asyw->image.blockh) |
5362306a36Sopenharmony_ci		  NVVAL(NV907C, SURFACE_SET_STORAGE, PITCH, asyw->image.pitch[0] >> 8) |
5462306a36Sopenharmony_ci		  NVVAL(NV907C, SURFACE_SET_STORAGE, PITCH, asyw->image.blocks[0]) |
5562306a36Sopenharmony_ci		  NVVAL(NV907C, SURFACE_SET_STORAGE, MEMORY_LAYOUT, asyw->image.layout),
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci				SURFACE_SET_PARAMS(0),
5862306a36Sopenharmony_ci		  NVVAL(NV907C, SURFACE_SET_PARAMS, FORMAT, asyw->image.format) |
5962306a36Sopenharmony_ci		  NVDEF(NV907C, SURFACE_SET_PARAMS, SUPER_SAMPLE, X1_AA) |
6062306a36Sopenharmony_ci		  NVDEF(NV907C, SURFACE_SET_PARAMS, GAMMA, LINEAR) |
6162306a36Sopenharmony_ci		  NVDEF(NV907C, SURFACE_SET_PARAMS, LAYOUT, FRM));
6262306a36Sopenharmony_ci	return 0;
6362306a36Sopenharmony_ci}
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_cistatic int
6662306a36Sopenharmony_cibase907c_xlut_clr(struct nv50_wndw *wndw)
6762306a36Sopenharmony_ci{
6862306a36Sopenharmony_ci	struct nvif_push *push = wndw->wndw.push;
6962306a36Sopenharmony_ci	int ret;
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	if ((ret = PUSH_WAIT(push, 6)))
7262306a36Sopenharmony_ci		return ret;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	PUSH_MTHD(push, NV907C, SET_BASE_LUT_LO,
7562306a36Sopenharmony_ci		  NVDEF(NV907C, SET_BASE_LUT_LO, ENABLE, DISABLE));
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	PUSH_MTHD(push, NV907C, SET_OUTPUT_LUT_LO,
7862306a36Sopenharmony_ci		  NVDEF(NV907C, SET_OUTPUT_LUT_LO, ENABLE, DISABLE));
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	PUSH_MTHD(push, NV907C, SET_CONTEXT_DMA_LUT, 0x00000000);
8162306a36Sopenharmony_ci	return 0;
8262306a36Sopenharmony_ci}
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cistatic int
8562306a36Sopenharmony_cibase907c_xlut_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
8662306a36Sopenharmony_ci{
8762306a36Sopenharmony_ci	struct nvif_push *push = wndw->wndw.push;
8862306a36Sopenharmony_ci	int ret;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	if ((ret = PUSH_WAIT(push, 6)))
9162306a36Sopenharmony_ci		return ret;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	PUSH_MTHD(push, NV907C, SET_BASE_LUT_LO,
9462306a36Sopenharmony_ci		  NVVAL(NV907C, SET_BASE_LUT_LO, ENABLE, asyw->xlut.i.enable) |
9562306a36Sopenharmony_ci		  NVVAL(NV907C, SET_BASE_LUT_LO, MODE, asyw->xlut.i.mode),
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci				SET_BASE_LUT_HI, asyw->xlut.i.offset >> 8,
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci				SET_OUTPUT_LUT_LO,
10062306a36Sopenharmony_ci		  NVDEF(NV907C, SET_OUTPUT_LUT_LO, ENABLE, USE_CORE_LUT));
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	PUSH_MTHD(push, NV907C, SET_CONTEXT_DMA_LUT, asyw->xlut.handle);
10362306a36Sopenharmony_ci	return 0;
10462306a36Sopenharmony_ci}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_cistatic void
10762306a36Sopenharmony_cibase907c_ilut(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw, int size)
10862306a36Sopenharmony_ci{
10962306a36Sopenharmony_ci	if (size == 1024)
11062306a36Sopenharmony_ci		asyw->xlut.i.mode = NV907C_SET_BASE_LUT_LO_MODE_INTERPOLATE_1025_UNITY_RANGE;
11162306a36Sopenharmony_ci	else
11262306a36Sopenharmony_ci		asyw->xlut.i.mode = NV907C_SET_BASE_LUT_LO_MODE_INTERPOLATE_257_UNITY_RANGE;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	asyw->xlut.i.enable = NV907C_SET_BASE_LUT_LO_ENABLE_ENABLE;
11562306a36Sopenharmony_ci	asyw->xlut.i.load = head907d_olut_load;
11662306a36Sopenharmony_ci}
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_cistatic inline u32
11962306a36Sopenharmony_cicsc_drm_to_base(u64 in)
12062306a36Sopenharmony_ci{
12162306a36Sopenharmony_ci	/* base takes a 19-bit 2's complement value in S3.16 format */
12262306a36Sopenharmony_ci	bool sign = in & BIT_ULL(63);
12362306a36Sopenharmony_ci	u32 integer = (in >> 32) & 0x7fffffff;
12462306a36Sopenharmony_ci	u32 fraction = in & 0xffffffff;
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	if (integer >= 4) {
12762306a36Sopenharmony_ci		return (1 << 18) - (sign ? 0 : 1);
12862306a36Sopenharmony_ci	} else {
12962306a36Sopenharmony_ci		u32 ret = (integer << 16) | (fraction >> 16);
13062306a36Sopenharmony_ci		if (sign)
13162306a36Sopenharmony_ci			ret = -ret;
13262306a36Sopenharmony_ci		return ret & GENMASK(18, 0);
13362306a36Sopenharmony_ci	}
13462306a36Sopenharmony_ci}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_civoid
13762306a36Sopenharmony_cibase907c_csc(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw,
13862306a36Sopenharmony_ci	     const struct drm_color_ctm *ctm)
13962306a36Sopenharmony_ci{
14062306a36Sopenharmony_ci	int i, j;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	for (j = 0; j < 3; j++) {
14362306a36Sopenharmony_ci		for (i = 0; i < 4; i++) {
14462306a36Sopenharmony_ci			u32 *val = &asyw->csc.matrix[j * 4 + i];
14562306a36Sopenharmony_ci			/* DRM does not support constant offset, while
14662306a36Sopenharmony_ci			 * HW CSC does. Skip it. */
14762306a36Sopenharmony_ci			if (i == 3) {
14862306a36Sopenharmony_ci				*val = 0;
14962306a36Sopenharmony_ci			} else {
15062306a36Sopenharmony_ci				*val = csc_drm_to_base(ctm->matrix[j * 3 + i]);
15162306a36Sopenharmony_ci			}
15262306a36Sopenharmony_ci		}
15362306a36Sopenharmony_ci	}
15462306a36Sopenharmony_ci}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_cistatic int
15762306a36Sopenharmony_cibase907c_csc_clr(struct nv50_wndw *wndw)
15862306a36Sopenharmony_ci{
15962306a36Sopenharmony_ci	struct nvif_push *push = wndw->wndw.push;
16062306a36Sopenharmony_ci	int ret;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	if ((ret = PUSH_WAIT(push, 2)))
16362306a36Sopenharmony_ci		return ret;
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	PUSH_MTHD(push, NV907C, SET_CSC_RED2RED,
16662306a36Sopenharmony_ci		  NVDEF(NV907C, SET_CSC_RED2RED, OWNER, CORE));
16762306a36Sopenharmony_ci	return 0;
16862306a36Sopenharmony_ci}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_cistatic int
17162306a36Sopenharmony_cibase907c_csc_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
17262306a36Sopenharmony_ci{
17362306a36Sopenharmony_ci	struct nvif_push *push = wndw->wndw.push;
17462306a36Sopenharmony_ci	int ret;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	if ((ret = PUSH_WAIT(push, 13)))
17762306a36Sopenharmony_ci		return ret;
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	PUSH_MTHD(push, NV907C, SET_CSC_RED2RED,
18062306a36Sopenharmony_ci		  NVDEF(NV907C, SET_CSC_RED2RED, OWNER, BASE) |
18162306a36Sopenharmony_ci		  NVVAL(NV907C, SET_CSC_RED2RED, COEFF, asyw->csc.matrix[0]),
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci				SET_CSC_GRN2RED, &asyw->csc.matrix[1], 11);
18462306a36Sopenharmony_ci	return 0;
18562306a36Sopenharmony_ci}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ciconst struct nv50_wndw_func
18862306a36Sopenharmony_cibase907c = {
18962306a36Sopenharmony_ci	.acquire = base507c_acquire,
19062306a36Sopenharmony_ci	.release = base507c_release,
19162306a36Sopenharmony_ci	.sema_set = base507c_sema_set,
19262306a36Sopenharmony_ci	.sema_clr = base507c_sema_clr,
19362306a36Sopenharmony_ci	.ntfy_reset = base507c_ntfy_reset,
19462306a36Sopenharmony_ci	.ntfy_set = base507c_ntfy_set,
19562306a36Sopenharmony_ci	.ntfy_clr = base507c_ntfy_clr,
19662306a36Sopenharmony_ci	.ntfy_wait_begun = base507c_ntfy_wait_begun,
19762306a36Sopenharmony_ci	.ilut = base907c_ilut,
19862306a36Sopenharmony_ci	.csc = base907c_csc,
19962306a36Sopenharmony_ci	.csc_set = base907c_csc_set,
20062306a36Sopenharmony_ci	.csc_clr = base907c_csc_clr,
20162306a36Sopenharmony_ci	.olut_core = true,
20262306a36Sopenharmony_ci	.ilut_size = 1024,
20362306a36Sopenharmony_ci	.xlut_set = base907c_xlut_set,
20462306a36Sopenharmony_ci	.xlut_clr = base907c_xlut_clr,
20562306a36Sopenharmony_ci	.image_set = base907c_image_set,
20662306a36Sopenharmony_ci	.image_clr = base507c_image_clr,
20762306a36Sopenharmony_ci	.update = base507c_update,
20862306a36Sopenharmony_ci};
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ciint
21162306a36Sopenharmony_cibase907c_new(struct nouveau_drm *drm, int head, s32 oclass,
21262306a36Sopenharmony_ci	     struct nv50_wndw **pwndw)
21362306a36Sopenharmony_ci{
21462306a36Sopenharmony_ci	return base507c_new_(&base907c, base507c_format, drm, head, oclass,
21562306a36Sopenharmony_ci			     0x00000002 << (head * 4), pwndw);
21662306a36Sopenharmony_ci}
217