18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright 2009 Ben Skeggs
38c2ecf20Sopenharmony_ci * Copyright 2008 Stuart Bennett
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
68c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
78c2ecf20Sopenharmony_ci * to deal in the Software without restriction, including without limitation
88c2ecf20Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
98c2ecf20Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
108c2ecf20Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice (including the next
138c2ecf20Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
148c2ecf20Sopenharmony_ci * Software.
158c2ecf20Sopenharmony_ci *
168c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
178c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
188c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
198c2ecf20Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
208c2ecf20Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
218c2ecf20Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
228c2ecf20Sopenharmony_ci * DEALINGS IN THE SOFTWARE.
238c2ecf20Sopenharmony_ci */
248c2ecf20Sopenharmony_ci#define NVIF_DEBUG_PRINT_DISABLE
258c2ecf20Sopenharmony_ci#include "nouveau_drv.h"
268c2ecf20Sopenharmony_ci#include "nouveau_dma.h"
278c2ecf20Sopenharmony_ci#include "nouveau_fbcon.h"
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci#include <nvif/push006c.h>
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ciint
328c2ecf20Sopenharmony_cinv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region)
338c2ecf20Sopenharmony_ci{
348c2ecf20Sopenharmony_ci	struct nouveau_fbdev *nfbdev = info->par;
358c2ecf20Sopenharmony_ci	struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev);
368c2ecf20Sopenharmony_ci	struct nouveau_channel *chan = drm->channel;
378c2ecf20Sopenharmony_ci	struct nvif_push *push = chan->chan.push;
388c2ecf20Sopenharmony_ci	int ret;
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	ret = PUSH_WAIT(push, 4);
418c2ecf20Sopenharmony_ci	if (ret)
428c2ecf20Sopenharmony_ci		return ret;
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	PUSH_NVSQ(push, NV05F, 0x0300, (region->sy << 16) | region->sx,
458c2ecf20Sopenharmony_ci			       0x0304, (region->dy << 16) | region->dx,
468c2ecf20Sopenharmony_ci			       0x0308, (region->height << 16) | region->width);
478c2ecf20Sopenharmony_ci	PUSH_KICK(push);
488c2ecf20Sopenharmony_ci	return 0;
498c2ecf20Sopenharmony_ci}
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ciint
528c2ecf20Sopenharmony_cinv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
538c2ecf20Sopenharmony_ci{
548c2ecf20Sopenharmony_ci	struct nouveau_fbdev *nfbdev = info->par;
558c2ecf20Sopenharmony_ci	struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev);
568c2ecf20Sopenharmony_ci	struct nouveau_channel *chan = drm->channel;
578c2ecf20Sopenharmony_ci	struct nvif_push *push = chan->chan.push;
588c2ecf20Sopenharmony_ci	int ret;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	ret = PUSH_WAIT(push, 7);
618c2ecf20Sopenharmony_ci	if (ret)
628c2ecf20Sopenharmony_ci		return ret;
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	PUSH_NVSQ(push, NV04A, 0x02fc, (rect->rop != ROP_COPY) ? 1 : 3);
658c2ecf20Sopenharmony_ci	if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
668c2ecf20Sopenharmony_ci	    info->fix.visual == FB_VISUAL_DIRECTCOLOR)
678c2ecf20Sopenharmony_ci		PUSH_NVSQ(push, NV04A, 0x03fc, ((uint32_t *)info->pseudo_palette)[rect->color]);
688c2ecf20Sopenharmony_ci	else
698c2ecf20Sopenharmony_ci		PUSH_NVSQ(push, NV04A, 0x03fc, rect->color);
708c2ecf20Sopenharmony_ci	PUSH_NVSQ(push, NV04A, 0x0400, (rect->dx << 16) | rect->dy,
718c2ecf20Sopenharmony_ci			       0x0404, (rect->width << 16) | rect->height);
728c2ecf20Sopenharmony_ci	PUSH_KICK(push);
738c2ecf20Sopenharmony_ci	return 0;
748c2ecf20Sopenharmony_ci}
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ciint
778c2ecf20Sopenharmony_cinv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
788c2ecf20Sopenharmony_ci{
798c2ecf20Sopenharmony_ci	struct nouveau_fbdev *nfbdev = info->par;
808c2ecf20Sopenharmony_ci	struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev);
818c2ecf20Sopenharmony_ci	struct nouveau_channel *chan = drm->channel;
828c2ecf20Sopenharmony_ci	struct nvif_push *push = chan->chan.push;
838c2ecf20Sopenharmony_ci	uint32_t fg;
848c2ecf20Sopenharmony_ci	uint32_t bg;
858c2ecf20Sopenharmony_ci	uint32_t dsize;
868c2ecf20Sopenharmony_ci	uint32_t *data = (uint32_t *)image->data;
878c2ecf20Sopenharmony_ci	int ret;
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	if (image->depth != 1)
908c2ecf20Sopenharmony_ci		return -ENODEV;
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	ret = PUSH_WAIT(push, 8);
938c2ecf20Sopenharmony_ci	if (ret)
948c2ecf20Sopenharmony_ci		return ret;
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
978c2ecf20Sopenharmony_ci	    info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
988c2ecf20Sopenharmony_ci		fg = ((uint32_t *) info->pseudo_palette)[image->fg_color];
998c2ecf20Sopenharmony_ci		bg = ((uint32_t *) info->pseudo_palette)[image->bg_color];
1008c2ecf20Sopenharmony_ci	} else {
1018c2ecf20Sopenharmony_ci		fg = image->fg_color;
1028c2ecf20Sopenharmony_ci		bg = image->bg_color;
1038c2ecf20Sopenharmony_ci	}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	PUSH_NVSQ(push, NV04A, 0x0be4, (image->dy << 16) | (image->dx & 0xffff),
1068c2ecf20Sopenharmony_ci			       0x0be8, ((image->dy + image->height) << 16) |
1078c2ecf20Sopenharmony_ci				       ((image->dx + image->width) & 0xffff),
1088c2ecf20Sopenharmony_ci			       0x0bec, bg,
1098c2ecf20Sopenharmony_ci			       0x0bf0, fg,
1108c2ecf20Sopenharmony_ci			       0x0bf4, (image->height << 16) | ALIGN(image->width, 8),
1118c2ecf20Sopenharmony_ci			       0x0bf8, (image->height << 16) | image->width,
1128c2ecf20Sopenharmony_ci			       0x0bfc, (image->dy << 16) | (image->dx & 0xffff));
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	dsize = ALIGN(ALIGN(image->width, 8) * image->height, 32) >> 5;
1158c2ecf20Sopenharmony_ci	while (dsize) {
1168c2ecf20Sopenharmony_ci		int iter_len = dsize > 128 ? 128 : dsize;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci		ret = PUSH_WAIT(push, iter_len + 1);
1198c2ecf20Sopenharmony_ci		if (ret)
1208c2ecf20Sopenharmony_ci			return ret;
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci		PUSH_NVSQ(push, NV04A, 0x0c00, data, iter_len);
1238c2ecf20Sopenharmony_ci		data += iter_len;
1248c2ecf20Sopenharmony_ci		dsize -= iter_len;
1258c2ecf20Sopenharmony_ci	}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	PUSH_KICK(push);
1288c2ecf20Sopenharmony_ci	return 0;
1298c2ecf20Sopenharmony_ci}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ciint
1328c2ecf20Sopenharmony_cinv04_fbcon_accel_init(struct fb_info *info)
1338c2ecf20Sopenharmony_ci{
1348c2ecf20Sopenharmony_ci	struct nouveau_fbdev *nfbdev = info->par;
1358c2ecf20Sopenharmony_ci	struct drm_device *dev = nfbdev->helper.dev;
1368c2ecf20Sopenharmony_ci	struct nouveau_drm *drm = nouveau_drm(dev);
1378c2ecf20Sopenharmony_ci	struct nouveau_channel *chan = drm->channel;
1388c2ecf20Sopenharmony_ci	struct nvif_device *device = &drm->client.device;
1398c2ecf20Sopenharmony_ci	struct nvif_push *push = chan->chan.push;
1408c2ecf20Sopenharmony_ci	int surface_fmt, pattern_fmt, rect_fmt;
1418c2ecf20Sopenharmony_ci	int ret;
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	switch (info->var.bits_per_pixel) {
1448c2ecf20Sopenharmony_ci	case 8:
1458c2ecf20Sopenharmony_ci		surface_fmt = 1;
1468c2ecf20Sopenharmony_ci		pattern_fmt = 3;
1478c2ecf20Sopenharmony_ci		rect_fmt = 3;
1488c2ecf20Sopenharmony_ci		break;
1498c2ecf20Sopenharmony_ci	case 16:
1508c2ecf20Sopenharmony_ci		surface_fmt = 4;
1518c2ecf20Sopenharmony_ci		pattern_fmt = 1;
1528c2ecf20Sopenharmony_ci		rect_fmt = 1;
1538c2ecf20Sopenharmony_ci		break;
1548c2ecf20Sopenharmony_ci	case 32:
1558c2ecf20Sopenharmony_ci		switch (info->var.transp.length) {
1568c2ecf20Sopenharmony_ci		case 0: /* depth 24 */
1578c2ecf20Sopenharmony_ci		case 8: /* depth 32 */
1588c2ecf20Sopenharmony_ci			break;
1598c2ecf20Sopenharmony_ci		default:
1608c2ecf20Sopenharmony_ci			return -EINVAL;
1618c2ecf20Sopenharmony_ci		}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci		surface_fmt = 6;
1648c2ecf20Sopenharmony_ci		pattern_fmt = 3;
1658c2ecf20Sopenharmony_ci		rect_fmt = 3;
1668c2ecf20Sopenharmony_ci		break;
1678c2ecf20Sopenharmony_ci	default:
1688c2ecf20Sopenharmony_ci		return -EINVAL;
1698c2ecf20Sopenharmony_ci	}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	ret = nvif_object_ctor(&chan->user, "fbconCtxSurf2d", 0x0062,
1728c2ecf20Sopenharmony_ci			       device->info.family >= NV_DEVICE_INFO_V0_CELSIUS ?
1738c2ecf20Sopenharmony_ci			       0x0062 : 0x0042, NULL, 0, &nfbdev->surf2d);
1748c2ecf20Sopenharmony_ci	if (ret)
1758c2ecf20Sopenharmony_ci		return ret;
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	ret = nvif_object_ctor(&chan->user, "fbconCtxClip", 0x0019, 0x0019,
1788c2ecf20Sopenharmony_ci			       NULL, 0, &nfbdev->clip);
1798c2ecf20Sopenharmony_ci	if (ret)
1808c2ecf20Sopenharmony_ci		return ret;
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	ret = nvif_object_ctor(&chan->user, "fbconCtxRop", 0x0043, 0x0043,
1838c2ecf20Sopenharmony_ci			       NULL, 0, &nfbdev->rop);
1848c2ecf20Sopenharmony_ci	if (ret)
1858c2ecf20Sopenharmony_ci		return ret;
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	ret = nvif_object_ctor(&chan->user, "fbconCtxPatt", 0x0044, 0x0044,
1888c2ecf20Sopenharmony_ci			       NULL, 0, &nfbdev->patt);
1898c2ecf20Sopenharmony_ci	if (ret)
1908c2ecf20Sopenharmony_ci		return ret;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	ret = nvif_object_ctor(&chan->user, "fbconGdiRectText", 0x004a, 0x004a,
1938c2ecf20Sopenharmony_ci			       NULL, 0, &nfbdev->gdi);
1948c2ecf20Sopenharmony_ci	if (ret)
1958c2ecf20Sopenharmony_ci		return ret;
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	ret = nvif_object_ctor(&chan->user, "fbconImageBlit", 0x005f,
1988c2ecf20Sopenharmony_ci			       device->info.chipset >= 0x11 ? 0x009f : 0x005f,
1998c2ecf20Sopenharmony_ci			       NULL, 0, &nfbdev->blit);
2008c2ecf20Sopenharmony_ci	if (ret)
2018c2ecf20Sopenharmony_ci		return ret;
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	if (PUSH_WAIT(push, 49 + (device->info.chipset >= 0x11 ? 4 : 0))) {
2048c2ecf20Sopenharmony_ci		nouveau_fbcon_gpu_lockup(info);
2058c2ecf20Sopenharmony_ci		return 0;
2068c2ecf20Sopenharmony_ci	}
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	PUSH_NVSQ(push, NV042, 0x0000, nfbdev->surf2d.handle);
2098c2ecf20Sopenharmony_ci	PUSH_NVSQ(push, NV042, 0x0184, chan->vram.handle,
2108c2ecf20Sopenharmony_ci			       0x0188, chan->vram.handle);
2118c2ecf20Sopenharmony_ci	PUSH_NVSQ(push, NV042, 0x0300, surface_fmt,
2128c2ecf20Sopenharmony_ci			       0x0304, info->fix.line_length | (info->fix.line_length << 16),
2138c2ecf20Sopenharmony_ci			       0x0308, info->fix.smem_start - dev->mode_config.fb_base,
2148c2ecf20Sopenharmony_ci			       0x030c, info->fix.smem_start - dev->mode_config.fb_base);
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	PUSH_NVSQ(push, NV043, 0x0000, nfbdev->rop.handle);
2178c2ecf20Sopenharmony_ci	PUSH_NVSQ(push, NV043, 0x0300, 0x55);
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	PUSH_NVSQ(push, NV044, 0x0000, nfbdev->patt.handle);
2208c2ecf20Sopenharmony_ci	PUSH_NVSQ(push, NV044, 0x0300, pattern_fmt,
2218c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN
2228c2ecf20Sopenharmony_ci			       0x0304, 2,
2238c2ecf20Sopenharmony_ci#else
2248c2ecf20Sopenharmony_ci			       0x0304, 1,
2258c2ecf20Sopenharmony_ci#endif
2268c2ecf20Sopenharmony_ci			       0x0308, 0,
2278c2ecf20Sopenharmony_ci			       0x030c, 1,
2288c2ecf20Sopenharmony_ci			       0x0310, ~0,
2298c2ecf20Sopenharmony_ci			       0x0314, ~0,
2308c2ecf20Sopenharmony_ci			       0x0318, ~0,
2318c2ecf20Sopenharmony_ci			       0x031c, ~0);
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	PUSH_NVSQ(push, NV019, 0x0000, nfbdev->clip.handle);
2348c2ecf20Sopenharmony_ci	PUSH_NVSQ(push, NV019, 0x0300, 0,
2358c2ecf20Sopenharmony_ci			       0x0304, (info->var.yres_virtual << 16) | info->var.xres_virtual);
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	PUSH_NVSQ(push, NV05F, 0x0000, nfbdev->blit.handle);
2388c2ecf20Sopenharmony_ci	PUSH_NVSQ(push, NV05F, 0x019c, nfbdev->surf2d.handle);
2398c2ecf20Sopenharmony_ci	PUSH_NVSQ(push, NV05F, 0x02fc, 3);
2408c2ecf20Sopenharmony_ci	if (nfbdev->blit.oclass == 0x009f) {
2418c2ecf20Sopenharmony_ci		PUSH_NVSQ(push, NV09F, 0x0120, 0,
2428c2ecf20Sopenharmony_ci				       0x0124, 1,
2438c2ecf20Sopenharmony_ci				       0x0128, 2);
2448c2ecf20Sopenharmony_ci	}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	PUSH_NVSQ(push, NV04A, 0x0000, nfbdev->gdi.handle);
2478c2ecf20Sopenharmony_ci	PUSH_NVSQ(push, NV04A, 0x0198, nfbdev->surf2d.handle);
2488c2ecf20Sopenharmony_ci	PUSH_NVSQ(push, NV04A, 0x0188, nfbdev->patt.handle,
2498c2ecf20Sopenharmony_ci			       0x018c, nfbdev->rop.handle);
2508c2ecf20Sopenharmony_ci	PUSH_NVSQ(push, NV04A, 0x0304, 1);
2518c2ecf20Sopenharmony_ci	PUSH_NVSQ(push, NV04A, 0x0300, rect_fmt);
2528c2ecf20Sopenharmony_ci	PUSH_NVSQ(push, NV04A, 0x02fc, 3);
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	PUSH_KICK(push);
2558c2ecf20Sopenharmony_ci	return 0;
2568c2ecf20Sopenharmony_ci}
2578c2ecf20Sopenharmony_ci
258