blob: 6d38cb1488ae986dcf01aacb213b5d12e67c9544 [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"
Ben Skeggs4c1361422010-11-15 11:54:21 +10006#include "nouveau_mm.h"
Ben Skeggs6ee73862009-12-11 19:24:15 +10007
Ben Skeggsceed5f32010-10-05 16:41:29 +10008int
Ben Skeggs6ee73862009-12-11 19:24:15 +10009nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
10{
Dave Airlie8be48d92010-03-30 05:34:14 +000011 struct nouveau_fbdev *nfbdev = info->par;
12 struct drm_device *dev = nfbdev->dev;
Ben Skeggs6ee73862009-12-11 19:24:15 +100013 struct drm_nouveau_private *dev_priv = dev->dev_private;
14 struct nouveau_channel *chan = dev_priv->channel;
Ben Skeggsceed5f32010-10-05 16:41:29 +100015 int ret;
Ben Skeggs6ee73862009-12-11 19:24:15 +100016
Ben Skeggsceed5f32010-10-05 16:41:29 +100017 ret = RING_SPACE(chan, rect->rop == ROP_COPY ? 7 : 11);
18 if (ret)
19 return ret;
Ben Skeggs6ee73862009-12-11 19:24:15 +100020
21 if (rect->rop != ROP_COPY) {
22 BEGIN_RING(chan, NvSub2D, 0x02ac, 1);
23 OUT_RING(chan, 1);
24 }
25 BEGIN_RING(chan, NvSub2D, 0x0588, 1);
Ben Skeggsbf5302b2010-01-04 09:10:55 +100026 if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
27 info->fix.visual == FB_VISUAL_DIRECTCOLOR)
28 OUT_RING(chan, ((uint32_t *)info->pseudo_palette)[rect->color]);
29 else
30 OUT_RING(chan, rect->color);
Ben Skeggs6ee73862009-12-11 19:24:15 +100031 BEGIN_RING(chan, NvSub2D, 0x0600, 4);
32 OUT_RING(chan, rect->dx);
33 OUT_RING(chan, rect->dy);
34 OUT_RING(chan, rect->dx + rect->width);
35 OUT_RING(chan, rect->dy + rect->height);
36 if (rect->rop != ROP_COPY) {
37 BEGIN_RING(chan, NvSub2D, 0x02ac, 1);
38 OUT_RING(chan, 3);
39 }
40 FIRE_RING(chan);
Ben Skeggsceed5f32010-10-05 16:41:29 +100041 return 0;
Ben Skeggs6ee73862009-12-11 19:24:15 +100042}
43
Ben Skeggsceed5f32010-10-05 16:41:29 +100044int
Ben Skeggs6ee73862009-12-11 19:24:15 +100045nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region)
46{
Dave Airlie8be48d92010-03-30 05:34:14 +000047 struct nouveau_fbdev *nfbdev = info->par;
48 struct drm_device *dev = nfbdev->dev;
Ben Skeggs6ee73862009-12-11 19:24:15 +100049 struct drm_nouveau_private *dev_priv = dev->dev_private;
50 struct nouveau_channel *chan = dev_priv->channel;
Ben Skeggsceed5f32010-10-05 16:41:29 +100051 int ret;
Ben Skeggs6ee73862009-12-11 19:24:15 +100052
Ben Skeggsceed5f32010-10-05 16:41:29 +100053 ret = RING_SPACE(chan, 12);
54 if (ret)
55 return ret;
Ben Skeggs6ee73862009-12-11 19:24:15 +100056
57 BEGIN_RING(chan, NvSub2D, 0x0110, 1);
58 OUT_RING(chan, 0);
59 BEGIN_RING(chan, NvSub2D, 0x08b0, 4);
60 OUT_RING(chan, region->dx);
61 OUT_RING(chan, region->dy);
62 OUT_RING(chan, region->width);
63 OUT_RING(chan, region->height);
64 BEGIN_RING(chan, NvSub2D, 0x08d0, 4);
65 OUT_RING(chan, 0);
66 OUT_RING(chan, region->sx);
67 OUT_RING(chan, 0);
68 OUT_RING(chan, region->sy);
69 FIRE_RING(chan);
Ben Skeggsceed5f32010-10-05 16:41:29 +100070 return 0;
Ben Skeggs6ee73862009-12-11 19:24:15 +100071}
72
Ben Skeggsceed5f32010-10-05 16:41:29 +100073int
Ben Skeggs6ee73862009-12-11 19:24:15 +100074nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
75{
Dave Airlie8be48d92010-03-30 05:34:14 +000076 struct nouveau_fbdev *nfbdev = info->par;
77 struct drm_device *dev = nfbdev->dev;
Ben Skeggs6ee73862009-12-11 19:24:15 +100078 struct drm_nouveau_private *dev_priv = dev->dev_private;
79 struct nouveau_channel *chan = dev_priv->channel;
80 uint32_t width, dwords, *data = (uint32_t *)image->data;
81 uint32_t mask = ~(~0 >> (32 - info->var.bits_per_pixel));
82 uint32_t *palette = info->pseudo_palette;
Ben Skeggsceed5f32010-10-05 16:41:29 +100083 int ret;
Ben Skeggs6ee73862009-12-11 19:24:15 +100084
Ben Skeggsceed5f32010-10-05 16:41:29 +100085 if (image->depth != 1)
86 return -ENODEV;
Ben Skeggs6ee73862009-12-11 19:24:15 +100087
Ben Skeggsceed5f32010-10-05 16:41:29 +100088 ret = RING_SPACE(chan, 11);
89 if (ret)
90 return ret;
Ben Skeggs6ee73862009-12-11 19:24:15 +100091
Matt Turner3bfc7d22010-02-24 23:27:10 -050092 width = ALIGN(image->width, 32);
Ben Skeggs6ee73862009-12-11 19:24:15 +100093 dwords = (width * image->height) >> 5;
94
95 BEGIN_RING(chan, NvSub2D, 0x0814, 2);
96 if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
97 info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
98 OUT_RING(chan, palette[image->bg_color] | mask);
99 OUT_RING(chan, palette[image->fg_color] | mask);
100 } else {
101 OUT_RING(chan, image->bg_color);
102 OUT_RING(chan, image->fg_color);
103 }
104 BEGIN_RING(chan, NvSub2D, 0x0838, 2);
105 OUT_RING(chan, image->width);
106 OUT_RING(chan, image->height);
107 BEGIN_RING(chan, NvSub2D, 0x0850, 4);
108 OUT_RING(chan, 0);
109 OUT_RING(chan, image->dx);
110 OUT_RING(chan, 0);
111 OUT_RING(chan, image->dy);
112
113 while (dwords) {
114 int push = dwords > 2047 ? 2047 : dwords;
115
Ben Skeggsceed5f32010-10-05 16:41:29 +1000116 ret = RING_SPACE(chan, push + 1);
117 if (ret)
118 return ret;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000119
120 dwords -= push;
121
122 BEGIN_RING(chan, NvSub2D, 0x40000860, push);
123 OUT_RINGp(chan, data, push);
124 data += push;
125 }
126
127 FIRE_RING(chan);
Ben Skeggsceed5f32010-10-05 16:41:29 +1000128 return 0;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000129}
130
131int
132nv50_fbcon_accel_init(struct fb_info *info)
133{
Dave Airlie8be48d92010-03-30 05:34:14 +0000134 struct nouveau_fbdev *nfbdev = info->par;
135 struct drm_device *dev = nfbdev->dev;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000136 struct drm_nouveau_private *dev_priv = dev->dev_private;
137 struct nouveau_channel *chan = dev_priv->channel;
Ben Skeggs4c1361422010-11-15 11:54:21 +1000138 struct nouveau_bo *nvbo = nfbdev->nouveau_fb.nvbo;
Ben Skeggs6ee73862009-12-11 19:24:15 +1000139 int ret, format;
Ben Skeggs0c324972010-03-16 13:20:58 +1000140
Ben Skeggs6ee73862009-12-11 19:24:15 +1000141 switch (info->var.bits_per_pixel) {
142 case 8:
143 format = 0xf3;
144 break;
145 case 15:
146 format = 0xf8;
147 break;
148 case 16:
149 format = 0xe8;
150 break;
151 case 32:
152 switch (info->var.transp.length) {
153 case 0: /* depth 24 */
154 case 8: /* depth 32, just use 24.. */
155 format = 0xe6;
156 break;
157 case 2: /* depth 30 */
158 format = 0xd1;
159 break;
160 default:
161 return -EINVAL;
162 }
163 break;
164 default:
165 return -EINVAL;
166 }
167
Ben Skeggsceac3092010-11-23 10:10:24 +1000168 ret = nouveau_gpuobj_gr_new(dev_priv->channel, Nv2D, 0x502d);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000169 if (ret)
170 return ret;
171
172 ret = RING_SPACE(chan, 59);
173 if (ret) {
Marcin Slusarz846975a2010-01-04 19:25:09 +0100174 nouveau_fbcon_gpu_lockup(info);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000175 return ret;
176 }
177
178 BEGIN_RING(chan, NvSub2D, 0x0000, 1);
179 OUT_RING(chan, Nv2D);
180 BEGIN_RING(chan, NvSub2D, 0x0180, 4);
181 OUT_RING(chan, NvNotify0);
182 OUT_RING(chan, chan->vram_handle);
183 OUT_RING(chan, chan->vram_handle);
184 OUT_RING(chan, chan->vram_handle);
185 BEGIN_RING(chan, NvSub2D, 0x0290, 1);
186 OUT_RING(chan, 0);
187 BEGIN_RING(chan, NvSub2D, 0x0888, 1);
188 OUT_RING(chan, 1);
189 BEGIN_RING(chan, NvSub2D, 0x02ac, 1);
190 OUT_RING(chan, 3);
191 BEGIN_RING(chan, NvSub2D, 0x02a0, 1);
192 OUT_RING(chan, 0x55);
193 BEGIN_RING(chan, NvSub2D, 0x08c0, 4);
194 OUT_RING(chan, 0);
195 OUT_RING(chan, 1);
196 OUT_RING(chan, 0);
197 OUT_RING(chan, 1);
198 BEGIN_RING(chan, NvSub2D, 0x0580, 2);
199 OUT_RING(chan, 4);
200 OUT_RING(chan, format);
201 BEGIN_RING(chan, NvSub2D, 0x02e8, 2);
202 OUT_RING(chan, 2);
203 OUT_RING(chan, 1);
204 BEGIN_RING(chan, NvSub2D, 0x0804, 1);
205 OUT_RING(chan, format);
206 BEGIN_RING(chan, NvSub2D, 0x0800, 1);
207 OUT_RING(chan, 1);
208 BEGIN_RING(chan, NvSub2D, 0x0808, 3);
209 OUT_RING(chan, 0);
210 OUT_RING(chan, 0);
Marcin Koƛcielnickic82b88d2010-02-27 18:13:35 +0000211 OUT_RING(chan, 1);
Ben Skeggs6ee73862009-12-11 19:24:15 +1000212 BEGIN_RING(chan, NvSub2D, 0x081c, 1);
213 OUT_RING(chan, 1);
214 BEGIN_RING(chan, NvSub2D, 0x0840, 4);
215 OUT_RING(chan, 0);
216 OUT_RING(chan, 1);
217 OUT_RING(chan, 0);
218 OUT_RING(chan, 1);
219 BEGIN_RING(chan, NvSub2D, 0x0200, 2);
220 OUT_RING(chan, format);
221 OUT_RING(chan, 1);
222 BEGIN_RING(chan, NvSub2D, 0x0214, 5);
223 OUT_RING(chan, info->fix.line_length);
224 OUT_RING(chan, info->var.xres_virtual);
225 OUT_RING(chan, info->var.yres_virtual);
Ben Skeggs4c1361422010-11-15 11:54:21 +1000226 OUT_RING(chan, upper_32_bits(nvbo->vma.offset));
227 OUT_RING(chan, lower_32_bits(nvbo->vma.offset));
Ben Skeggs6ee73862009-12-11 19:24:15 +1000228 BEGIN_RING(chan, NvSub2D, 0x0230, 2);
229 OUT_RING(chan, format);
230 OUT_RING(chan, 1);
231 BEGIN_RING(chan, NvSub2D, 0x0244, 5);
232 OUT_RING(chan, info->fix.line_length);
233 OUT_RING(chan, info->var.xres_virtual);
234 OUT_RING(chan, info->var.yres_virtual);
Ben Skeggs4c1361422010-11-15 11:54:21 +1000235 OUT_RING(chan, upper_32_bits(nvbo->vma.offset));
236 OUT_RING(chan, lower_32_bits(nvbo->vma.offset));
Ben Skeggs6ee73862009-12-11 19:24:15 +1000237
Ben Skeggs6ee73862009-12-11 19:24:15 +1000238 return 0;
239}
240