OSDN Git Service

initial import
[android-x86/device-viliv-s5.git] / psb-kernel-source-4.41.1 / drm_fb.c
1 /*
2  * Copyright © 2007 David Airlie
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  *
23  * Authors:
24  *     David Airlie
25  */
26     /*
27      *  Modularization
28      */
29
30 #include <linux/module.h>
31 #include <linux/kernel.h>
32 #include <linux/errno.h>
33 #include <linux/string.h>
34 #include <linux/mm.h>
35 #include <linux/tty.h>
36 #include <linux/slab.h>
37 #include <linux/delay.h>
38 #include <linux/fb.h>
39 #include <linux/init.h>
40
41 #include "drmP.h"
42 #include "drm_crtc.h"
43
44 struct drmfb_par {
45         struct drm_device *dev;
46         struct drm_crtc *crtc;
47 };
48
49 static int drmfb_setcolreg(unsigned regno, unsigned red, unsigned green,
50                            unsigned blue, unsigned transp,
51                            struct fb_info *info)
52 {
53         struct drmfb_par *par = info->par;
54         struct drm_framebuffer *fb = par->crtc->fb;
55         struct drm_crtc *crtc = par->crtc;
56
57         if (regno > 255)
58                 return 1;
59
60         if (fb->depth == 8) {
61                 if (crtc->funcs->gamma_set) {
62                         crtc->funcs->gamma_set(crtc, red, green, blue, regno);
63                 }
64                 return 0;
65         }
66         
67         if (regno < 16) {
68                 switch (fb->depth) {
69                 case 15:
70                         fb->pseudo_palette[regno] = ((red & 0xf800) >>  1) |
71                                 ((green & 0xf800) >>  6) |
72                                 ((blue & 0xf800) >> 11);
73                         break;
74                 case 16:
75                         fb->pseudo_palette[regno] = (red & 0xf800) |
76                                 ((green & 0xfc00) >>  5) |
77                                 ((blue  & 0xf800) >> 11);
78                         break;
79                 case 24:
80                 case 32:
81                         fb->pseudo_palette[regno] = ((red & 0xff00) << 8) |
82                                 (green & 0xff00) |
83                                 ((blue  & 0xff00) >> 8);
84                         break;
85                 }
86         }
87
88         return 0;
89 }
90
91 static int drmfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
92 {
93         struct drmfb_par *par = info->par;
94         struct drm_device *dev = par->dev;
95         struct drm_framebuffer *fb = par->crtc->fb;
96         struct drm_display_mode *drm_mode;
97         struct drm_output *output;
98         int depth;
99
100         if (!var->pixclock)
101                 return -EINVAL;
102
103         /* Need to resize the fb object !!! */
104         if (var->xres > fb->width || var->yres > fb->height) {
105                 DRM_ERROR("Requested width/height is greater than current fb object %dx%d > %dx%d\n",var->xres,var->yres,fb->width,fb->height);
106                 DRM_ERROR("Need resizing code.\n");
107                 return -EINVAL;
108         }
109
110         switch (var->bits_per_pixel) {
111         case 16:
112                 depth = (var->green.length == 6) ? 16 : 15;
113                 break;
114         case 32:
115                 depth = (var->transp.length > 0) ? 32 : 24;
116                 break;
117         default:
118                 depth = var->bits_per_pixel;
119                 break;
120         }
121                 
122         switch (depth) {
123         case 8:
124                 var->red.offset = 0;
125                 var->green.offset = 0;
126                 var->blue.offset = 0;
127                 var->red.length = 8;
128                 var->green.length = 8;
129                 var->blue.length = 8;
130                 var->transp.length = 0;
131                 var->transp.offset = 0;
132                 break;
133         case 15:
134                 var->red.offset = 10;
135                 var->green.offset = 5;
136                 var->blue.offset = 0;
137                 var->red.length = 5;
138                 var->green.length = 5;
139                 var->blue.length = 5;
140                 var->transp.length = 1;
141                 var->transp.offset = 15;
142                 break;
143         case 16:
144                 var->red.offset = 11;
145                 var->green.offset = 6;
146                 var->blue.offset = 0;
147                 var->red.length = 5;
148                 var->green.length = 6;
149                 var->blue.length = 5;
150                 var->transp.length = 0;
151                 var->transp.offset = 0;
152                 break;
153         case 24:
154                 var->red.offset = 16;
155                 var->green.offset = 8;
156                 var->blue.offset = 0;
157                 var->red.length = 8;
158                 var->green.length = 8;
159                 var->blue.length = 8;
160                 var->transp.length = 0;
161                 var->transp.offset = 0;
162                 break;
163         case 32:
164                 var->red.offset = 16;
165                 var->green.offset = 8;
166                 var->blue.offset = 0;
167                 var->red.length = 8;
168                 var->green.length = 8;
169                 var->blue.length = 8;
170                 var->transp.length = 8;
171                 var->transp.offset = 24;
172                 break;
173         default:
174                 return -EINVAL; 
175         }
176
177 #if 0
178         /* Here we walk the output mode list and look for modes. If we haven't
179          * got it, then bail. Not very nice, so this is disabled.
180          * In the set_par code, we create our mode based on the incoming
181          * parameters. Nicer, but may not be desired by some.
182          */
183         list_for_each_entry(output, &dev->mode_config.output_list, head) {
184                 if (output->crtc == par->crtc)
185                         break;
186         }
187     
188         list_for_each_entry(drm_mode, &output->modes, head) {
189                 if (drm_mode->hdisplay == var->xres &&
190                     drm_mode->vdisplay == var->yres &&
191                     drm_mode->clock != 0)
192                     break;
193         }
194
195         if (!drm_mode)
196                 return -EINVAL;
197 #endif
198
199         return 0;
200 }
201
202 /* this will let fbcon do the mode init */
203 static int drmfb_set_par(struct fb_info *info)
204 {
205         struct drmfb_par *par = info->par;
206         struct drm_framebuffer *fb = par->crtc->fb;
207         struct drm_device *dev = par->dev;
208         struct drm_display_mode *drm_mode;
209         struct fb_var_screeninfo *var = &info->var;
210         struct drm_output *output;
211
212         switch (var->bits_per_pixel) {
213         case 16:
214                 fb->depth = (var->green.length == 6) ? 16 : 15;
215                 break;
216         case 32:
217                 fb->depth = (var->transp.length > 0) ? 32 : 24;
218                 break;
219         default:
220                 fb->depth = var->bits_per_pixel;
221                 break;
222         }
223
224         fb->bits_per_pixel = var->bits_per_pixel;
225
226         info->fix.line_length = fb->pitch;
227         info->fix.smem_len = info->fix.line_length * fb->height;
228         info->fix.visual = (fb->depth == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
229
230         info->screen_size = info->fix.smem_len; /* ??? */
231
232         /* Should we walk the output's modelist or just create our own ???
233          * For now, we create and destroy a mode based on the incoming 
234          * parameters. But there's commented out code below which scans 
235          * the output list too.
236          */
237 #if 0
238         list_for_each_entry(output, &dev->mode_config.output_list, head) {
239                 if (output->crtc == par->crtc)
240                         break;
241         }
242     
243         list_for_each_entry(drm_mode, &output->modes, head) {
244                 if (drm_mode->hdisplay == var->xres &&
245                     drm_mode->vdisplay == var->yres &&
246                     drm_mode->clock != 0)
247                     break;
248         }
249 #else
250         drm_mode = drm_mode_create(dev);
251         drm_mode->hdisplay = var->xres;
252         drm_mode->hsync_start = drm_mode->hdisplay + var->right_margin;
253         drm_mode->hsync_end = drm_mode->hsync_start + var->hsync_len;
254         drm_mode->htotal = drm_mode->hsync_end + var->left_margin;
255         drm_mode->vdisplay = var->yres;
256         drm_mode->vsync_start = drm_mode->vdisplay + var->lower_margin;
257         drm_mode->vsync_end = drm_mode->vsync_start + var->vsync_len;
258         drm_mode->vtotal = drm_mode->vsync_end + var->upper_margin;
259         drm_mode->clock = PICOS2KHZ(var->pixclock);
260         drm_mode->vrefresh = drm_mode_vrefresh(drm_mode);
261         drm_mode_set_name(drm_mode);
262         drm_mode_set_crtcinfo(drm_mode, CRTC_INTERLACE_HALVE_V);
263 #endif
264
265         if (!drm_crtc_set_mode(par->crtc, drm_mode, 0, 0))
266                 return -EINVAL;
267
268         /* Have to destroy our created mode if we're not searching the mode
269          * list for it.
270          */
271 #if 1 
272         drm_mode_destroy(dev, drm_mode);
273 #endif
274
275         return 0;
276 }
277
278 static struct fb_ops drmfb_ops = {
279         .owner = THIS_MODULE,
280         //      .fb_open = drmfb_open,
281         //      .fb_read = drmfb_read,
282         //      .fb_write = drmfb_write,
283         //      .fb_release = drmfb_release,
284         //      .fb_ioctl = drmfb_ioctl,
285         .fb_check_var = drmfb_check_var,
286         .fb_set_par = drmfb_set_par,
287         .fb_setcolreg = drmfb_setcolreg,
288         .fb_fillrect = cfb_fillrect,
289         .fb_copyarea = cfb_copyarea,
290         .fb_imageblit = cfb_imageblit,
291 };
292
293 int drmfb_probe(struct drm_device *dev, struct drm_crtc *crtc)
294 {
295         struct fb_info *info;
296         struct drm_framebuffer *fb = crtc->fb;
297         struct drmfb_par *par;
298         struct device *device = &dev->pdev->dev; 
299         struct drm_display_mode *mode = crtc->desired_mode;
300         int ret;
301
302         info = framebuffer_alloc(sizeof(struct drmfb_par), device);
303         if (!info)
304                 return -ENOMEM;
305
306         fb->fbdev = info;
307                 
308         par = info->par;
309
310         par->dev = dev;
311         par->crtc = crtc;
312
313         info->fbops = &drmfb_ops;
314
315         strcpy(info->fix.id, "drmfb");
316         info->fix.type = FB_TYPE_PACKED_PIXELS;
317         info->fix.visual = FB_VISUAL_TRUECOLOR;
318         info->fix.accel = FB_ACCEL_NONE;
319         info->fix.type_aux = 0;
320         info->fix.mmio_start = 0;
321         info->fix.mmio_len = 0;
322         info->fix.line_length = fb->pitch;
323         info->fix.smem_start = fb->offset + dev->mode_config.fb_base;
324         info->fix.smem_len = info->fix.line_length * fb->height;
325
326         info->flags = FBINFO_DEFAULT;
327
328         ret = drm_bo_kmap(fb->bo, 0, fb->bo->num_pages, &fb->kmap);
329         if (ret)
330                 DRM_ERROR("error mapping fb: %d\n", ret);
331
332         info->screen_base = fb->kmap.virtual;
333         info->screen_size = info->fix.smem_len; /* ??? */
334         info->pseudo_palette = fb->pseudo_palette;
335         info->var.xres_virtual = fb->width;
336         info->var.yres_virtual = fb->height;
337         info->var.bits_per_pixel = fb->bits_per_pixel;
338         info->var.xoffset = 0;
339         info->var.yoffset = 0;
340         info->var.activate = FB_ACTIVATE_NOW;
341         info->var.height = -1;
342         info->var.width = -1;
343         info->var.vmode = FB_VMODE_NONINTERLACED;
344
345         info->var.xres = mode->hdisplay;
346         info->var.right_margin = mode->hsync_start - mode->hdisplay;
347         info->var.hsync_len = mode->hsync_end - mode->hsync_start;
348         info->var.left_margin = mode->htotal - mode->hsync_end;
349         info->var.yres = mode->vdisplay;
350         info->var.lower_margin = mode->vsync_start - mode->vdisplay;
351         info->var.vsync_len = mode->vsync_end - mode->vsync_start;
352         info->var.upper_margin = mode->vtotal - mode->vsync_end;
353         info->var.pixclock = 10000000 / mode->htotal * 1000 /
354                                 mode->vtotal * 100;
355         /* avoid overflow */
356         info->var.pixclock = info->var.pixclock * 1000 / mode->vrefresh;
357
358         DRM_DEBUG("fb depth is %d\n", fb->depth);
359         switch(fb->depth) {
360         case 8:
361                 info->var.red.offset = 0;
362                 info->var.green.offset = 0;
363                 info->var.blue.offset = 0;
364                 info->var.red.length = 8; /* 8bit DAC */
365                 info->var.green.length = 8;
366                 info->var.blue.length = 8;
367                 info->var.transp.offset = 0;
368                 info->var.transp.length = 0;
369                 break;
370         case 15:
371                 info->var.red.offset = 10;
372                 info->var.green.offset = 5;
373                 info->var.blue.offset = 0;
374                 info->var.red.length = info->var.green.length =
375                         info->var.blue.length = 5;
376                 info->var.transp.offset = 15;
377                 info->var.transp.length = 1;
378                 break;
379         case 16:
380                 info->var.red.offset = 11;
381                 info->var.green.offset = 5;
382                 info->var.blue.offset = 0;
383                 info->var.red.length = 5;
384                 info->var.green.length = 6;
385                 info->var.blue.length = 5;
386                 info->var.transp.offset = 0;
387                 info->var.transp.length = 0;
388                 break;
389         case 24:
390                 info->var.red.offset = 16;
391                 info->var.green.offset = 8;
392                 info->var.blue.offset = 0;
393                 info->var.red.length = info->var.green.length =
394                         info->var.blue.length = 8;
395                 info->var.transp.offset = 0;
396                 info->var.transp.length = 0;
397                 break;
398         case 32:
399                 info->var.red.offset = 16;
400                 info->var.green.offset = 8;
401                 info->var.blue.offset = 0;
402                 info->var.red.length = info->var.green.length =
403                         info->var.blue.length = 8;
404                 info->var.transp.offset = 24;
405                 info->var.transp.length = 8;
406                 break;
407         default:
408                 break;
409         }
410
411         if (register_framebuffer(info) < 0) {
412                 unregister_framebuffer(info);
413                 return -EINVAL;
414         }
415
416         printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
417                info->fix.id);
418         return 0;
419 }
420 EXPORT_SYMBOL(drmfb_probe);
421
422 int drmfb_remove(struct drm_device *dev, struct drm_crtc *crtc)
423 {
424         struct fb_info *info = fb->fbdev;
425         struct drm_framebuffer *fb = crtc->fb;
426         
427         if (info) {
428                 unregister_framebuffer(info);
429                 framebuffer_release(info);
430                 drm_bo_kunmap(&fb->kmap);
431                 drm_bo_usage_deref_unlocked(fb->bo);
432         }
433         return 0;
434 }
435 EXPORT_SYMBOL(drmfb_remove);
436 MODULE_LICENSE("GPL");