blob: 6edf9dca35cad346e810239f3b048197ab335de1 [file] [log] [blame]
Ben Skeggs6ee73862009-12-11 19:24:15 +10001#include "drmP.h"
2#include "nouveau_drv.h"
3#include "nouveau_dma.h"
Ben Skeggsa8eaebc2010-09-01 15:24:31 +10004#include "nouveau_ramht.h"
Ben Skeggs6ee73862009-12-11 19:24:15 +10005#include "nouveau_fbcon.h"
6
Ben Skeggsceed5f32010-10-05 16:41:29 +10007int
Ben Skeggs6ee73862009-12-11 19:24:15 +10008nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
9{
Dave Airlie8be48d92010-03-30 05:34:14 +000010 struct nouveau_fbdev *nfbdev = info->par;
11 struct drm_device *dev = nfbdev->dev;
Ben Skeggs6ee73862009-12-11 19:24:15 +100012 struct drm_nouveau_private *dev_priv = dev->dev_private;
13 struct nouveau_channel *chan = dev_priv->channel;
Ben Skeggsceed5f32010-10-05 16:41:29 +100014 int ret;
Ben Skeggs6ee73862009-12-11 19:24:15 +100015
Ben Skeggsceed5f32010-10-05 16:41:29 +100016 ret = RING_SPACE(chan, rect->rop == ROP_COPY ? 7 : 11);
17 if (ret)
18 return ret;
Ben Skeggs6ee73862009-12-11 19:24:15 +100019
20 if (rect->rop != ROP_COPY) {
21 BEGIN_RING(chan, NvSub2D, 0x02ac, 1);
22 OUT_RING(chan, 1);
23 }
24 BEGIN_RING(chan, NvSub2D, 0x0588, 1);
Ben Skeggsbf5302b2010-01-04 09:10:55 +100025 if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
26 info->fix.visual == FB_VISUAL_DIRECTCOLOR)
27 OUT_RING(chan, ((uint32_t *)info->pseudo_palette)[rect->color]);
28 else
29 OUT_RING(chan, rect->color);
Ben Skeggs6ee73862009-12-11 19:24:15 +100030 BEGIN_RING(chan, NvSub2D, 0x0600, 4);
31 OUT_RING(chan, rect->dx);
32 OUT_RING(chan, rect->dy);
33 OUT_RING(chan, rect->dx + rect->width);
34 OUT_RING(chan, rect->dy + rect->height);
35 if (rect->rop != ROP_COPY) {
36 BEGIN_RING(chan, NvSub2D, 0x02ac, 1);
37 OUT_RING(chan, 3);
38 }
39 FIRE_RING(chan);
Ben Skeggsceed5f32010-10-05 16:41:29 +100040 return 0;
Ben Skeggs6ee73862009-12-11 19:24:15 +100041}
42
Ben Skeggsceed5f32010-10-05 16:41:29 +100043int
Ben Skeggs6ee73862009-12-11 19:24:15 +100044nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region)
45{
Dave Airlie8be48d92010-03-30 05:34:14 +000046 struct nouveau_fbdev *nfbdev = info->par;
47 struct drm_device *dev = nfbdev->dev;
Ben Skeggs6ee73862009-12-11 19:24:15 +100048 struct drm_nouveau_private *dev_priv = dev->dev_private;
49 struct nouveau_channel *chan = dev_priv->channel;
Ben Skeggsceed5f32010-10-05 16:41:29 +100050 int ret;
Ben Skeggs6ee73862009-12-11 19:24:15 +100051
Ben Skeggsceed5f32010-10-05 16:41:29 +100052 ret = RING_SPACE(chan, 12);
53 if (ret)
54 return ret;
Ben Skeggs6ee73862009-12-11 19:24:15 +100055
56 BEGIN_RING(chan, NvSub2D, 0x0110, 1);
57 OUT_RING(chan, 0);
58 BEGIN_RING(chan, NvSub2D, 0x08b0, 4);
59 OUT_RING(chan, region->dx);
60 OUT_RING(chan, region->dy);
61 OUT_RING(chan, region->width);
62 OUT_RING(chan, region->height);
63 BEGIN_RING(chan, NvSub2D, 0x08d0, 4);
64 OUT_RING(chan, 0);
65 OUT_RING(chan, region->sx);
66 OUT_RING(chan, 0);
67 OUT_RING(chan, region->sy);
68 FIRE_RING(chan);
Ben Skeggsceed5f32010-10-05 16:41:29 +100069 return 0;
Ben Skeggs6ee73862009-12-11 19:24:15 +100070}
71
Ben Skeggsceed5f32010-10-05 16:41:29 +100072int
Ben Skeggs6ee73862009-12-11 19:24:15 +100073nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
74{
Dave Airlie8be48d92010-03-30 05:34:14 +000075 struct nouveau_fbdev *nfbdev = info->par;
76 struct drm_device *dev = nfbdev->dev;
Ben Skeggs6ee73862009-12-11 19:24:15 +100077 struct drm_nouveau_private *dev_priv = dev->dev_private;
78 struct nouveau_channel *chan = dev_priv->channel;
79 uint32_t width, dwords, *data = (uint32_t *)image->data;
80 uint32_t mask = ~(~0 >> (32 - info->var.bits_per_pixel));
81 uint32_t *palette = info->pseudo_palette;
Ben Skeggsceed5f32010-10-05 16:41:29 +100082 int ret;
Ben Skeggs6ee73862009-12-11 19:24:15 +100083
Ben Skeggsceed5f32010-10-05 16:41:29 +100084 if (image->depth != 1)
85 return -ENODEV;
Ben Skeggs6ee73862009-12-11 19:24:15 +100086
Ben Skeggsceed5f32010-10-05 16:41:29 +100087 ret = RING_SPACE(chan, 11);
88 if (ret)
89 return ret;
Ben Skeggs6ee73862009-12-11 19:24:15 +100090
Matt Turner3bfc7d22010-02-24 23:27:10 -050091 width = ALIGN(image->width, 32);
Ben Skeggs6ee73862009-12-11 19:24:15 +100092 dwords = (width * image->height) >> 5;
93
94 BEGIN_RING(chan, NvSub2D, 0x0814, 2);
95 if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
96 info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
97 OUT_RING(chan, palette[image->bg_color] | mask);
98 OUT_RING(chan, palette[image->fg_color] | mask);
99 } else {
100 OUT_RING(chan, image->bg_color);
101 OUT_RING(chan, image->fg_color);
102 }
103 BEGIN_RING(chan, NvSub2D, 0x0838, 2);
104 OUT_RING(chan, image->width);
105 OUT_RING(chan, image->height);
106 BEGIN_RING(chan, NvSub2D, 0x0850, 4);
107 OUT_RING(chan, 0);
108 OUT_RING(chan, image->dx);
109 OUT_RING(chan, 0);
110 OUT_RING(chan, image->dy);
111
112 while (dwords) {
113 int push = dwords > 2047 ? 2047 : dwords;
114
Ben Skeggsceed5f32010-10-05 16:41:29 +1000115 ret = RING_SPACE(chan, push + 1);
116 if (ret)
117 return ret;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000118
119 dwords -= push;
120
121 BEGIN_RING(chan, NvSub2D, 0x40000860, push);
122 OUT_RINGp(chan, data, push);
123 data += push;
124 }
125
126 FIRE_RING(chan);
Ben Skeggsceed5f32010-10-05 16:41:29 +1000127 return 0;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000128}
129
130int
131nv50_fbcon_accel_init(struct fb_info *info)
132{
Dave Airlie8be48d92010-03-30 05:34:14 +0000133 struct nouveau_fbdev *nfbdev = info->par;
134 struct drm_device *dev = nfbdev->dev;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000135 struct drm_nouveau_private *dev_priv = dev->dev_private;
136 struct nouveau_channel *chan = dev_priv->channel;
137 struct nouveau_gpuobj *eng2d = NULL;
Ben Skeggs0c324972010-03-16 13:20:58 +1000138 uint64_t fb;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000139 int ret, format;
140
Ben Skeggs0c324972010-03-16 13:20:58 +1000141 fb = info->fix.smem_start - dev_priv->fb_phys + dev_priv->vm_vram_base;
142
Ben Skeggs6ee73862009-12-11 19:24:15 +1000143 switch (info->var.bits_per_pixel) {
144 case 8:
145 format = 0xf3;
146 break;
147 case 15:
148 format = 0xf8;
149 break;
150 case 16:
151 format = 0xe8;
152 break;
153 case 32:
154 switch (info->var.transp.length) {
155 case 0: /* depth 24 */
156 case 8: /* depth 32, just use 24.. */
157 format = 0xe6;
158 break;
159 case 2: /* depth 30 */
160 format = 0xd1;
161 break;
162 default:
163 return -EINVAL;
164 }
165 break;
166 default:
167 return -EINVAL;
168 }
169
170 ret = nouveau_gpuobj_gr_new(dev_priv->channel, 0x502d, &eng2d);
171 if (ret)
172 return ret;
173
Ben Skeggsa8eaebc2010-09-01 15:24:31 +1000174 ret = nouveau_ramht_insert(dev_priv->channel, Nv2D, eng2d);
175 nouveau_gpuobj_ref(NULL, &eng2d);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000176 if (ret)
177 return ret;
178
179 ret = RING_SPACE(chan, 59);
180 if (ret) {
Marcin Slusarz846975a2010-01-04 19:25:09 +0100181 nouveau_fbcon_gpu_lockup(info);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000182 return ret;
183 }
184
185 BEGIN_RING(chan, NvSub2D, 0x0000, 1);
186 OUT_RING(chan, Nv2D);
187 BEGIN_RING(chan, NvSub2D, 0x0180, 4);
188 OUT_RING(chan, NvNotify0);
189 OUT_RING(chan, chan->vram_handle);
190 OUT_RING(chan, chan->vram_handle);
191 OUT_RING(chan, chan->vram_handle);
192 BEGIN_RING(chan, NvSub2D, 0x0290, 1);
193 OUT_RING(chan, 0);
194 BEGIN_RING(chan, NvSub2D, 0x0888, 1);
195 OUT_RING(chan, 1);
196 BEGIN_RING(chan, NvSub2D, 0x02ac, 1);
197 OUT_RING(chan, 3);
198 BEGIN_RING(chan, NvSub2D, 0x02a0, 1);
199 OUT_RING(chan, 0x55);
200 BEGIN_RING(chan, NvSub2D, 0x08c0, 4);
201 OUT_RING(chan, 0);
202 OUT_RING(chan, 1);
203 OUT_RING(chan, 0);
204 OUT_RING(chan, 1);
205 BEGIN_RING(chan, NvSub2D, 0x0580, 2);
206 OUT_RING(chan, 4);
207 OUT_RING(chan, format);
208 BEGIN_RING(chan, NvSub2D, 0x02e8, 2);
209 OUT_RING(chan, 2);
210 OUT_RING(chan, 1);
211 BEGIN_RING(chan, NvSub2D, 0x0804, 1);
212 OUT_RING(chan, format);
213 BEGIN_RING(chan, NvSub2D, 0x0800, 1);
214 OUT_RING(chan, 1);
215 BEGIN_RING(chan, NvSub2D, 0x0808, 3);
216 OUT_RING(chan, 0);
217 OUT_RING(chan, 0);
Marcin Koƛcielnickic82b88d2010-02-27 18:13:35 +0000218 OUT_RING(chan, 1);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000219 BEGIN_RING(chan, NvSub2D, 0x081c, 1);
220 OUT_RING(chan, 1);
221 BEGIN_RING(chan, NvSub2D, 0x0840, 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, 0x0200, 2);
227 OUT_RING(chan, format);
228 OUT_RING(chan, 1);
229 BEGIN_RING(chan, NvSub2D, 0x0214, 5);
230 OUT_RING(chan, info->fix.line_length);
231 OUT_RING(chan, info->var.xres_virtual);
232 OUT_RING(chan, info->var.yres_virtual);
Ben Skeggs0c324972010-03-16 13:20:58 +1000233 OUT_RING(chan, upper_32_bits(fb));
234 OUT_RING(chan, lower_32_bits(fb));
Ben Skeggs6ee73862009-12-11 19:24:15 +1000235 BEGIN_RING(chan, NvSub2D, 0x0230, 2);
236 OUT_RING(chan, format);
237 OUT_RING(chan, 1);
238 BEGIN_RING(chan, NvSub2D, 0x0244, 5);
239 OUT_RING(chan, info->fix.line_length);
240 OUT_RING(chan, info->var.xres_virtual);
241 OUT_RING(chan, info->var.yres_virtual);
Ben Skeggs0c324972010-03-16 13:20:58 +1000242 OUT_RING(chan, upper_32_bits(fb));
243 OUT_RING(chan, lower_32_bits(fb));
Ben Skeggs6ee73862009-12-11 19:24:15 +1000244
Ben Skeggs6ee73862009-12-11 19:24:15 +1000245 return 0;
246}
247