nv04_fbcon.c 7.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
/*
 * Copyright 2009 Ben Skeggs
 * Copyright 2008 Stuart Bennett
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

25
#include "nouveau_drv.h"
26 27 28
#include "nouveau_dma.h"
#include "nouveau_fbcon.h"

29
int
30 31
nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region)
{
32
	struct nouveau_fbdev *nfbdev = info->par;
33
	struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev);
34
	struct nouveau_channel *chan = drm->channel;
35
	int ret;
36

37 38 39
	ret = RING_SPACE(chan, 4);
	if (ret)
		return ret;
40

41
	BEGIN_NV04(chan, NvSubImageBlit, 0x0300, 3);
42 43 44 45
	OUT_RING(chan, (region->sy << 16) | region->sx);
	OUT_RING(chan, (region->dy << 16) | region->dx);
	OUT_RING(chan, (region->height << 16) | region->width);
	FIRE_RING(chan);
46
	return 0;
47 48
}

49
int
50 51
nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
{
52
	struct nouveau_fbdev *nfbdev = info->par;
53
	struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev);
54
	struct nouveau_channel *chan = drm->channel;
55
	int ret;
56

57 58 59
	ret = RING_SPACE(chan, 7);
	if (ret)
		return ret;
60

61
	BEGIN_NV04(chan, NvSubGdiRect, 0x02fc, 1);
62
	OUT_RING(chan, (rect->rop != ROP_COPY) ? 1 : 3);
63
	BEGIN_NV04(chan, NvSubGdiRect, 0x03fc, 1);
64 65 66 67 68
	if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
	    info->fix.visual == FB_VISUAL_DIRECTCOLOR)
		OUT_RING(chan, ((uint32_t *)info->pseudo_palette)[rect->color]);
	else
		OUT_RING(chan, rect->color);
69
	BEGIN_NV04(chan, NvSubGdiRect, 0x0400, 2);
70 71 72
	OUT_RING(chan, (rect->dx << 16) | rect->dy);
	OUT_RING(chan, (rect->width << 16) | rect->height);
	FIRE_RING(chan);
73
	return 0;
74 75
}

76
int
77 78
nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
{
79
	struct nouveau_fbdev *nfbdev = info->par;
80
	struct nouveau_drm *drm = nouveau_drm(nfbdev->helper.dev);
81
	struct nouveau_channel *chan = drm->channel;
82 83 84 85
	uint32_t fg;
	uint32_t bg;
	uint32_t dsize;
	uint32_t *data = (uint32_t *)image->data;
86
	int ret;
87

88 89
	if (image->depth != 1)
		return -ENODEV;
90

91 92 93
	ret = RING_SPACE(chan, 8);
	if (ret)
		return ret;
94 95 96 97 98 99 100 101 102 103

	if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
	    info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
		fg = ((uint32_t *) info->pseudo_palette)[image->fg_color];
		bg = ((uint32_t *) info->pseudo_palette)[image->bg_color];
	} else {
		fg = image->fg_color;
		bg = image->bg_color;
	}

104
	BEGIN_NV04(chan, NvSubGdiRect, 0x0be4, 7);
105 106 107 108 109
	OUT_RING(chan, (image->dy << 16) | (image->dx & 0xffff));
	OUT_RING(chan, ((image->dy + image->height) << 16) |
			 ((image->dx + image->width) & 0xffff));
	OUT_RING(chan, bg);
	OUT_RING(chan, fg);
110
	OUT_RING(chan, (image->height << 16) | ALIGN(image->width, 8));
111
	OUT_RING(chan, (image->height << 16) | image->width);
112 113
	OUT_RING(chan, (image->dy << 16) | (image->dx & 0xffff));

114
	dsize = ALIGN(ALIGN(image->width, 8) * image->height, 32) >> 5;
115 116 117
	while (dsize) {
		int iter_len = dsize > 128 ? 128 : dsize;

118 119 120
		ret = RING_SPACE(chan, iter_len + 1);
		if (ret)
			return ret;
121

122
		BEGIN_NV04(chan, NvSubGdiRect, 0x0c00, iter_len);
123 124 125 126 127 128
		OUT_RINGp(chan, data, iter_len);
		data += iter_len;
		dsize -= iter_len;
	}

	FIRE_RING(chan);
129
	return 0;
130 131 132 133 134
}

int
nv04_fbcon_accel_init(struct fb_info *info)
{
135
	struct nouveau_fbdev *nfbdev = info->par;
136
	struct drm_device *dev = nfbdev->helper.dev;
137
	struct nouveau_drm *drm = nouveau_drm(dev);
138
	struct nouveau_channel *chan = drm->channel;
139
	struct nvif_device *device = &drm->device;
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
	int surface_fmt, pattern_fmt, rect_fmt;
	int ret;

	switch (info->var.bits_per_pixel) {
	case 8:
		surface_fmt = 1;
		pattern_fmt = 3;
		rect_fmt = 3;
		break;
	case 16:
		surface_fmt = 4;
		pattern_fmt = 1;
		rect_fmt = 1;
		break;
	case 32:
		switch (info->var.transp.length) {
		case 0: /* depth 24 */
		case 8: /* depth 32 */
			break;
		default:
			return -EINVAL;
		}

		surface_fmt = 6;
		pattern_fmt = 3;
		rect_fmt = 3;
		break;
	default:
		return -EINVAL;
	}

171
	ret = nvif_object_init(&chan->user, 0x0062,
172 173
			       device->info.family >= NV_DEVICE_INFO_V0_CELSIUS ?
			       0x0062 : 0x0042, NULL, 0, &nfbdev->surf2d);
174 175 176
	if (ret)
		return ret;

177
	ret = nvif_object_init(&chan->user, 0x0019, 0x0019, NULL, 0,
178
			       &nfbdev->clip);
179 180 181
	if (ret)
		return ret;

182
	ret = nvif_object_init(&chan->user, 0x0043, 0x0043, NULL, 0,
183
			       &nfbdev->rop);
184 185 186
	if (ret)
		return ret;

187
	ret = nvif_object_init(&chan->user, 0x0044, 0x0044, NULL, 0,
188
			       &nfbdev->patt);
189 190 191
	if (ret)
		return ret;

192
	ret = nvif_object_init(&chan->user, 0x004a, 0x004a, NULL, 0,
193
			       &nfbdev->gdi);
194 195 196
	if (ret)
		return ret;

197
	ret = nvif_object_init(&chan->user, 0x005f,
198 199
			       device->info.chipset >= 0x11 ? 0x009f : 0x005f,
			       NULL, 0, &nfbdev->blit);
200 201 202
	if (ret)
		return ret;

203
	if (RING_SPACE(chan, 49 + (device->info.chipset >= 0x11 ? 4 : 0))) {
204
		nouveau_fbcon_gpu_lockup(info);
205 206 207
		return 0;
	}

208
	BEGIN_NV04(chan, NvSubCtxSurf2D, 0x0000, 1);
209
	OUT_RING(chan, nfbdev->surf2d.handle);
210
	BEGIN_NV04(chan, NvSubCtxSurf2D, 0x0184, 2);
211 212
	OUT_RING(chan, chan->vram.handle);
	OUT_RING(chan, chan->vram.handle);
213
	BEGIN_NV04(chan, NvSubCtxSurf2D, 0x0300, 4);
214 215 216 217 218
	OUT_RING(chan, surface_fmt);
	OUT_RING(chan, info->fix.line_length | (info->fix.line_length << 16));
	OUT_RING(chan, info->fix.smem_start - dev->mode_config.fb_base);
	OUT_RING(chan, info->fix.smem_start - dev->mode_config.fb_base);

219
	BEGIN_NV04(chan, NvSubCtxSurf2D, 0x0000, 1);
220
	OUT_RING(chan, nfbdev->rop.handle);
221
	BEGIN_NV04(chan, NvSubCtxSurf2D, 0x0300, 1);
222 223
	OUT_RING(chan, 0x55);

224
	BEGIN_NV04(chan, NvSubCtxSurf2D, 0x0000, 1);
225
	OUT_RING(chan, nfbdev->patt.handle);
226
	BEGIN_NV04(chan, NvSubCtxSurf2D, 0x0300, 8);
227 228 229 230 231 232 233 234 235 236 237 238 239
	OUT_RING(chan, pattern_fmt);
#ifdef __BIG_ENDIAN
	OUT_RING(chan, 2);
#else
	OUT_RING(chan, 1);
#endif
	OUT_RING(chan, 0);
	OUT_RING(chan, 1);
	OUT_RING(chan, ~0);
	OUT_RING(chan, ~0);
	OUT_RING(chan, ~0);
	OUT_RING(chan, ~0);

240
	BEGIN_NV04(chan, NvSubCtxSurf2D, 0x0000, 1);
241
	OUT_RING(chan, nfbdev->clip.handle);
242
	BEGIN_NV04(chan, NvSubCtxSurf2D, 0x0300, 2);
243 244 245
	OUT_RING(chan, 0);
	OUT_RING(chan, (info->var.yres_virtual << 16) | info->var.xres_virtual);

246
	BEGIN_NV04(chan, NvSubImageBlit, 0x0000, 1);
247
	OUT_RING(chan, nfbdev->blit.handle);
248
	BEGIN_NV04(chan, NvSubImageBlit, 0x019c, 1);
249
	OUT_RING(chan, nfbdev->surf2d.handle);
250
	BEGIN_NV04(chan, NvSubImageBlit, 0x02fc, 1);
251
	OUT_RING(chan, 3);
252
	if (device->info.chipset >= 0x11 /*XXX: oclass == 0x009f*/) {
253 254 255 256 257
		BEGIN_NV04(chan, NvSubImageBlit, 0x0120, 3);
		OUT_RING(chan, 0);
		OUT_RING(chan, 1);
		OUT_RING(chan, 2);
	}
258

259
	BEGIN_NV04(chan, NvSubGdiRect, 0x0000, 1);
260
	OUT_RING(chan, nfbdev->gdi.handle);
261
	BEGIN_NV04(chan, NvSubGdiRect, 0x0198, 1);
262
	OUT_RING(chan, nfbdev->surf2d.handle);
263
	BEGIN_NV04(chan, NvSubGdiRect, 0x0188, 2);
264 265
	OUT_RING(chan, nfbdev->patt.handle);
	OUT_RING(chan, nfbdev->rop.handle);
266
	BEGIN_NV04(chan, NvSubGdiRect, 0x0304, 1);
267
	OUT_RING(chan, 1);
268
	BEGIN_NV04(chan, NvSubGdiRect, 0x0300, 1);
269
	OUT_RING(chan, rect_fmt);
270
	BEGIN_NV04(chan, NvSubGdiRect, 0x02fc, 1);
271 272 273 274 275 276 277
	OUT_RING(chan, 3);

	FIRE_RING(chan);

	return 0;
}