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

Subversion Repositories test_project

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 *  linux/drivers/video/clps711xfb.c
3
 *
4
 *  Copyright (C) 2000-2001 Deep Blue Solutions Ltd.
5
 *
6
 * This program is free software; you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation; either version 2 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
 *
20
 *  Framebuffer driver for the CLPS7111 and EP7212 processors.
21
 */
22
#include <linux/module.h>
23
#include <linux/kernel.h>
24
#include <linux/slab.h>
25
#include <linux/fb.h>
26
#include <linux/init.h>
27
#include <linux/proc_fs.h>
28
#include <linux/delay.h>
29
 
30
#include <asm/hardware.h>
31
#include <asm/mach-types.h>
32
#include <linux/uaccess.h>
33
 
34
#include <asm/hardware/clps7111.h>
35
#include <asm/arch/syspld.h>
36
 
37
struct fb_info  *cfb;
38
 
39
#define CMAP_MAX_SIZE   16
40
 
41
/* The /proc entry for the backlight. */
42
static struct proc_dir_entry *clps7111fb_backlight_proc_entry = NULL;
43
 
44
static int clps7111fb_proc_backlight_read(char *page, char **start, off_t off,
45
                int count, int *eof, void *data);
46
static int clps7111fb_proc_backlight_write(struct file *file,
47
                const char *buffer, unsigned long count, void *data);
48
 
49
/*
50
 * LCD AC Prescale.  This comes from the LCD panel manufacturers specifications.
51
 * This determines how many clocks + 1 of CL1 before the M signal toggles.
52
 * The number of lines on the display must not be divisible by this number.
53
 */
54
static unsigned int lcd_ac_prescale = 13;
55
 
56
/*
57
 *    Set a single color register. Return != 0 for invalid regno.
58
 */
59
static int
60
clps7111fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
61
                     u_int transp, struct fb_info *info)
62
{
63
        unsigned int level, mask, shift, pal;
64
 
65
        if (regno >= (1 << info->var.bits_per_pixel))
66
                return 1;
67
 
68
        /* gray = 0.30*R + 0.58*G + 0.11*B */
69
        level = (red * 77 + green * 151 + blue * 28) >> 20;
70
 
71
        /*
72
         * On an LCD, a high value is dark, while a low value is light.
73
         * So we invert the level.
74
         *
75
         * This isn't true on all machines, so we only do it on EDB7211.
76
         *  --rmk
77
         */
78
        if (machine_is_edb7211()) {
79
                level = 15 - level;
80
        }
81
 
82
        shift = 4 * (regno & 7);
83
        level <<= shift;
84
        mask  = 15 << shift;
85
        level &= mask;
86
 
87
        regno = regno < 8 ? PALLSW : PALMSW;
88
 
89
        pal = clps_readl(regno);
90
        pal = (pal & ~mask) | level;
91
        clps_writel(pal, regno);
92
 
93
        return 0;
94
}
95
 
96
/*
97
 * Validate the purposed mode.
98
 */
99
static int
100
clps7111fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
101
{
102
        var->transp.msb_right   = 0;
103
        var->transp.offset      = 0;
104
        var->transp.length      = 0;
105
        var->red.msb_right      = 0;
106
        var->red.offset         = 0;
107
        var->red.length         = var->bits_per_pixel;
108
        var->green              = var->red;
109
        var->blue               = var->red;
110
 
111
        if (var->bits_per_pixel > 4)
112
                return -EINVAL;
113
 
114
        return 0;
115
}
116
 
117
/*
118
 * Set the hardware state.
119
 */
120
static int
121
clps7111fb_set_par(struct fb_info *info)
122
{
123
        unsigned int lcdcon, syscon, pixclock;
124
 
125
        switch (info->var.bits_per_pixel) {
126
        case 1:
127
                info->fix.visual = FB_VISUAL_MONO01;
128
                break;
129
        case 2:
130
                info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
131
                break;
132
        case 4:
133
                info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
134
                break;
135
        }
136
 
137
        info->fix.line_length = info->var.xres_virtual * info->var.bits_per_pixel / 8;
138
 
139
        lcdcon = (info->var.xres_virtual * info->var.yres_virtual * info->var.bits_per_pixel) / 128 - 1;
140
        lcdcon |= ((info->var.xres_virtual / 16) - 1) << 13;
141
        lcdcon |= lcd_ac_prescale << 25;
142
 
143
        /*
144
         * Calculate pixel prescale value from the pixclock.  This is:
145
         *  36.864MHz / pixclock_mhz - 1.
146
         * However, pixclock is in picoseconds, so this ends up being:
147
         *  36864000 * pixclock_ps / 10^12 - 1
148
         * and this will overflow the 32-bit math.  We perform this as
149
         * (9 * 4096000 == 36864000):
150
         *  pixclock_ps * 9 * (4096000 / 10^12) - 1
151
         */
152
        pixclock = 9 * info->var.pixclock / 244140 - 1;
153
        lcdcon |= pixclock << 19;
154
 
155
        if (info->var.bits_per_pixel == 4)
156
                lcdcon |= LCDCON_GSMD;
157
        if (info->var.bits_per_pixel >= 2)
158
                lcdcon |= LCDCON_GSEN;
159
 
160
        /*
161
         * LCDCON must only be changed while the LCD is disabled
162
         */
163
        syscon = clps_readl(SYSCON1);
164
        clps_writel(syscon & ~SYSCON1_LCDEN, SYSCON1);
165
        clps_writel(lcdcon, LCDCON);
166
        clps_writel(syscon | SYSCON1_LCDEN, SYSCON1);
167
        return 0;
168
}
169
 
170
static int clps7111fb_blank(int blank, struct fb_info *info)
171
{
172
        if (blank) {
173
                if (machine_is_edb7211()) {
174
                        /* Turn off the LCD backlight. */
175
                        clps_writeb(clps_readb(PDDR) & ~EDB_PD3_LCDBL, PDDR);
176
 
177
                        /* Power off the LCD DC-DC converter. */
178
                        clps_writeb(clps_readb(PDDR) & ~EDB_PD1_LCD_DC_DC_EN, PDDR);
179
 
180
                        /* Delay for a little while (half a second). */
181
                        udelay(100);
182
 
183
                        /* Power off the LCD panel. */
184
                        clps_writeb(clps_readb(PDDR) & ~EDB_PD2_LCDEN, PDDR);
185
 
186
                        /* Power off the LCD controller. */
187
                        clps_writel(clps_readl(SYSCON1) & ~SYSCON1_LCDEN,
188
                                        SYSCON1);
189
                }
190
        } else {
191
                if (machine_is_edb7211()) {
192
                        /* Power up the LCD controller. */
193
                        clps_writel(clps_readl(SYSCON1) | SYSCON1_LCDEN,
194
                                        SYSCON1);
195
 
196
                        /* Power up the LCD panel. */
197
                        clps_writeb(clps_readb(PDDR) | EDB_PD2_LCDEN, PDDR);
198
 
199
                        /* Delay for a little while. */
200
                        udelay(100);
201
 
202
                        /* Power up the LCD DC-DC converter. */
203
                        clps_writeb(clps_readb(PDDR) | EDB_PD1_LCD_DC_DC_EN,
204
                                        PDDR);
205
 
206
                        /* Turn on the LCD backlight. */
207
                        clps_writeb(clps_readb(PDDR) | EDB_PD3_LCDBL, PDDR);
208
                }
209
        }
210
        return 0;
211
}
212
 
213
static struct fb_ops clps7111fb_ops = {
214
        .owner          = THIS_MODULE,
215
        .fb_check_var   = clps7111fb_check_var,
216
        .fb_set_par     = clps7111fb_set_par,
217
        .fb_setcolreg   = clps7111fb_setcolreg,
218
        .fb_blank       = clps7111fb_blank,
219
        .fb_fillrect    = cfb_fillrect,
220
        .fb_copyarea    = cfb_copyarea,
221
        .fb_imageblit   = cfb_imageblit,
222
};
223
 
224
static int
225
clps7111fb_proc_backlight_read(char *page, char **start, off_t off,
226
                int count, int *eof, void *data)
227
{
228
        /* We need at least two characters, one for the digit, and one for
229
         * the terminating NULL. */
230
        if (count < 2)
231
                return -EINVAL;
232
 
233
        if (machine_is_edb7211()) {
234
                return sprintf(page, "%d\n",
235
                                (clps_readb(PDDR) & EDB_PD3_LCDBL) ? 1 : 0);
236
        }
237
 
238
        return 0;
239
}
240
 
241
static int
242
clps7111fb_proc_backlight_write(struct file *file, const char *buffer,
243
                unsigned long count, void *data)
244
{
245
        unsigned char char_value;
246
        int value;
247
 
248
        if (count < 1) {
249
                return -EINVAL;
250
        }
251
 
252
        if (copy_from_user(&char_value, buffer, 1))
253
                return -EFAULT;
254
 
255
        value = char_value - '0';
256
 
257
        if (machine_is_edb7211()) {
258
                unsigned char port_d;
259
 
260
                port_d = clps_readb(PDDR);
261
 
262
                if (value) {
263
                        port_d |= EDB_PD3_LCDBL;
264
                } else {
265
                        port_d &= ~EDB_PD3_LCDBL;
266
                }
267
 
268
                clps_writeb(port_d, PDDR);
269
        }
270
 
271
        return count;
272
}
273
 
274
static void __init clps711x_guess_lcd_params(struct fb_info *info)
275
{
276
        unsigned int lcdcon, syscon, size;
277
        unsigned long phys_base = PAGE_OFFSET;
278
        void *virt_base = (void *)PAGE_OFFSET;
279
 
280
        info->var.xres_virtual   = 640;
281
        info->var.yres_virtual   = 240;
282
        info->var.bits_per_pixel = 4;
283
        info->var.activate       = FB_ACTIVATE_NOW;
284
        info->var.height         = -1;
285
        info->var.width          = -1;
286
        info->var.pixclock       = 93006; /* 10.752MHz pixel clock */
287
 
288
        /*
289
         * If the LCD controller is already running, decode the values
290
         * in LCDCON to xres/yres/bpp/pixclock/acprescale
291
         */
292
        syscon = clps_readl(SYSCON1);
293
        if (syscon & SYSCON1_LCDEN) {
294
                lcdcon = clps_readl(LCDCON);
295
 
296
                /*
297
                 * Decode GSMD and GSEN bits to bits per pixel
298
                 */
299
                switch (lcdcon & (LCDCON_GSMD | LCDCON_GSEN)) {
300
                case LCDCON_GSMD | LCDCON_GSEN:
301
                        info->var.bits_per_pixel = 4;
302
                        break;
303
 
304
                case LCDCON_GSEN:
305
                        info->var.bits_per_pixel = 2;
306
                        break;
307
 
308
                default:
309
                        info->var.bits_per_pixel = 1;
310
                        break;
311
                }
312
 
313
                /*
314
                 * Decode xres/yres
315
                 */
316
                info->var.xres_virtual = (((lcdcon >> 13) & 0x3f) + 1) * 16;
317
                info->var.yres_virtual = (((lcdcon & 0x1fff) + 1) * 128) /
318
                                          (info->var.xres_virtual *
319
                                           info->var.bits_per_pixel);
320
 
321
                /*
322
                 * Calculate pixclock
323
                 */
324
                info->var.pixclock = (((lcdcon >> 19) & 0x3f) + 1) * 244140 / 9;
325
 
326
                /*
327
                 * Grab AC prescale
328
                 */
329
                lcd_ac_prescale = (lcdcon >> 25) & 0x1f;
330
        }
331
 
332
        info->var.xres = info->var.xres_virtual;
333
        info->var.yres = info->var.yres_virtual;
334
        info->var.grayscale = info->var.bits_per_pixel > 1;
335
 
336
        size = info->var.xres * info->var.yres * info->var.bits_per_pixel / 8;
337
 
338
        /*
339
         * Might be worth checking to see if we can use the on-board
340
         * RAM if size here...
341
         * CLPS7110 - no on-board SRAM
342
         * EP7212   - 38400 bytes
343
         */
344
        if (size <= 38400) {
345
                printk(KERN_INFO "CLPS711xFB: could use on-board SRAM?\n");
346
        }
347
 
348
        if ((syscon & SYSCON1_LCDEN) == 0) {
349
                /*
350
                 * The display isn't running.  Ensure that
351
                 * the display memory is empty.
352
                 */
353
                memset(virt_base, 0, size);
354
        }
355
 
356
        info->screen_base    = virt_base;
357
        info->fix.smem_start = phys_base;
358
        info->fix.smem_len   = PAGE_ALIGN(size);
359
        info->fix.type       = FB_TYPE_PACKED_PIXELS;
360
}
361
 
362
int __init clps711xfb_init(void)
363
{
364
        int err = -ENOMEM;
365
 
366
        if (fb_get_options("clps711xfb", NULL))
367
                return -ENODEV;
368
 
369
        cfb = kzalloc(sizeof(*cfb), GFP_KERNEL);
370
        if (!cfb)
371
                goto out;
372
 
373
        strcpy(cfb->fix.id, "clps711x");
374
 
375
        cfb->fbops              = &clps7111fb_ops;
376
        cfb->flags              = FBINFO_DEFAULT;
377
 
378
        clps711x_guess_lcd_params(cfb);
379
 
380
        fb_alloc_cmap(&cfb->cmap, CMAP_MAX_SIZE, 0);
381
 
382
        /* Register the /proc entries. */
383
        clps7111fb_backlight_proc_entry = create_proc_entry("backlight", 0444,
384
                &proc_root);
385
        if (clps7111fb_backlight_proc_entry == NULL) {
386
                printk("Couldn't create the /proc entry for the backlight.\n");
387
                return -EINVAL;
388
        }
389
 
390
        clps7111fb_backlight_proc_entry->read_proc =
391
                &clps7111fb_proc_backlight_read;
392
        clps7111fb_backlight_proc_entry->write_proc =
393
                &clps7111fb_proc_backlight_write;
394
 
395
        /*
396
         * Power up the LCD
397
         */
398
        if (machine_is_p720t()) {
399
                PLD_LCDEN = PLD_LCDEN_EN;
400
                PLD_PWR |= (PLD_S4_ON|PLD_S3_ON|PLD_S2_ON|PLD_S1_ON);
401
        }
402
 
403
        if (machine_is_edb7211()) {
404
                /* Power up the LCD panel. */
405
                clps_writeb(clps_readb(PDDR) | EDB_PD2_LCDEN, PDDR);
406
 
407
                /* Delay for a little while. */
408
                udelay(100);
409
 
410
                /* Power up the LCD DC-DC converter. */
411
                clps_writeb(clps_readb(PDDR) | EDB_PD1_LCD_DC_DC_EN, PDDR);
412
 
413
                /* Turn on the LCD backlight. */
414
                clps_writeb(clps_readb(PDDR) | EDB_PD3_LCDBL, PDDR);
415
        }
416
 
417
        err = register_framebuffer(cfb);
418
 
419
out:    return err;
420
}
421
 
422
static void __exit clps711xfb_exit(void)
423
{
424
        unregister_framebuffer(cfb);
425
        kfree(cfb);
426
 
427
        /*
428
         * Power down the LCD
429
         */
430
        if (machine_is_p720t()) {
431
                PLD_LCDEN = 0;
432
                PLD_PWR &= ~(PLD_S4_ON|PLD_S3_ON|PLD_S2_ON|PLD_S1_ON);
433
        }
434
}
435
 
436
module_init(clps711xfb_init);
437
module_exit(clps711xfb_exit);
438
 
439
MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
440
MODULE_DESCRIPTION("CLPS711x framebuffer driver");
441
MODULE_LICENSE("GPL");

powered by: WebSVN 2.1.0

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