• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6.36/drivers/gpu/drm/nouveau/
1#include "drmP.h"
2#include "nouveau_drv.h"
3#include "nouveau_dma.h"
4#include "nouveau_fbcon.h"
5
6void
7nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
8{
9	struct nouveau_fbdev *nfbdev = info->par;
10	struct drm_device *dev = nfbdev->dev;
11	struct drm_nouveau_private *dev_priv = dev->dev_private;
12	struct nouveau_channel *chan = dev_priv->channel;
13
14	if (info->state != FBINFO_STATE_RUNNING)
15		return;
16
17	if (!(info->flags & FBINFO_HWACCEL_DISABLED) &&
18	     RING_SPACE(chan, rect->rop == ROP_COPY ? 7 : 11)) {
19		nouveau_fbcon_gpu_lockup(info);
20	}
21
22	if (info->flags & FBINFO_HWACCEL_DISABLED) {
23		cfb_fillrect(info, rect);
24		return;
25	}
26
27	if (rect->rop != ROP_COPY) {
28		BEGIN_RING(chan, NvSub2D, 0x02ac, 1);
29		OUT_RING(chan, 1);
30	}
31	BEGIN_RING(chan, NvSub2D, 0x0588, 1);
32	if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
33	    info->fix.visual == FB_VISUAL_DIRECTCOLOR)
34		OUT_RING(chan, ((uint32_t *)info->pseudo_palette)[rect->color]);
35	else
36		OUT_RING(chan, rect->color);
37	BEGIN_RING(chan, NvSub2D, 0x0600, 4);
38	OUT_RING(chan, rect->dx);
39	OUT_RING(chan, rect->dy);
40	OUT_RING(chan, rect->dx + rect->width);
41	OUT_RING(chan, rect->dy + rect->height);
42	if (rect->rop != ROP_COPY) {
43		BEGIN_RING(chan, NvSub2D, 0x02ac, 1);
44		OUT_RING(chan, 3);
45	}
46	FIRE_RING(chan);
47}
48
49void
50nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region)
51{
52	struct nouveau_fbdev *nfbdev = info->par;
53	struct drm_device *dev = nfbdev->dev;
54	struct drm_nouveau_private *dev_priv = dev->dev_private;
55	struct nouveau_channel *chan = dev_priv->channel;
56
57	if (info->state != FBINFO_STATE_RUNNING)
58		return;
59
60	if (!(info->flags & FBINFO_HWACCEL_DISABLED) && RING_SPACE(chan, 12)) {
61		nouveau_fbcon_gpu_lockup(info);
62	}
63
64	if (info->flags & FBINFO_HWACCEL_DISABLED) {
65		cfb_copyarea(info, region);
66		return;
67	}
68
69	BEGIN_RING(chan, NvSub2D, 0x0110, 1);
70	OUT_RING(chan, 0);
71	BEGIN_RING(chan, NvSub2D, 0x08b0, 4);
72	OUT_RING(chan, region->dx);
73	OUT_RING(chan, region->dy);
74	OUT_RING(chan, region->width);
75	OUT_RING(chan, region->height);
76	BEGIN_RING(chan, NvSub2D, 0x08d0, 4);
77	OUT_RING(chan, 0);
78	OUT_RING(chan, region->sx);
79	OUT_RING(chan, 0);
80	OUT_RING(chan, region->sy);
81	FIRE_RING(chan);
82}
83
84void
85nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
86{
87	struct nouveau_fbdev *nfbdev = info->par;
88	struct drm_device *dev = nfbdev->dev;
89	struct drm_nouveau_private *dev_priv = dev->dev_private;
90	struct nouveau_channel *chan = dev_priv->channel;
91	uint32_t width, dwords, *data = (uint32_t *)image->data;
92	uint32_t mask = ~(~0 >> (32 - info->var.bits_per_pixel));
93	uint32_t *palette = info->pseudo_palette;
94
95	if (info->state != FBINFO_STATE_RUNNING)
96		return;
97
98	if (image->depth != 1) {
99		cfb_imageblit(info, image);
100		return;
101	}
102
103	if (!(info->flags & FBINFO_HWACCEL_DISABLED) && RING_SPACE(chan, 11)) {
104		nouveau_fbcon_gpu_lockup(info);
105	}
106
107	if (info->flags & FBINFO_HWACCEL_DISABLED) {
108		cfb_imageblit(info, image);
109		return;
110	}
111
112	width = ALIGN(image->width, 32);
113	dwords = (width * image->height) >> 5;
114
115	BEGIN_RING(chan, NvSub2D, 0x0814, 2);
116	if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
117	    info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
118		OUT_RING(chan, palette[image->bg_color] | mask);
119		OUT_RING(chan, palette[image->fg_color] | mask);
120	} else {
121		OUT_RING(chan, image->bg_color);
122		OUT_RING(chan, image->fg_color);
123	}
124	BEGIN_RING(chan, NvSub2D, 0x0838, 2);
125	OUT_RING(chan, image->width);
126	OUT_RING(chan, image->height);
127	BEGIN_RING(chan, NvSub2D, 0x0850, 4);
128	OUT_RING(chan, 0);
129	OUT_RING(chan, image->dx);
130	OUT_RING(chan, 0);
131	OUT_RING(chan, image->dy);
132
133	while (dwords) {
134		int push = dwords > 2047 ? 2047 : dwords;
135
136		if (RING_SPACE(chan, push + 1)) {
137			nouveau_fbcon_gpu_lockup(info);
138			cfb_imageblit(info, image);
139			return;
140		}
141
142		dwords -= push;
143
144		BEGIN_RING(chan, NvSub2D, 0x40000860, push);
145		OUT_RINGp(chan, data, push);
146		data += push;
147	}
148
149	FIRE_RING(chan);
150}
151
152int
153nv50_fbcon_accel_init(struct fb_info *info)
154{
155	struct nouveau_fbdev *nfbdev = info->par;
156	struct drm_device *dev = nfbdev->dev;
157	struct drm_nouveau_private *dev_priv = dev->dev_private;
158	struct nouveau_channel *chan = dev_priv->channel;
159	struct nouveau_gpuobj *eng2d = NULL;
160	uint64_t fb;
161	int ret, format;
162
163	fb = info->fix.smem_start - dev_priv->fb_phys + dev_priv->vm_vram_base;
164
165	switch (info->var.bits_per_pixel) {
166	case 8:
167		format = 0xf3;
168		break;
169	case 15:
170		format = 0xf8;
171		break;
172	case 16:
173		format = 0xe8;
174		break;
175	case 32:
176		switch (info->var.transp.length) {
177		case 0: /* depth 24 */
178		case 8: /* depth 32, just use 24.. */
179			format = 0xe6;
180			break;
181		case 2: /* depth 30 */
182			format = 0xd1;
183			break;
184		default:
185			return -EINVAL;
186		}
187		break;
188	default:
189		return -EINVAL;
190	}
191
192	ret = nouveau_gpuobj_gr_new(dev_priv->channel, 0x502d, &eng2d);
193	if (ret)
194		return ret;
195
196	ret = nouveau_gpuobj_ref_add(dev, dev_priv->channel, Nv2D, eng2d, NULL);
197	if (ret)
198		return ret;
199
200	ret = RING_SPACE(chan, 59);
201	if (ret) {
202		nouveau_fbcon_gpu_lockup(info);
203		return ret;
204	}
205
206	BEGIN_RING(chan, NvSub2D, 0x0000, 1);
207	OUT_RING(chan, Nv2D);
208	BEGIN_RING(chan, NvSub2D, 0x0180, 4);
209	OUT_RING(chan, NvNotify0);
210	OUT_RING(chan, chan->vram_handle);
211	OUT_RING(chan, chan->vram_handle);
212	OUT_RING(chan, chan->vram_handle);
213	BEGIN_RING(chan, NvSub2D, 0x0290, 1);
214	OUT_RING(chan, 0);
215	BEGIN_RING(chan, NvSub2D, 0x0888, 1);
216	OUT_RING(chan, 1);
217	BEGIN_RING(chan, NvSub2D, 0x02ac, 1);
218	OUT_RING(chan, 3);
219	BEGIN_RING(chan, NvSub2D, 0x02a0, 1);
220	OUT_RING(chan, 0x55);
221	BEGIN_RING(chan, NvSub2D, 0x08c0, 4);
222	OUT_RING(chan, 0);
223	OUT_RING(chan, 1);
224	OUT_RING(chan, 0);
225	OUT_RING(chan, 1);
226	BEGIN_RING(chan, NvSub2D, 0x0580, 2);
227	OUT_RING(chan, 4);
228	OUT_RING(chan, format);
229	BEGIN_RING(chan, NvSub2D, 0x02e8, 2);
230	OUT_RING(chan, 2);
231	OUT_RING(chan, 1);
232	BEGIN_RING(chan, NvSub2D, 0x0804, 1);
233	OUT_RING(chan, format);
234	BEGIN_RING(chan, NvSub2D, 0x0800, 1);
235	OUT_RING(chan, 1);
236	BEGIN_RING(chan, NvSub2D, 0x0808, 3);
237	OUT_RING(chan, 0);
238	OUT_RING(chan, 0);
239	OUT_RING(chan, 1);
240	BEGIN_RING(chan, NvSub2D, 0x081c, 1);
241	OUT_RING(chan, 1);
242	BEGIN_RING(chan, NvSub2D, 0x0840, 4);
243	OUT_RING(chan, 0);
244	OUT_RING(chan, 1);
245	OUT_RING(chan, 0);
246	OUT_RING(chan, 1);
247	BEGIN_RING(chan, NvSub2D, 0x0200, 2);
248	OUT_RING(chan, format);
249	OUT_RING(chan, 1);
250	BEGIN_RING(chan, NvSub2D, 0x0214, 5);
251	OUT_RING(chan, info->fix.line_length);
252	OUT_RING(chan, info->var.xres_virtual);
253	OUT_RING(chan, info->var.yres_virtual);
254	OUT_RING(chan, upper_32_bits(fb));
255	OUT_RING(chan, lower_32_bits(fb));
256	BEGIN_RING(chan, NvSub2D, 0x0230, 2);
257	OUT_RING(chan, format);
258	OUT_RING(chan, 1);
259	BEGIN_RING(chan, NvSub2D, 0x0244, 5);
260	OUT_RING(chan, info->fix.line_length);
261	OUT_RING(chan, info->var.xres_virtual);
262	OUT_RING(chan, info->var.yres_virtual);
263	OUT_RING(chan, upper_32_bits(fb));
264	OUT_RING(chan, lower_32_bits(fb));
265
266	return 0;
267}
268