1/*
2 * Copyright 2018 Red Hat Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 */
22#include "base.h"
23
24#include <nvif/cl507c.h>
25#include <nvif/event.h>
26#include <nvif/push507c.h>
27#include <nvif/timer.h>
28
29#include <nvhw/class/cl507c.h>
30
31#include <drm/drm_atomic_helper.h>
32#include <drm/drm_fourcc.h>
33#include <drm/drm_plane_helper.h>
34
35#include "nouveau_bo.h"
36
37int
38base507c_update(struct nv50_wndw *wndw, u32 *interlock)
39{
40	struct nvif_push *push = wndw->wndw.push;
41	int ret;
42
43	if ((ret = PUSH_WAIT(push, 2)))
44		return ret;
45
46	PUSH_MTHD(push, NV507C, UPDATE, interlock[NV50_DISP_INTERLOCK_CORE]);
47	return PUSH_KICK(push);
48}
49
50int
51base507c_image_clr(struct nv50_wndw *wndw)
52{
53	struct nvif_push *push = wndw->wndw.push;
54	int ret;
55
56	if ((ret = PUSH_WAIT(push, 4)))
57		return ret;
58
59	PUSH_MTHD(push, NV507C, SET_PRESENT_CONTROL,
60		  NVDEF(NV507C, SET_PRESENT_CONTROL, BEGIN_MODE, NON_TEARING) |
61		  NVVAL(NV507C, SET_PRESENT_CONTROL, MIN_PRESENT_INTERVAL, 0));
62
63	PUSH_MTHD(push, NV507C, SET_CONTEXT_DMA_ISO, 0x00000000);
64	return 0;
65}
66
67static int
68base507c_image_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
69{
70	struct nvif_push *push = wndw->wndw.push;
71	int ret;
72
73	if ((ret = PUSH_WAIT(push, 13)))
74		return ret;
75
76	PUSH_MTHD(push, NV507C, SET_PRESENT_CONTROL,
77		  NVVAL(NV507C, SET_PRESENT_CONTROL, BEGIN_MODE, asyw->image.mode) |
78		  NVVAL(NV507C, SET_PRESENT_CONTROL, MIN_PRESENT_INTERVAL, asyw->image.interval));
79
80	PUSH_MTHD(push, NV507C, SET_CONTEXT_DMA_ISO, asyw->image.handle[0]);
81
82	if (asyw->image.format == NV507C_SURFACE_SET_PARAMS_FORMAT_RF16_GF16_BF16_AF16) {
83		PUSH_MTHD(push, NV507C, SET_PROCESSING,
84			  NVDEF(NV507C, SET_PROCESSING, USE_GAIN_OFS, ENABLE),
85
86					SET_CONVERSION,
87			  NVVAL(NV507C, SET_CONVERSION, GAIN, 0) |
88			  NVVAL(NV507C, SET_CONVERSION, OFS, 0x64));
89	} else {
90		PUSH_MTHD(push, NV507C, SET_PROCESSING,
91			  NVDEF(NV507C, SET_PROCESSING, USE_GAIN_OFS, DISABLE),
92
93					SET_CONVERSION,
94			  NVVAL(NV507C, SET_CONVERSION, GAIN, 0) |
95			  NVVAL(NV507C, SET_CONVERSION, OFS, 0));
96	}
97
98	PUSH_MTHD(push, NV507C, SURFACE_SET_OFFSET(0, 0), asyw->image.offset[0] >> 8);
99
100	PUSH_MTHD(push, NV507C, SURFACE_SET_SIZE(0),
101		  NVVAL(NV507C, SURFACE_SET_SIZE, WIDTH, asyw->image.w) |
102		  NVVAL(NV507C, SURFACE_SET_SIZE, HEIGHT, asyw->image.h),
103
104				SURFACE_SET_STORAGE(0),
105		  NVVAL(NV507C, SURFACE_SET_STORAGE, MEMORY_LAYOUT, asyw->image.layout) |
106		  NVVAL(NV507C, SURFACE_SET_STORAGE, PITCH, asyw->image.pitch[0] >> 8) |
107		  NVVAL(NV507C, SURFACE_SET_STORAGE, PITCH, asyw->image.blocks[0]) |
108		  NVVAL(NV507C, SURFACE_SET_STORAGE, BLOCK_HEIGHT, asyw->image.blockh),
109
110				SURFACE_SET_PARAMS(0),
111		  NVVAL(NV507C, SURFACE_SET_PARAMS, FORMAT, asyw->image.format) |
112		  NVDEF(NV507C, SURFACE_SET_PARAMS, SUPER_SAMPLE, X1_AA) |
113		  NVDEF(NV507C, SURFACE_SET_PARAMS, GAMMA, LINEAR) |
114		  NVDEF(NV507C, SURFACE_SET_PARAMS, LAYOUT, FRM) |
115		  NVVAL(NV507C, SURFACE_SET_PARAMS, KIND, asyw->image.kind) |
116		  NVDEF(NV507C, SURFACE_SET_PARAMS, PART_STRIDE, PARTSTRIDE_256));
117	return 0;
118}
119
120int
121base507c_xlut_clr(struct nv50_wndw *wndw)
122{
123	struct nvif_push *push = wndw->wndw.push;
124	int ret;
125
126	if ((ret = PUSH_WAIT(push, 2)))
127		return ret;
128
129	PUSH_MTHD(push, NV507C, SET_BASE_LUT_LO,
130		  NVDEF(NV507C, SET_BASE_LUT_LO, ENABLE, DISABLE));
131	return 0;
132}
133
134int
135base507c_xlut_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
136{
137	struct nvif_push *push = wndw->wndw.push;
138	int ret;
139
140	if ((ret = PUSH_WAIT(push, 2)))
141		return ret;
142
143	PUSH_MTHD(push, NV507C, SET_BASE_LUT_LO,
144		  NVDEF(NV507C, SET_BASE_LUT_LO, ENABLE, USE_CORE_LUT));
145	return 0;
146}
147
148int
149base507c_ntfy_wait_begun(struct nouveau_bo *bo, u32 offset,
150			 struct nvif_device *device)
151{
152	s64 time = nvif_msec(device, 2000ULL,
153		if (NVBO_TD32(bo, offset, NV_DISP_BASE_NOTIFIER_1, _0, STATUS, ==, BEGUN))
154			break;
155		usleep_range(1, 2);
156	);
157	return time < 0 ? time : 0;
158}
159
160int
161base507c_ntfy_clr(struct nv50_wndw *wndw)
162{
163	struct nvif_push *push = wndw->wndw.push;
164	int ret;
165
166	if ((ret = PUSH_WAIT(push, 2)))
167		return ret;
168
169	PUSH_MTHD(push, NV507C, SET_CONTEXT_DMA_NOTIFIER, 0x00000000);
170	return 0;
171}
172
173int
174base507c_ntfy_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
175{
176	struct nvif_push *push = wndw->wndw.push;
177	int ret;
178
179	if ((ret = PUSH_WAIT(push, 3)))
180		return ret;
181
182	PUSH_MTHD(push, NV507C, SET_NOTIFIER_CONTROL,
183		  NVVAL(NV507C, SET_NOTIFIER_CONTROL, MODE, asyw->ntfy.awaken) |
184		  NVVAL(NV507C, SET_NOTIFIER_CONTROL, OFFSET, asyw->ntfy.offset >> 2),
185
186				SET_CONTEXT_DMA_NOTIFIER, asyw->ntfy.handle);
187	return 0;
188}
189
190void
191base507c_ntfy_reset(struct nouveau_bo *bo, u32 offset)
192{
193	NVBO_WR32(bo, offset, NV_DISP_BASE_NOTIFIER_1, _0,
194			NVDEF(NV_DISP_BASE_NOTIFIER_1, _0, STATUS, NOT_BEGUN));
195}
196
197int
198base507c_sema_clr(struct nv50_wndw *wndw)
199{
200	struct nvif_push *push = wndw->wndw.push;
201	int ret;
202
203	if ((ret = PUSH_WAIT(push, 2)))
204		return ret;
205
206	PUSH_MTHD(push, NV507C, SET_CONTEXT_DMA_SEMAPHORE, 0x00000000);
207	return 0;
208}
209
210int
211base507c_sema_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
212{
213	struct nvif_push *push = wndw->wndw.push;
214	int ret;
215
216	if ((ret = PUSH_WAIT(push, 5)))
217		return ret;
218
219	PUSH_MTHD(push, NV507C, SET_SEMAPHORE_CONTROL, asyw->sema.offset,
220				SET_SEMAPHORE_ACQUIRE, asyw->sema.acquire,
221				SET_SEMAPHORE_RELEASE, asyw->sema.release,
222				SET_CONTEXT_DMA_SEMAPHORE, asyw->sema.handle);
223	return 0;
224}
225
226void
227base507c_release(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw,
228		 struct nv50_head_atom *asyh)
229{
230	asyh->base.cpp = 0;
231}
232
233int
234base507c_acquire(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw,
235		 struct nv50_head_atom *asyh)
236{
237	const struct drm_framebuffer *fb = asyw->state.fb;
238	int ret;
239
240	ret = drm_atomic_helper_check_plane_state(&asyw->state, &asyh->state,
241						  DRM_PLANE_HELPER_NO_SCALING,
242						  DRM_PLANE_HELPER_NO_SCALING,
243						  false, true);
244	if (ret)
245		return ret;
246
247	if (!wndw->func->ilut) {
248		if ((asyh->base.cpp != 1) ^ (fb->format->cpp[0] != 1))
249			asyh->state.color_mgmt_changed = true;
250	}
251
252	asyh->base.depth = fb->format->depth;
253	asyh->base.cpp = fb->format->cpp[0];
254	asyh->base.x = asyw->state.src.x1 >> 16;
255	asyh->base.y = asyw->state.src.y1 >> 16;
256	asyh->base.w = asyw->state.fb->width;
257	asyh->base.h = asyw->state.fb->height;
258
259	/* Some newer formats, esp FP16 ones, don't have a
260	 * "depth". There's nothing that really makes sense there
261	 * either, so just set it to the implicit bit count.
262	 */
263	if (!asyh->base.depth)
264		asyh->base.depth = asyh->base.cpp * 8;
265
266	return 0;
267}
268
269const u32
270base507c_format[] = {
271	DRM_FORMAT_C8,
272	DRM_FORMAT_RGB565,
273	DRM_FORMAT_XRGB1555,
274	DRM_FORMAT_ARGB1555,
275	DRM_FORMAT_XRGB8888,
276	DRM_FORMAT_ARGB8888,
277	DRM_FORMAT_XBGR2101010,
278	DRM_FORMAT_ABGR2101010,
279	DRM_FORMAT_XBGR8888,
280	DRM_FORMAT_ABGR8888,
281	DRM_FORMAT_XBGR16161616F,
282	DRM_FORMAT_ABGR16161616F,
283	0
284};
285
286static const struct nv50_wndw_func
287base507c = {
288	.acquire = base507c_acquire,
289	.release = base507c_release,
290	.sema_set = base507c_sema_set,
291	.sema_clr = base507c_sema_clr,
292	.ntfy_reset = base507c_ntfy_reset,
293	.ntfy_set = base507c_ntfy_set,
294	.ntfy_clr = base507c_ntfy_clr,
295	.ntfy_wait_begun = base507c_ntfy_wait_begun,
296	.olut_core = 1,
297	.xlut_set = base507c_xlut_set,
298	.xlut_clr = base507c_xlut_clr,
299	.image_set = base507c_image_set,
300	.image_clr = base507c_image_clr,
301	.update = base507c_update,
302};
303
304int
305base507c_new_(const struct nv50_wndw_func *func, const u32 *format,
306	      struct nouveau_drm *drm, int head, s32 oclass, u32 interlock_data,
307	      struct nv50_wndw **pwndw)
308{
309	struct nv50_disp_base_channel_dma_v0 args = {
310		.head = head,
311	};
312	struct nouveau_display *disp = nouveau_display(drm->dev);
313	struct nv50_disp *disp50 = nv50_disp(drm->dev);
314	struct nv50_wndw *wndw;
315	int ret;
316
317	ret = nv50_wndw_new_(func, drm->dev, DRM_PLANE_TYPE_PRIMARY,
318			     "base", head, format, BIT(head),
319			     NV50_DISP_INTERLOCK_BASE, interlock_data, &wndw);
320	if (*pwndw = wndw, ret)
321		return ret;
322
323	ret = nv50_dmac_create(&drm->client.device, &disp->disp.object,
324			       &oclass, head, &args, sizeof(args),
325			       disp50->sync->offset, &wndw->wndw);
326	if (ret) {
327		NV_ERROR(drm, "base%04x allocation failed: %d\n", oclass, ret);
328		return ret;
329	}
330
331	ret = nvif_notify_ctor(&wndw->wndw.base.user, "kmsBaseNtfy",
332			       wndw->notify.func, false,
333			       NV50_DISP_BASE_CHANNEL_DMA_V0_NTFY_UEVENT,
334			       &(struct nvif_notify_uevent_req) {},
335			       sizeof(struct nvif_notify_uevent_req),
336			       sizeof(struct nvif_notify_uevent_rep),
337			       &wndw->notify);
338	if (ret)
339		return ret;
340
341	wndw->ntfy = NV50_DISP_BASE_NTFY(wndw->id);
342	wndw->sema = NV50_DISP_BASE_SEM0(wndw->id);
343	wndw->data = 0x00000000;
344	return 0;
345}
346
347int
348base507c_new(struct nouveau_drm *drm, int head, s32 oclass,
349	     struct nv50_wndw **pwndw)
350{
351	return base507c_new_(&base507c, base507c_format, drm, head, oclass,
352			     0x00000002 << (head * 8), pwndw);
353}
354