OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [video/] [au1100fb.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 * BRIEF MODULE DESCRIPTION
3
 *      Au1100 LCD Driver.
4
 *
5
 * Rewritten for 2.6 by Embedded Alley Solutions
6
 *      <source@embeddedalley.com>, based on submissions by
7
 *      Karl Lessard <klessard@sunrisetelecom.com>
8
 *      <c.pellegrin@exadron.com>
9
 *
10
 * PM support added by Rodolfo Giometti <giometti@linux.it>
11
 * Cursor enable/disable by Rodolfo Giometti <giometti@linux.it>
12
 *
13
 * Copyright 2002 MontaVista Software
14
 * Author: MontaVista Software, Inc.
15
 *              ppopov@mvista.com or source@mvista.com
16
 *
17
 * Copyright 2002 Alchemy Semiconductor
18
 * Author: Alchemy Semiconductor
19
 *
20
 * Based on:
21
 * linux/drivers/video/skeletonfb.c -- Skeleton for a frame buffer device
22
 *  Created 28 Dec 1997 by Geert Uytterhoeven
23
 *
24
 *  This program is free software; you can redistribute  it and/or modify it
25
 *  under  the terms of  the GNU General  Public License as published by the
26
 *  Free Software Foundation;  either version 2 of the  License, or (at your
27
 *  option) any later version.
28
 *
29
 *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
30
 *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
31
 *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
32
 *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
33
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
34
 *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
35
 *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
36
 *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
37
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
38
 *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39
 *
40
 *  You should have received a copy of the  GNU General Public License along
41
 *  with this program; if not, write  to the Free Software Foundation, Inc.,
42
 *  675 Mass Ave, Cambridge, MA 02139, USA.
43
 */
44
#include <linux/module.h>
45
#include <linux/kernel.h>
46
#include <linux/errno.h>
47
#include <linux/string.h>
48
#include <linux/mm.h>
49
#include <linux/fb.h>
50
#include <linux/init.h>
51
#include <linux/interrupt.h>
52
#include <linux/ctype.h>
53
#include <linux/dma-mapping.h>
54
#include <linux/platform_device.h>
55
 
56
#include <asm/mach-au1x00/au1000.h>
57
 
58
#define DEBUG 0
59
 
60
#include "au1100fb.h"
61
 
62
/*
63
 * Sanity check. If this is a new Au1100 based board, search for
64
 * the PB1100 ifdefs to make sure you modify the code accordingly.
65
 */
66
#if defined(CONFIG_MIPS_PB1100)
67
  #include <asm/mach-pb1x00/pb1100.h>
68
#elif defined(CONFIG_MIPS_DB1100)
69
  #include <asm/mach-db1x00/db1x00.h>
70
#else
71
  #error "Unknown Au1100 board, Au1100 FB driver not supported"
72
#endif
73
 
74
#define DRIVER_NAME "au1100fb"
75
#define DRIVER_DESC "LCD controller driver for AU1100 processors"
76
 
77
#define to_au1100fb_device(_info) \
78
          (_info ? container_of(_info, struct au1100fb_device, info) : NULL);
79
 
80
/* Bitfields format supported by the controller. Note that the order of formats
81
 * SHOULD be the same as in the LCD_CONTROL_SBPPF field, so we can retrieve the
82
 * right pixel format by doing rgb_bitfields[LCD_CONTROL_SBPPF_XXX >> LCD_CONTROL_SBPPF]
83
 */
84
struct fb_bitfield rgb_bitfields[][4] =
85
{
86
        /*     Red,        Green,        Blue,       Transp   */
87
        { { 10, 6, 0 }, { 5, 5, 0 }, { 0, 5, 0 }, { 0, 0, 0 } },
88
        { { 11, 5, 0 }, { 5, 6, 0 }, { 0, 5, 0 }, { 0, 0, 0 } },
89
        { { 11, 5, 0 }, { 6, 5, 0 }, { 0, 6, 0 }, { 0, 0, 0 } },
90
        { { 10, 5, 0 }, { 5, 5, 0 }, { 0, 5, 0 }, { 15, 1, 0 } },
91
        { { 11, 5, 0 }, { 6, 5, 0 }, { 1, 5, 0 }, { 0, 1, 0 } },
92
 
93
        /* The last is used to describe 12bpp format */
94
        { { 8, 4, 0 },  { 4, 4, 0 }, { 0, 4, 0 }, { 0, 0, 0 } },
95
};
96
 
97
static struct fb_fix_screeninfo au1100fb_fix __initdata = {
98
        .id             = "AU1100 FB",
99
        .xpanstep       = 1,
100
        .ypanstep       = 1,
101
        .type           = FB_TYPE_PACKED_PIXELS,
102
        .accel          = FB_ACCEL_NONE,
103
};
104
 
105
static struct fb_var_screeninfo au1100fb_var __initdata = {
106
        .activate       = FB_ACTIVATE_NOW,
107
        .height         = -1,
108
        .width          = -1,
109
        .vmode          = FB_VMODE_NONINTERLACED,
110
};
111
 
112
static struct au1100fb_drv_info drv_info;
113
 
114
static int nocursor = 0;
115
module_param(nocursor, int, 0644);
116
MODULE_PARM_DESC(nocursor, "cursor enable/disable");
117
 
118
/* fb_blank
119
 * Blank the screen. Depending on the mode, the screen will be
120
 * activated with the backlight color, or desactivated
121
 */
122
static int au1100fb_fb_blank(int blank_mode, struct fb_info *fbi)
123
{
124
        struct au1100fb_device *fbdev = to_au1100fb_device(fbi);
125
 
126
        print_dbg("fb_blank %d %p", blank_mode, fbi);
127
 
128
        switch (blank_mode) {
129
 
130
        case VESA_NO_BLANKING:
131
                        /* Turn on panel */
132
                        fbdev->regs->lcd_control |= LCD_CONTROL_GO;
133
#ifdef CONFIG_MIPS_PB1100
134
                        if (drv_info.panel_idx == 1) {
135
                                au_writew(au_readw(PB1100_G_CONTROL)
136
                                          | (PB1100_G_CONTROL_BL | PB1100_G_CONTROL_VDD),
137
                        PB1100_G_CONTROL);
138
                        }
139
#endif
140
                au_sync();
141
                break;
142
 
143
        case VESA_VSYNC_SUSPEND:
144
        case VESA_HSYNC_SUSPEND:
145
        case VESA_POWERDOWN:
146
                        /* Turn off panel */
147
                        fbdev->regs->lcd_control &= ~LCD_CONTROL_GO;
148
#ifdef CONFIG_MIPS_PB1100
149
                        if (drv_info.panel_idx == 1) {
150
                                au_writew(au_readw(PB1100_G_CONTROL)
151
                                          & ~(PB1100_G_CONTROL_BL | PB1100_G_CONTROL_VDD),
152
                        PB1100_G_CONTROL);
153
                        }
154
#endif
155
                au_sync();
156
                break;
157
        default:
158
                break;
159
 
160
        }
161
        return 0;
162
}
163
 
164
/*
165
 * Set hardware with var settings. This will enable the controller with a specific
166
 * mode, normally validated with the fb_check_var method
167
         */
168
int au1100fb_setmode(struct au1100fb_device *fbdev)
169
{
170
        struct fb_info *info = &fbdev->info;
171
        u32 words;
172
        int index;
173
 
174
        if (!fbdev)
175
                return -EINVAL;
176
 
177
        /* Update var-dependent FB info */
178
        if (panel_is_active(fbdev->panel) || panel_is_color(fbdev->panel)) {
179
                if (info->var.bits_per_pixel <= 8) {
180
                        /* palettized */
181
                        info->var.red.offset    = 0;
182
                        info->var.red.length    = info->var.bits_per_pixel;
183
                        info->var.red.msb_right = 0;
184
 
185
                        info->var.green.offset  = 0;
186
                        info->var.green.length  = info->var.bits_per_pixel;
187
                        info->var.green.msb_right = 0;
188
 
189
                        info->var.blue.offset   = 0;
190
                        info->var.blue.length   = info->var.bits_per_pixel;
191
                        info->var.blue.msb_right = 0;
192
 
193
                        info->var.transp.offset = 0;
194
                        info->var.transp.length = 0;
195
                        info->var.transp.msb_right = 0;
196
 
197
                        info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
198
                        info->fix.line_length = info->var.xres_virtual /
199
                                                        (8/info->var.bits_per_pixel);
200
                } else {
201
                        /* non-palettized */
202
                        index = (fbdev->panel->control_base & LCD_CONTROL_SBPPF_MASK) >> LCD_CONTROL_SBPPF_BIT;
203
                        info->var.red = rgb_bitfields[index][0];
204
                        info->var.green = rgb_bitfields[index][1];
205
                        info->var.blue = rgb_bitfields[index][2];
206
                        info->var.transp = rgb_bitfields[index][3];
207
 
208
                        info->fix.visual = FB_VISUAL_TRUECOLOR;
209
                        info->fix.line_length = info->var.xres_virtual << 1; /* depth=16 */
210
                }
211
        } else {
212
                /* mono */
213
                info->fix.visual = FB_VISUAL_MONO10;
214
                info->fix.line_length = info->var.xres_virtual / 8;
215
        }
216
 
217
        info->screen_size = info->fix.line_length * info->var.yres_virtual;
218
        info->var.rotate = ((fbdev->panel->control_base&LCD_CONTROL_SM_MASK) \
219
                                >> LCD_CONTROL_SM_BIT) * 90;
220
 
221
        /* Determine BPP mode and format */
222
        fbdev->regs->lcd_control = fbdev->panel->control_base;
223
        fbdev->regs->lcd_horztiming = fbdev->panel->horztiming;
224
        fbdev->regs->lcd_verttiming = fbdev->panel->verttiming;
225
        fbdev->regs->lcd_clkcontrol = fbdev->panel->clkcontrol_base;
226
        fbdev->regs->lcd_intenable = 0;
227
        fbdev->regs->lcd_intstatus = 0;
228
        fbdev->regs->lcd_dmaaddr0 = LCD_DMA_SA_N(fbdev->fb_phys);
229
 
230
        if (panel_is_dual(fbdev->panel)) {
231
                /* Second panel display seconf half of screen if possible,
232
                 * otherwise display the same as the first panel */
233
                if (info->var.yres_virtual >= (info->var.yres << 1)) {
234
                        fbdev->regs->lcd_dmaaddr1 = LCD_DMA_SA_N(fbdev->fb_phys +
235
                                                          (info->fix.line_length *
236
                                                          (info->var.yres_virtual >> 1)));
237
                } else {
238
                        fbdev->regs->lcd_dmaaddr1 = LCD_DMA_SA_N(fbdev->fb_phys);
239
                }
240
        }
241
 
242
        words = info->fix.line_length / sizeof(u32);
243
        if (!info->var.rotate || (info->var.rotate == 180)) {
244
                words *= info->var.yres_virtual;
245
                if (info->var.rotate /* 180 */) {
246
                        words -= (words % 8); /* should be divisable by 8 */
247
                }
248
        }
249
        fbdev->regs->lcd_words = LCD_WRD_WRDS_N(words);
250
 
251
        fbdev->regs->lcd_pwmdiv = 0;
252
        fbdev->regs->lcd_pwmhi = 0;
253
 
254
        /* Resume controller */
255
        fbdev->regs->lcd_control |= LCD_CONTROL_GO;
256
        mdelay(10);
257
        au1100fb_fb_blank(VESA_NO_BLANKING, info);
258
 
259
        return 0;
260
}
261
 
262
/* fb_setcolreg
263
 * Set color in LCD palette.
264
 */
265
int au1100fb_fb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *fbi)
266
{
267
        struct au1100fb_device *fbdev;
268
        u32 *palette;
269
        u32 value;
270
 
271
        fbdev = to_au1100fb_device(fbi);
272
        palette = fbdev->regs->lcd_pallettebase;
273
 
274
        if (regno > (AU1100_LCD_NBR_PALETTE_ENTRIES - 1))
275
                return -EINVAL;
276
 
277
        if (fbi->var.grayscale) {
278
                /* Convert color to grayscale */
279
                red = green = blue =
280
                        (19595 * red + 38470 * green + 7471 * blue) >> 16;
281
        }
282
 
283
        if (fbi->fix.visual == FB_VISUAL_TRUECOLOR) {
284
                /* Place color in the pseudopalette */
285
                if (regno > 16)
286
                        return -EINVAL;
287
 
288
                palette = (u32*)fbi->pseudo_palette;
289
 
290
                red   >>= (16 - fbi->var.red.length);
291
                green >>= (16 - fbi->var.green.length);
292
                blue  >>= (16 - fbi->var.blue.length);
293
 
294
                value = (red   << fbi->var.red.offset)  |
295
                        (green << fbi->var.green.offset)|
296
                        (blue  << fbi->var.blue.offset);
297
                value &= 0xFFFF;
298
 
299
        } else if (panel_is_active(fbdev->panel)) {
300
                /* COLOR TFT PALLETTIZED (use RGB 565) */
301
                value = (red & 0xF800)|((green >> 5) & 0x07E0)|((blue >> 11) & 0x001F);
302
                value &= 0xFFFF;
303
 
304
        } else if (panel_is_color(fbdev->panel)) {
305
                /* COLOR STN MODE */
306
                value = (((panel_swap_rgb(fbdev->panel) ? blue : red) >> 12) & 0x000F) |
307
                        ((green >> 8) & 0x00F0) |
308
                        (((panel_swap_rgb(fbdev->panel) ? red : blue) >> 4) & 0x0F00);
309
                value &= 0xFFF;
310
        } else {
311
                /* MONOCHROME MODE */
312
                value = (green >> 12) & 0x000F;
313
                value &= 0xF;
314
        }
315
 
316
        palette[regno] = value;
317
 
318
        return 0;
319
}
320
 
321
/* fb_pan_display
322
 * Pan display in x and/or y as specified
323
 */
324
int au1100fb_fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *fbi)
325
{
326
        struct au1100fb_device *fbdev;
327
        int dy;
328
 
329
        fbdev = to_au1100fb_device(fbi);
330
 
331
        print_dbg("fb_pan_display %p %p", var, fbi);
332
 
333
        if (!var || !fbdev) {
334
                return -EINVAL;
335
        }
336
 
337
        if (var->xoffset - fbi->var.xoffset) {
338
                /* No support for X panning for now! */
339
                return -EINVAL;
340
        }
341
 
342
        print_dbg("fb_pan_display 2 %p %p", var, fbi);
343
        dy = var->yoffset - fbi->var.yoffset;
344
        if (dy) {
345
 
346
                u32 dmaaddr;
347
 
348
                print_dbg("Panning screen of %d lines", dy);
349
 
350
                dmaaddr = fbdev->regs->lcd_dmaaddr0;
351
                dmaaddr += (fbi->fix.line_length * dy);
352
 
353
                /* TODO: Wait for current frame to finished */
354
                fbdev->regs->lcd_dmaaddr0 = LCD_DMA_SA_N(dmaaddr);
355
 
356
                if (panel_is_dual(fbdev->panel)) {
357
                        dmaaddr = fbdev->regs->lcd_dmaaddr1;
358
                        dmaaddr += (fbi->fix.line_length * dy);
359
                        fbdev->regs->lcd_dmaaddr0 = LCD_DMA_SA_N(dmaaddr);
360
        }
361
        }
362
        print_dbg("fb_pan_display 3 %p %p", var, fbi);
363
 
364
        return 0;
365
}
366
 
367
/* fb_rotate
368
 * Rotate the display of this angle. This doesn't seems to be used by the core,
369
 * but as our hardware supports it, so why not implementing it...
370
 */
371
void au1100fb_fb_rotate(struct fb_info *fbi, int angle)
372
{
373
        struct au1100fb_device *fbdev = to_au1100fb_device(fbi);
374
 
375
        print_dbg("fb_rotate %p %d", fbi, angle);
376
 
377
        if (fbdev && (angle > 0) && !(angle % 90)) {
378
 
379
                fbdev->regs->lcd_control &= ~LCD_CONTROL_GO;
380
 
381
                fbdev->regs->lcd_control &= ~(LCD_CONTROL_SM_MASK);
382
                fbdev->regs->lcd_control |= ((angle/90) << LCD_CONTROL_SM_BIT);
383
 
384
                fbdev->regs->lcd_control |= LCD_CONTROL_GO;
385
        }
386
}
387
 
388
/* fb_mmap
389
 * Map video memory in user space. We don't use the generic fb_mmap method mainly
390
 * to allow the use of the TLB streaming flag (CCA=6)
391
 */
392
int au1100fb_fb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
393
{
394
        struct au1100fb_device *fbdev;
395
        unsigned int len;
396
        unsigned long start=0, off;
397
 
398
        fbdev = to_au1100fb_device(fbi);
399
 
400
        if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) {
401
                return -EINVAL;
402
        }
403
 
404
        start = fbdev->fb_phys & PAGE_MASK;
405
        len = PAGE_ALIGN((start & ~PAGE_MASK) + fbdev->fb_len);
406
 
407
        off = vma->vm_pgoff << PAGE_SHIFT;
408
 
409
        if ((vma->vm_end - vma->vm_start + off) > len) {
410
                return -EINVAL;
411
        }
412
 
413
        off += start;
414
        vma->vm_pgoff = off >> PAGE_SHIFT;
415
 
416
        vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
417
        pgprot_val(vma->vm_page_prot) |= (6 << 9); //CCA=6
418
 
419
        vma->vm_flags |= VM_IO;
420
 
421
        if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
422
                                vma->vm_end - vma->vm_start,
423
                                vma->vm_page_prot)) {
424
                return -EAGAIN;
425
        }
426
 
427
        return 0;
428
}
429
 
430
/* fb_cursor
431
 * Used to disable cursor drawing...
432
 */
433
int au1100fb_fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
434
{
435
        if (nocursor)
436
                return 0;
437
        else
438
                return -EINVAL; /* just to force soft_cursor() call */
439
}
440
 
441
static struct fb_ops au1100fb_ops =
442
{
443
        .owner                  = THIS_MODULE,
444
        .fb_setcolreg           = au1100fb_fb_setcolreg,
445
        .fb_blank               = au1100fb_fb_blank,
446
        .fb_pan_display         = au1100fb_fb_pan_display,
447
        .fb_fillrect            = cfb_fillrect,
448
        .fb_copyarea            = cfb_copyarea,
449
        .fb_imageblit           = cfb_imageblit,
450
        .fb_rotate              = au1100fb_fb_rotate,
451
        .fb_mmap                = au1100fb_fb_mmap,
452
        .fb_cursor              = au1100fb_fb_cursor,
453
};
454
 
455
 
456
/*-------------------------------------------------------------------------*/
457
 
458
/* AU1100 LCD controller device driver */
459
 
460
static int __init au1100fb_drv_probe(struct device *dev)
461
{
462
        struct au1100fb_device *fbdev = NULL;
463
        struct resource *regs_res;
464
        unsigned long page;
465
        u32 sys_clksrc;
466
 
467
        if (!dev)
468
                        return -EINVAL;
469
 
470
        /* Allocate new device private */
471
        if (!(fbdev = kzalloc(sizeof(struct au1100fb_device), GFP_KERNEL))) {
472
                print_err("fail to allocate device private record");
473
                return -ENOMEM;
474
        }
475
 
476
        fbdev->panel = &known_lcd_panels[drv_info.panel_idx];
477
 
478
        dev_set_drvdata(dev, (void*)fbdev);
479
 
480
        /* Allocate region for our registers and map them */
481
        if (!(regs_res = platform_get_resource(to_platform_device(dev),
482
                                        IORESOURCE_MEM, 0))) {
483
                print_err("fail to retrieve registers resource");
484
                return -EFAULT;
485
        }
486
 
487
        au1100fb_fix.mmio_start = regs_res->start;
488
        au1100fb_fix.mmio_len = regs_res->end - regs_res->start + 1;
489
 
490
        if (!request_mem_region(au1100fb_fix.mmio_start, au1100fb_fix.mmio_len,
491
                                DRIVER_NAME)) {
492
                print_err("fail to lock memory region at 0x%08lx",
493
                                au1100fb_fix.mmio_start);
494
                return -EBUSY;
495
        }
496
 
497
        fbdev->regs = (struct au1100fb_regs*)KSEG1ADDR(au1100fb_fix.mmio_start);
498
 
499
        print_dbg("Register memory map at %p", fbdev->regs);
500
        print_dbg("phys=0x%08x, size=%d", fbdev->regs_phys, fbdev->regs_len);
501
 
502
 
503
 
504
        /* Allocate the framebuffer to the maximum screen size * nbr of video buffers */
505
        fbdev->fb_len = fbdev->panel->xres * fbdev->panel->yres *
506
                        (fbdev->panel->bpp >> 3) * AU1100FB_NBR_VIDEO_BUFFERS;
507
 
508
        fbdev->fb_mem = dma_alloc_coherent(dev, PAGE_ALIGN(fbdev->fb_len),
509
                                        &fbdev->fb_phys, GFP_KERNEL);
510
        if (!fbdev->fb_mem) {
511
                print_err("fail to allocate frambuffer (size: %dK))",
512
                          fbdev->fb_len / 1024);
513
                return -ENOMEM;
514
        }
515
 
516
        au1100fb_fix.smem_start = fbdev->fb_phys;
517
        au1100fb_fix.smem_len = fbdev->fb_len;
518
 
519
        /*
520
         * Set page reserved so that mmap will work. This is necessary
521
         * since we'll be remapping normal memory.
522
         */
523
        for (page = (unsigned long)fbdev->fb_mem;
524
             page < PAGE_ALIGN((unsigned long)fbdev->fb_mem + fbdev->fb_len);
525
             page += PAGE_SIZE) {
526
#if CONFIG_DMA_NONCOHERENT
527
                SetPageReserved(virt_to_page(CAC_ADDR(page)));
528
#else
529
                SetPageReserved(virt_to_page(page));
530
#endif
531
        }
532
 
533
        print_dbg("Framebuffer memory map at %p", fbdev->fb_mem);
534
        print_dbg("phys=0x%08x, size=%dK", fbdev->fb_phys, fbdev->fb_len / 1024);
535
 
536
        /* Setup LCD clock to AUX (48 MHz) */
537
        sys_clksrc = au_readl(SYS_CLKSRC) & ~(SYS_CS_ML_MASK | SYS_CS_DL | SYS_CS_CL);
538
        au_writel((sys_clksrc | (1 << SYS_CS_ML_BIT)), SYS_CLKSRC);
539
 
540
        /* load the panel info into the var struct */
541
        au1100fb_var.bits_per_pixel = fbdev->panel->bpp;
542
        au1100fb_var.xres = fbdev->panel->xres;
543
        au1100fb_var.xres_virtual = au1100fb_var.xres;
544
        au1100fb_var.yres = fbdev->panel->yres;
545
        au1100fb_var.yres_virtual = au1100fb_var.yres;
546
 
547
        fbdev->info.screen_base = fbdev->fb_mem;
548
        fbdev->info.fbops = &au1100fb_ops;
549
        fbdev->info.fix = au1100fb_fix;
550
 
551
        if (!(fbdev->info.pseudo_palette = kzalloc(sizeof(u32) * 16, GFP_KERNEL))) {
552
                return -ENOMEM;
553
        }
554
 
555
        if (fb_alloc_cmap(&fbdev->info.cmap, AU1100_LCD_NBR_PALETTE_ENTRIES, 0) < 0) {
556
                print_err("Fail to allocate colormap (%d entries)",
557
                           AU1100_LCD_NBR_PALETTE_ENTRIES);
558
                kfree(fbdev->info.pseudo_palette);
559
                return -EFAULT;
560
        }
561
 
562
        fbdev->info.var = au1100fb_var;
563
 
564
        /* Set h/w registers */
565
        au1100fb_setmode(fbdev);
566
 
567
        /* Register new framebuffer */
568
        if (register_framebuffer(&fbdev->info) < 0) {
569
                print_err("cannot register new framebuffer");
570
                goto failed;
571
        }
572
 
573
        return 0;
574
 
575
failed:
576
        if (fbdev->regs) {
577
                release_mem_region(fbdev->regs_phys, fbdev->regs_len);
578
        }
579
        if (fbdev->fb_mem) {
580
                dma_free_noncoherent(dev, fbdev->fb_len, fbdev->fb_mem, fbdev->fb_phys);
581
        }
582
        if (fbdev->info.cmap.len != 0) {
583
                fb_dealloc_cmap(&fbdev->info.cmap);
584
        }
585
        kfree(fbdev);
586
        dev_set_drvdata(dev, NULL);
587
 
588
        return 0;
589
}
590
 
591
int au1100fb_drv_remove(struct device *dev)
592
{
593
        struct au1100fb_device *fbdev = NULL;
594
 
595
        if (!dev)
596
                return -ENODEV;
597
 
598
        fbdev = (struct au1100fb_device*) dev_get_drvdata(dev);
599
 
600
#if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO)
601
        au1100fb_fb_blank(VESA_POWERDOWN, &fbdev->info);
602
#endif
603
        fbdev->regs->lcd_control &= ~LCD_CONTROL_GO;
604
 
605
        /* Clean up all probe data */
606
        unregister_framebuffer(&fbdev->info);
607
 
608
        release_mem_region(fbdev->regs_phys, fbdev->regs_len);
609
 
610
        dma_free_coherent(dev, PAGE_ALIGN(fbdev->fb_len), fbdev->fb_mem, fbdev->fb_phys);
611
 
612
        fb_dealloc_cmap(&fbdev->info.cmap);
613
        kfree(fbdev->info.pseudo_palette);
614
        kfree((void*)fbdev);
615
 
616
        return 0;
617
}
618
 
619
#ifdef CONFIG_PM
620
static u32 sys_clksrc;
621
static struct au1100fb_regs fbregs;
622
 
623
int au1100fb_drv_suspend(struct device *dev, pm_message_t state)
624
{
625
        struct au1100fb_device *fbdev = dev_get_drvdata(dev);
626
 
627
        if (!fbdev)
628
                return 0;
629
 
630
        /* Save the clock source state */
631
        sys_clksrc = au_readl(SYS_CLKSRC);
632
 
633
        /* Blank the LCD */
634
        au1100fb_fb_blank(VESA_POWERDOWN, &fbdev->info);
635
 
636
        /* Stop LCD clocking */
637
        au_writel(sys_clksrc & ~SYS_CS_ML_MASK, SYS_CLKSRC);
638
 
639
        memcpy(&fbregs, fbdev->regs, sizeof(struct au1100fb_regs));
640
 
641
        return 0;
642
}
643
 
644
int au1100fb_drv_resume(struct device *dev)
645
{
646
        struct au1100fb_device *fbdev = dev_get_drvdata(dev);
647
 
648
        if (!fbdev)
649
                return 0;
650
 
651
        memcpy(fbdev->regs, &fbregs, sizeof(struct au1100fb_regs));
652
 
653
        /* Restart LCD clocking */
654
        au_writel(sys_clksrc, SYS_CLKSRC);
655
 
656
        /* Unblank the LCD */
657
        au1100fb_fb_blank(VESA_NO_BLANKING, &fbdev->info);
658
 
659
        return 0;
660
}
661
#else
662
#define au1100fb_drv_suspend NULL
663
#define au1100fb_drv_resume NULL
664
#endif
665
 
666
static struct device_driver au1100fb_driver = {
667
        .name           = "au1100-lcd",
668
        .bus            = &platform_bus_type,
669
 
670
        .probe          = au1100fb_drv_probe,
671
        .remove         = au1100fb_drv_remove,
672
        .suspend        = au1100fb_drv_suspend,
673
        .resume         = au1100fb_drv_resume,
674
};
675
 
676
/*-------------------------------------------------------------------------*/
677
 
678
/* Kernel driver */
679
 
680
int au1100fb_setup(char *options)
681
{
682
        char* this_opt;
683
        int num_panels = ARRAY_SIZE(known_lcd_panels);
684
        char* mode = NULL;
685
        int panel_idx = 0;
686
 
687
        if (num_panels <= 0) {
688
                print_err("No LCD panels supported by driver!");
689
                return -EFAULT;
690
                        }
691
 
692
        if (options) {
693
                while ((this_opt = strsep(&options,",")) != NULL) {
694
                        /* Panel option */
695
                        if (!strncmp(this_opt, "panel:", 6)) {
696
                                int i;
697
                                this_opt += 6;
698
                                for (i = 0; i < num_panels; i++) {
699
                                        if (!strncmp(this_opt,
700
                                                     known_lcd_panels[i].name,
701
                                                        strlen(this_opt))) {
702
                                                panel_idx = i;
703
                                                break;
704
                                        }
705
                                }
706
                                if (i >= num_panels) {
707
                                        print_warn("Panel %s not supported!", this_opt);
708
                                }
709
                        }
710
                        if (!strncmp(this_opt, "nocursor", 8)) {
711
                                this_opt += 8;
712
                                nocursor = 1;
713
                                print_info("Cursor disabled");
714
                        }
715
                        /* Mode option (only option that start with digit) */
716
                        else if (isdigit(this_opt[0])) {
717
                                mode = kmalloc(strlen(this_opt) + 1, GFP_KERNEL);
718
                                strncpy(mode, this_opt, strlen(this_opt) + 1);
719
                        }
720
                        /* Unsupported option */
721
                        else {
722
                                print_warn("Unsupported option \"%s\"", this_opt);
723
                        }
724
                }
725
        }
726
 
727
        drv_info.panel_idx = panel_idx;
728
        drv_info.opt_mode = mode;
729
 
730
        print_info("Panel=%s Mode=%s",
731
                        known_lcd_panels[drv_info.panel_idx].name,
732
                        drv_info.opt_mode ? drv_info.opt_mode : "default");
733
 
734
        return 0;
735
}
736
 
737
int __init au1100fb_init(void)
738
{
739
        char* options;
740
        int ret;
741
 
742
        print_info("" DRIVER_DESC "");
743
 
744
        memset(&drv_info, 0, sizeof(drv_info));
745
 
746
        if (fb_get_options(DRIVER_NAME, &options))
747
                return -ENODEV;
748
 
749
        /* Setup driver with options */
750
        ret = au1100fb_setup(options);
751
        if (ret < 0) {
752
                print_err("Fail to setup driver");
753
                return ret;
754
        }
755
 
756
        return driver_register(&au1100fb_driver);
757
}
758
 
759
void __exit au1100fb_cleanup(void)
760
{
761
        driver_unregister(&au1100fb_driver);
762
 
763
        kfree(drv_info.opt_mode);
764
}
765
 
766
module_init(au1100fb_init);
767
module_exit(au1100fb_cleanup);
768
 
769
MODULE_DESCRIPTION(DRIVER_DESC);
770
MODULE_LICENSE("GPL");

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.