aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/da8xx-fb.c
diff options
context:
space:
mode:
authorSudhakar Rajashekhara <sudhakar.raj@ti.com>2009-09-22 19:47:06 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-09-23 10:39:50 -0400
commit4ed824d9aead77a6a4eb1e89c3b3d270ba386fad (patch)
treec5b1f863ca2a610ff893fd9ad301355ab5c3e108 /drivers/video/da8xx-fb.c
parent6e3658f0df6f708202159302b4f3915d9b97b8dc (diff)
davinci: fb: Frame Buffer driver for TI DA8xx/OMAP-L1xx
Add LCD controller (LCDC) driver for TI's DA8xx/OMAP-L1xx architecture. LCDC specifications can be found at http://www.ti.com/litv/pdf/sprufm0a. LCDC on DA8xx consists of two independent controllers, the Raster Controller and the LCD Interface Display Driver (LIDD) controller. LIDD further supports character and graphic displays. This patch adds support for the graphic display (Sharp LQ035Q3DG01) found on the DA830 based EVM. The EVM details can be found at: http://support.spectrumdigital.com/boards/dskda830/revc/. Signed-off-by: Sudhakar Rajashekhara <sudhakar.raj@ti.com> Signed-off-by: Pavel Kiryukhin <pkiryukhin@ru.mvista.com> Signed-off-by: Steve Chen <schen@mvista.com> Acked-by: Krzysztof Helt <krzysztof.h1@wp.pl> DESC davinci-fb-frame-buffer-driver-for-ti-da8xx-omap-l1xx-fix EDESC From: Andrew Morton <akpm@linux-foundation.org> fix kconfig indenting Cc: Krzysztof Helt <krzysztof.h1@wp.pl> Cc: Pavel Kiryukhin <pkiryukhin@ru.mvista.com> Cc: Steve Chen <schen@mvista.com> Cc: Sudhakar Rajashekhara <sudhakar.raj@ti.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/video/da8xx-fb.c')
-rw-r--r--drivers/video/da8xx-fb.c909
1 files changed, 909 insertions, 0 deletions
diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c
new file mode 100644
index 000000000000..e0bbc66499c8
--- /dev/null
+++ b/drivers/video/da8xx-fb.c
@@ -0,0 +1,909 @@
1/*
2 * Copyright (C) 2008-2009 MontaVista Software Inc.
3 * Copyright (C) 2008-2009 Texas Instruments Inc
4 *
5 * Based on the LCD driver for TI Avalanche processors written by
6 * Ajay Singh and Shalom Hai.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option)any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22#include <linux/module.h>
23#include <linux/kernel.h>
24#include <linux/fb.h>
25#include <linux/dma-mapping.h>
26#include <linux/device.h>
27#include <linux/platform_device.h>
28#include <linux/uaccess.h>
29#include <linux/device.h>
30#include <linux/interrupt.h>
31#include <linux/clk.h>
32#include <video/da8xx-fb.h>
33
34#define DRIVER_NAME "da8xx_lcdc"
35
36/* LCD Status Register */
37#define LCD_END_OF_FRAME0 BIT(8)
38#define LCD_FIFO_UNDERFLOW BIT(5)
39#define LCD_SYNC_LOST BIT(2)
40
41/* LCD DMA Control Register */
42#define LCD_DMA_BURST_SIZE(x) ((x) << 4)
43#define LCD_DMA_BURST_1 0x0
44#define LCD_DMA_BURST_2 0x1
45#define LCD_DMA_BURST_4 0x2
46#define LCD_DMA_BURST_8 0x3
47#define LCD_DMA_BURST_16 0x4
48#define LCD_END_OF_FRAME_INT_ENA BIT(2)
49#define LCD_DUAL_FRAME_BUFFER_ENABLE BIT(0)
50
51/* LCD Control Register */
52#define LCD_CLK_DIVISOR(x) ((x) << 8)
53#define LCD_RASTER_MODE 0x01
54
55/* LCD Raster Control Register */
56#define LCD_PALETTE_LOAD_MODE(x) ((x) << 20)
57#define PALETTE_AND_DATA 0x00
58#define PALETTE_ONLY 0x01
59
60#define LCD_MONO_8BIT_MODE BIT(9)
61#define LCD_RASTER_ORDER BIT(8)
62#define LCD_TFT_MODE BIT(7)
63#define LCD_UNDERFLOW_INT_ENA BIT(6)
64#define LCD_MONOCHROME_MODE BIT(1)
65#define LCD_RASTER_ENABLE BIT(0)
66#define LCD_TFT_ALT_ENABLE BIT(23)
67#define LCD_STN_565_ENABLE BIT(24)
68
69/* LCD Raster Timing 2 Register */
70#define LCD_AC_BIAS_TRANSITIONS_PER_INT(x) ((x) << 16)
71#define LCD_AC_BIAS_FREQUENCY(x) ((x) << 8)
72#define LCD_SYNC_CTRL BIT(25)
73#define LCD_SYNC_EDGE BIT(24)
74#define LCD_INVERT_PIXEL_CLOCK BIT(22)
75#define LCD_INVERT_LINE_CLOCK BIT(21)
76#define LCD_INVERT_FRAME_CLOCK BIT(20)
77
78/* LCD Block */
79#define LCD_CTRL_REG 0x4
80#define LCD_STAT_REG 0x8
81#define LCD_RASTER_CTRL_REG 0x28
82#define LCD_RASTER_TIMING_0_REG 0x2C
83#define LCD_RASTER_TIMING_1_REG 0x30
84#define LCD_RASTER_TIMING_2_REG 0x34
85#define LCD_DMA_CTRL_REG 0x40
86#define LCD_DMA_FRM_BUF_BASE_ADDR_0_REG 0x44
87#define LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG 0x48
88
89#define WSI_TIMEOUT 50
90#define PALETTE_SIZE 256
91#define LEFT_MARGIN 64
92#define RIGHT_MARGIN 64
93#define UPPER_MARGIN 32
94#define LOWER_MARGIN 32
95
96static resource_size_t da8xx_fb_reg_base;
97static struct resource *lcdc_regs;
98
99static inline unsigned int lcdc_read(unsigned int addr)
100{
101 return (unsigned int)__raw_readl(da8xx_fb_reg_base + (addr));
102}
103
104static inline void lcdc_write(unsigned int val, unsigned int addr)
105{
106 __raw_writel(val, da8xx_fb_reg_base + (addr));
107}
108
109struct da8xx_fb_par {
110 wait_queue_head_t da8xx_wq;
111 resource_size_t p_palette_base;
112 unsigned char *v_palette_base;
113 struct clk *lcdc_clk;
114 int irq;
115 unsigned short pseudo_palette[16];
116 unsigned int databuf_sz;
117 unsigned int palette_sz;
118};
119
120/* Variable Screen Information */
121static struct fb_var_screeninfo da8xx_fb_var __devinitdata = {
122 .xoffset = 0,
123 .yoffset = 0,
124 .transp = {0, 0, 0},
125 .nonstd = 0,
126 .activate = 0,
127 .height = -1,
128 .width = -1,
129 .pixclock = 46666, /* 46us - AUO display */
130 .accel_flags = 0,
131 .left_margin = LEFT_MARGIN,
132 .right_margin = RIGHT_MARGIN,
133 .upper_margin = UPPER_MARGIN,
134 .lower_margin = LOWER_MARGIN,
135 .sync = 0,
136 .vmode = FB_VMODE_NONINTERLACED
137};
138
139static struct fb_fix_screeninfo da8xx_fb_fix __devinitdata = {
140 .id = "DA8xx FB Drv",
141 .type = FB_TYPE_PACKED_PIXELS,
142 .type_aux = 0,
143 .visual = FB_VISUAL_PSEUDOCOLOR,
144 .xpanstep = 1,
145 .ypanstep = 1,
146 .ywrapstep = 1,
147 .accel = FB_ACCEL_NONE
148};
149
150struct da8xx_panel {
151 const char name[25]; /* Full name <vendor>_<model> */
152 unsigned short width;
153 unsigned short height;
154 int hfp; /* Horizontal front porch */
155 int hbp; /* Horizontal back porch */
156 int hsw; /* Horizontal Sync Pulse Width */
157 int vfp; /* Vertical front porch */
158 int vbp; /* Vertical back porch */
159 int vsw; /* Vertical Sync Pulse Width */
160 int pxl_clk; /* Pixel clock */
161};
162
163static struct da8xx_panel known_lcd_panels[] = {
164 /* Sharp LCD035Q3DG01 */
165 [0] = {
166 .name = "Sharp_LCD035Q3DG01",
167 .width = 320,
168 .height = 240,
169 .hfp = 8,
170 .hbp = 6,
171 .hsw = 0,
172 .vfp = 2,
173 .vbp = 2,
174 .vsw = 0,
175 .pxl_clk = 0x10,
176 },
177 /* Sharp LK043T1DG01 */
178 [1] = {
179 .name = "Sharp_LK043T1DG01",
180 .width = 480,
181 .height = 272,
182 .hfp = 2,
183 .hbp = 2,
184 .hsw = 41,
185 .vfp = 2,
186 .vbp = 2,
187 .vsw = 10,
188 .pxl_clk = 0x12,
189 },
190};
191
192/* Disable the Raster Engine of the LCD Controller */
193static int lcd_disable_raster(struct da8xx_fb_par *par)
194{
195 int ret = 0;
196 u32 reg;
197
198 reg = lcdc_read(LCD_RASTER_CTRL_REG);
199 if (reg & LCD_RASTER_ENABLE) {
200 lcdc_write(reg & ~LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG);
201 ret = wait_event_interruptible_timeout(par->da8xx_wq,
202 !lcdc_read(LCD_STAT_REG) &
203 LCD_END_OF_FRAME0, WSI_TIMEOUT);
204 }
205
206 if (ret < 0)
207 return ret;
208 if (ret == 0)
209 return -ETIMEDOUT;
210
211 return 0;
212}
213
214static void lcd_blit(int load_mode, struct da8xx_fb_par *par)
215{
216 u32 tmp = par->p_palette_base + par->databuf_sz - 4;
217 u32 reg;
218
219 /* Update the databuf in the hw. */
220 lcdc_write(par->p_palette_base, LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
221 lcdc_write(tmp, LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG);
222
223 /* Start the DMA. */
224 reg = lcdc_read(LCD_RASTER_CTRL_REG);
225 reg &= ~(3 << 20);
226 if (load_mode == LOAD_DATA)
227 reg |= LCD_PALETTE_LOAD_MODE(PALETTE_AND_DATA);
228 else if (load_mode == LOAD_PALETTE)
229 reg |= LCD_PALETTE_LOAD_MODE(PALETTE_ONLY);
230
231 lcdc_write(reg, LCD_RASTER_CTRL_REG);
232}
233
234/* Configure the Burst Size of DMA */
235static int lcd_cfg_dma(int burst_size)
236{
237 u32 reg;
238
239 reg = lcdc_read(LCD_DMA_CTRL_REG) & 0x00000001;
240 switch (burst_size) {
241 case 1:
242 reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_1);
243 break;
244 case 2:
245 reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_2);
246 break;
247 case 4:
248 reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_4);
249 break;
250 case 8:
251 reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_8);
252 break;
253 case 16:
254 reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_16);
255 break;
256 default:
257 return -EINVAL;
258 }
259 lcdc_write(reg | LCD_END_OF_FRAME_INT_ENA, LCD_DMA_CTRL_REG);
260
261 return 0;
262}
263
264static void lcd_cfg_ac_bias(int period, int transitions_per_int)
265{
266 u32 reg;
267
268 /* Set the AC Bias Period and Number of Transisitons per Interrupt */
269 reg = lcdc_read(LCD_RASTER_TIMING_2_REG) & 0xFFF00000;
270 reg |= LCD_AC_BIAS_FREQUENCY(period) |
271 LCD_AC_BIAS_TRANSITIONS_PER_INT(transitions_per_int);
272 lcdc_write(reg, LCD_RASTER_TIMING_2_REG);
273}
274
275static void lcd_cfg_horizontal_sync(int back_porch, int pulse_width,
276 int front_porch)
277{
278 u32 reg;
279
280 reg = lcdc_read(LCD_RASTER_TIMING_0_REG) & 0xf;
281 reg |= ((back_porch & 0xff) << 24)
282 | ((front_porch & 0xff) << 16)
283 | ((pulse_width & 0x3f) << 10);
284 lcdc_write(reg, LCD_RASTER_TIMING_0_REG);
285}
286
287static void lcd_cfg_vertical_sync(int back_porch, int pulse_width,
288 int front_porch)
289{
290 u32 reg;
291
292 reg = lcdc_read(LCD_RASTER_TIMING_1_REG) & 0x3ff;
293 reg |= ((back_porch & 0xff) << 24)
294 | ((front_porch & 0xff) << 16)
295 | ((pulse_width & 0x3f) << 10);
296 lcdc_write(reg, LCD_RASTER_TIMING_1_REG);
297}
298
299static int lcd_cfg_display(const struct lcd_ctrl_config *cfg)
300{
301 u32 reg;
302
303 reg = lcdc_read(LCD_RASTER_CTRL_REG) & ~(LCD_TFT_MODE |
304 LCD_MONO_8BIT_MODE |
305 LCD_MONOCHROME_MODE);
306
307 switch (cfg->p_disp_panel->panel_shade) {
308 case MONOCHROME:
309 reg |= LCD_MONOCHROME_MODE;
310 if (cfg->mono_8bit_mode)
311 reg |= LCD_MONO_8BIT_MODE;
312 break;
313 case COLOR_ACTIVE:
314 reg |= LCD_TFT_MODE;
315 if (cfg->tft_alt_mode)
316 reg |= LCD_TFT_ALT_ENABLE;
317 break;
318
319 case COLOR_PASSIVE:
320 if (cfg->stn_565_mode)
321 reg |= LCD_STN_565_ENABLE;
322 break;
323
324 default:
325 return -EINVAL;
326 }
327
328 /* enable additional interrupts here */
329 reg |= LCD_UNDERFLOW_INT_ENA;
330
331 lcdc_write(reg, LCD_RASTER_CTRL_REG);
332
333 reg = lcdc_read(LCD_RASTER_TIMING_2_REG);
334
335 if (cfg->sync_ctrl)
336 reg |= LCD_SYNC_CTRL;
337 else
338 reg &= ~LCD_SYNC_CTRL;
339
340 if (cfg->sync_edge)
341 reg |= LCD_SYNC_EDGE;
342 else
343 reg &= ~LCD_SYNC_EDGE;
344
345 if (cfg->invert_pxl_clock)
346 reg |= LCD_INVERT_PIXEL_CLOCK;
347 else
348 reg &= ~LCD_INVERT_PIXEL_CLOCK;
349
350 if (cfg->invert_line_clock)
351 reg |= LCD_INVERT_LINE_CLOCK;
352 else
353 reg &= ~LCD_INVERT_LINE_CLOCK;
354
355 if (cfg->invert_frm_clock)
356 reg |= LCD_INVERT_FRAME_CLOCK;
357 else
358 reg &= ~LCD_INVERT_FRAME_CLOCK;
359
360 lcdc_write(reg, LCD_RASTER_TIMING_2_REG);
361
362 return 0;
363}
364
365static int lcd_cfg_frame_buffer(struct da8xx_fb_par *par, u32 width, u32 height,
366 u32 bpp, u32 raster_order)
367{
368 u32 bpl, reg;
369
370 /* Disable Dual Frame Buffer. */
371 reg = lcdc_read(LCD_DMA_CTRL_REG);
372 lcdc_write(reg & ~LCD_DUAL_FRAME_BUFFER_ENABLE,
373 LCD_DMA_CTRL_REG);
374 /* Set the Panel Width */
375 /* Pixels per line = (PPL + 1)*16 */
376 /*0x3F in bits 4..9 gives max horisontal resolution = 1024 pixels*/
377 width &= 0x3f0;
378 reg = lcdc_read(LCD_RASTER_TIMING_0_REG);
379 reg &= 0xfffffc00;
380 reg |= ((width >> 4) - 1) << 4;
381 lcdc_write(reg, LCD_RASTER_TIMING_0_REG);
382
383 /* Set the Panel Height */
384 reg = lcdc_read(LCD_RASTER_TIMING_1_REG);
385 reg = ((height - 1) & 0x3ff) | (reg & 0xfffffc00);
386 lcdc_write(reg, LCD_RASTER_TIMING_1_REG);
387
388 /* Set the Raster Order of the Frame Buffer */
389 reg = lcdc_read(LCD_RASTER_CTRL_REG) & ~(1 << 8);
390 if (raster_order)
391 reg |= LCD_RASTER_ORDER;
392 lcdc_write(reg, LCD_RASTER_CTRL_REG);
393
394 switch (bpp) {
395 case 1:
396 case 2:
397 case 4:
398 case 16:
399 par->palette_sz = 16 * 2;
400 break;
401
402 case 8:
403 par->palette_sz = 256 * 2;
404 break;
405
406 default:
407 return -EINVAL;
408 }
409
410 bpl = width * bpp / 8;
411 par->databuf_sz = height * bpl + par->palette_sz;
412
413 return 0;
414}
415
416static int fb_setcolreg(unsigned regno, unsigned red, unsigned green,
417 unsigned blue, unsigned transp,
418 struct fb_info *info)
419{
420 struct da8xx_fb_par *par = info->par;
421 unsigned short *palette = (unsigned short *)par->v_palette_base;
422 u_short pal;
423
424 if (regno > 255)
425 return 1;
426
427 if (info->fix.visual == FB_VISUAL_DIRECTCOLOR)
428 return 1;
429
430 if (info->var.bits_per_pixel == 8) {
431 red >>= 4;
432 green >>= 8;
433 blue >>= 12;
434
435 pal = (red & 0x0f00);
436 pal |= (green & 0x00f0);
437 pal |= (blue & 0x000f);
438
439 palette[regno] = pal;
440
441 } else if ((info->var.bits_per_pixel == 16) && regno < 16) {
442 red >>= (16 - info->var.red.length);
443 red <<= info->var.red.offset;
444
445 green >>= (16 - info->var.green.length);
446 green <<= info->var.green.offset;
447
448 blue >>= (16 - info->var.blue.length);
449 blue <<= info->var.blue.offset;
450
451 par->pseudo_palette[regno] = red | green | blue;
452
453 palette[0] = 0x4000;
454 }
455
456 return 0;
457}
458
459static int lcd_reset(struct da8xx_fb_par *par)
460{
461 int ret = 0;
462
463 /* Disable the Raster if previously Enabled */
464 if (lcdc_read(LCD_RASTER_CTRL_REG) & LCD_RASTER_ENABLE)
465 ret = lcd_disable_raster(par);
466
467 /* DMA has to be disabled */
468 lcdc_write(0, LCD_DMA_CTRL_REG);
469 lcdc_write(0, LCD_RASTER_CTRL_REG);
470
471 return ret;
472}
473
474static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg,
475 struct da8xx_panel *panel)
476{
477 u32 bpp;
478 int ret = 0;
479
480 ret = lcd_reset(par);
481 if (ret != 0)
482 return ret;
483
484 /* Configure the LCD clock divisor. */
485 lcdc_write(LCD_CLK_DIVISOR(panel->pxl_clk) |
486 (LCD_RASTER_MODE & 0x1), LCD_CTRL_REG);
487
488 /* Configure the DMA burst size. */
489 ret = lcd_cfg_dma(cfg->dma_burst_sz);
490 if (ret < 0)
491 return ret;
492
493 /* Configure the AC bias properties. */
494 lcd_cfg_ac_bias(cfg->ac_bias, cfg->ac_bias_intrpt);
495
496 /* Configure the vertical and horizontal sync properties. */
497 lcd_cfg_vertical_sync(panel->vbp, panel->vsw, panel->vfp);
498 lcd_cfg_horizontal_sync(panel->hbp, panel->hsw, panel->hfp);
499
500 /* Configure for disply */
501 ret = lcd_cfg_display(cfg);
502 if (ret < 0)
503 return ret;
504
505 if (QVGA != cfg->p_disp_panel->panel_type)
506 return -EINVAL;
507
508 if (cfg->bpp <= cfg->p_disp_panel->max_bpp &&
509 cfg->bpp >= cfg->p_disp_panel->min_bpp)
510 bpp = cfg->bpp;
511 else
512 bpp = cfg->p_disp_panel->max_bpp;
513 if (bpp == 12)
514 bpp = 16;
515 ret = lcd_cfg_frame_buffer(par, (unsigned int)panel->width,
516 (unsigned int)panel->height, bpp,
517 cfg->raster_order);
518 if (ret < 0)
519 return ret;
520
521 /* Configure FDD */
522 lcdc_write((lcdc_read(LCD_RASTER_CTRL_REG) & 0xfff00fff) |
523 (cfg->fdd << 12), LCD_RASTER_CTRL_REG);
524
525 return 0;
526}
527
528static irqreturn_t lcdc_irq_handler(int irq, void *arg)
529{
530 u32 stat = lcdc_read(LCD_STAT_REG);
531 struct da8xx_fb_par *par = arg;
532 u32 reg;
533
534 if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) {
535 reg = lcdc_read(LCD_RASTER_CTRL_REG);
536 lcdc_write(reg & ~LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG);
537 lcdc_write(stat, LCD_STAT_REG);
538 lcdc_write(reg | LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG);
539 } else
540 lcdc_write(stat, LCD_STAT_REG);
541
542 wake_up_interruptible(&par->da8xx_wq);
543 return IRQ_HANDLED;
544}
545
546static int fb_check_var(struct fb_var_screeninfo *var,
547 struct fb_info *info)
548{
549 int err = 0;
550
551 switch (var->bits_per_pixel) {
552 case 1:
553 case 8:
554 var->red.offset = 0;
555 var->red.length = 8;
556 var->green.offset = 0;
557 var->green.length = 8;
558 var->blue.offset = 0;
559 var->blue.length = 8;
560 var->transp.offset = 0;
561 var->transp.length = 0;
562 break;
563 case 4:
564 var->red.offset = 0;
565 var->red.length = 4;
566 var->green.offset = 0;
567 var->green.length = 4;
568 var->blue.offset = 0;
569 var->blue.length = 4;
570 var->transp.offset = 0;
571 var->transp.length = 0;
572 break;
573 case 16: /* RGB 565 */
574 var->red.offset = 0;
575 var->red.length = 5;
576 var->green.offset = 5;
577 var->green.length = 6;
578 var->blue.offset = 11;
579 var->blue.length = 5;
580 var->transp.offset = 0;
581 var->transp.length = 0;
582 break;
583 default:
584 err = -EINVAL;
585 }
586
587 var->red.msb_right = 0;
588 var->green.msb_right = 0;
589 var->blue.msb_right = 0;
590 var->transp.msb_right = 0;
591 return err;
592}
593
594static int __devexit fb_remove(struct platform_device *dev)
595{
596 struct fb_info *info = dev_get_drvdata(&dev->dev);
597 int ret = 0;
598
599 if (info) {
600 struct da8xx_fb_par *par = info->par;
601
602 if (lcdc_read(LCD_RASTER_CTRL_REG) & LCD_RASTER_ENABLE)
603 ret = lcd_disable_raster(par);
604 lcdc_write(0, LCD_RASTER_CTRL_REG);
605
606 /* disable DMA */
607 lcdc_write(0, LCD_DMA_CTRL_REG);
608
609 unregister_framebuffer(info);
610 fb_dealloc_cmap(&info->cmap);
611 dma_free_coherent(NULL, par->databuf_sz + PAGE_SIZE,
612 info->screen_base,
613 info->fix.smem_start);
614 free_irq(par->irq, par);
615 clk_disable(par->lcdc_clk);
616 clk_put(par->lcdc_clk);
617 framebuffer_release(info);
618 iounmap((void __iomem *)da8xx_fb_reg_base);
619 release_mem_region(lcdc_regs->start, resource_size(lcdc_regs));
620
621 }
622 return ret;
623}
624
625static int fb_ioctl(struct fb_info *info, unsigned int cmd,
626 unsigned long arg)
627{
628 struct lcd_sync_arg sync_arg;
629
630 switch (cmd) {
631 case FBIOGET_CONTRAST:
632 case FBIOPUT_CONTRAST:
633 case FBIGET_BRIGHTNESS:
634 case FBIPUT_BRIGHTNESS:
635 case FBIGET_COLOR:
636 case FBIPUT_COLOR:
637 return -EINVAL;
638 case FBIPUT_HSYNC:
639 if (copy_from_user(&sync_arg, (char *)arg,
640 sizeof(struct lcd_sync_arg)))
641 return -EINVAL;
642 lcd_cfg_horizontal_sync(sync_arg.back_porch,
643 sync_arg.pulse_width,
644 sync_arg.front_porch);
645 break;
646 case FBIPUT_VSYNC:
647 if (copy_from_user(&sync_arg, (char *)arg,
648 sizeof(struct lcd_sync_arg)))
649 return -EINVAL;
650 lcd_cfg_vertical_sync(sync_arg.back_porch,
651 sync_arg.pulse_width,
652 sync_arg.front_porch);
653 break;
654 default:
655 return -EINVAL;
656 }
657 return 0;
658}
659
660static struct fb_ops da8xx_fb_ops = {
661 .owner = THIS_MODULE,
662 .fb_check_var = fb_check_var,
663 .fb_setcolreg = fb_setcolreg,
664 .fb_ioctl = fb_ioctl,
665 .fb_fillrect = cfb_fillrect,
666 .fb_copyarea = cfb_copyarea,
667 .fb_imageblit = cfb_imageblit,
668};
669
670static int __init fb_probe(struct platform_device *device)
671{
672 struct da8xx_lcdc_platform_data *fb_pdata =
673 device->dev.platform_data;
674 struct lcd_ctrl_config *lcd_cfg;
675 struct da8xx_panel *lcdc_info;
676 struct fb_info *da8xx_fb_info;
677 struct clk *fb_clk = NULL;
678 struct da8xx_fb_par *par;
679 resource_size_t len;
680 int ret, i;
681
682 if (fb_pdata == NULL) {
683 dev_err(&device->dev, "Can not get platform data\n");
684 return -ENOENT;
685 }
686
687 lcdc_regs = platform_get_resource(device, IORESOURCE_MEM, 0);
688 if (!lcdc_regs) {
689 dev_err(&device->dev,
690 "Can not get memory resource for LCD controller\n");
691 return -ENOENT;
692 }
693
694 len = resource_size(lcdc_regs);
695
696 lcdc_regs = request_mem_region(lcdc_regs->start, len, lcdc_regs->name);
697 if (!lcdc_regs)
698 return -EBUSY;
699
700 da8xx_fb_reg_base = (resource_size_t)ioremap(lcdc_regs->start, len);
701 if (!da8xx_fb_reg_base) {
702 ret = -EBUSY;
703 goto err_request_mem;
704 }
705
706 fb_clk = clk_get(&device->dev, NULL);
707 if (IS_ERR(fb_clk)) {
708 dev_err(&device->dev, "Can not get device clock\n");
709 ret = -ENODEV;
710 goto err_ioremap;
711 }
712 ret = clk_enable(fb_clk);
713 if (ret)
714 goto err_clk_put;
715
716 for (i = 0, lcdc_info = known_lcd_panels;
717 i < ARRAY_SIZE(known_lcd_panels);
718 i++, lcdc_info++) {
719 if (strcmp(fb_pdata->type, lcdc_info->name) == 0)
720 break;
721 }
722
723 if (i == ARRAY_SIZE(known_lcd_panels)) {
724 dev_err(&device->dev, "GLCD: No valid panel found\n");
725 ret = ENODEV;
726 goto err_clk_disable;
727 } else
728 dev_info(&device->dev, "GLCD: Found %s panel\n",
729 fb_pdata->type);
730
731 lcd_cfg = (struct lcd_ctrl_config *)fb_pdata->controller_data;
732
733 da8xx_fb_info = framebuffer_alloc(sizeof(struct da8xx_fb_par),
734 &device->dev);
735 if (!da8xx_fb_info) {
736 dev_dbg(&device->dev, "Memory allocation failed for fb_info\n");
737 ret = -ENOMEM;
738 goto err_clk_disable;
739 }
740
741 par = da8xx_fb_info->par;
742
743 if (lcd_init(par, lcd_cfg, lcdc_info) < 0) {
744 dev_err(&device->dev, "lcd_init failed\n");
745 ret = -EFAULT;
746 goto err_release_fb;
747 }
748
749 /* allocate frame buffer */
750 da8xx_fb_info->screen_base = dma_alloc_coherent(NULL,
751 par->databuf_sz + PAGE_SIZE,
752 (resource_size_t *)
753 &da8xx_fb_info->fix.smem_start,
754 GFP_KERNEL | GFP_DMA);
755
756 if (!da8xx_fb_info->screen_base) {
757 dev_err(&device->dev,
758 "GLCD: kmalloc for frame buffer failed\n");
759 ret = -EINVAL;
760 goto err_release_fb;
761 }
762
763 /* move palette base pointer by (PAGE_SIZE - palette_sz) bytes */
764 par->v_palette_base = da8xx_fb_info->screen_base +
765 (PAGE_SIZE - par->palette_sz);
766 par->p_palette_base = da8xx_fb_info->fix.smem_start +
767 (PAGE_SIZE - par->palette_sz);
768
769 /* the rest of the frame buffer is pixel data */
770 da8xx_fb_fix.smem_start = par->p_palette_base + par->palette_sz;
771 da8xx_fb_fix.smem_len = par->databuf_sz - par->palette_sz;
772 da8xx_fb_fix.line_length = (lcdc_info->width * lcd_cfg->bpp) / 8;
773
774 par->lcdc_clk = fb_clk;
775
776 init_waitqueue_head(&par->da8xx_wq);
777
778 par->irq = platform_get_irq(device, 0);
779 if (par->irq < 0) {
780 ret = -ENOENT;
781 goto err_release_fb_mem;
782 }
783
784 ret = request_irq(par->irq, lcdc_irq_handler, 0, DRIVER_NAME, par);
785 if (ret)
786 goto err_release_fb_mem;
787
788 /* Initialize par */
789 da8xx_fb_info->var.bits_per_pixel = lcd_cfg->bpp;
790
791 da8xx_fb_var.xres = lcdc_info->width;
792 da8xx_fb_var.xres_virtual = lcdc_info->width;
793
794 da8xx_fb_var.yres = lcdc_info->height;
795 da8xx_fb_var.yres_virtual = lcdc_info->height;
796
797 da8xx_fb_var.grayscale =
798 lcd_cfg->p_disp_panel->panel_shade == MONOCHROME ? 1 : 0;
799 da8xx_fb_var.bits_per_pixel = lcd_cfg->bpp;
800
801 da8xx_fb_var.hsync_len = lcdc_info->hsw;
802 da8xx_fb_var.vsync_len = lcdc_info->vsw;
803
804 /* Initialize fbinfo */
805 da8xx_fb_info->flags = FBINFO_FLAG_DEFAULT;
806 da8xx_fb_info->fix = da8xx_fb_fix;
807 da8xx_fb_info->var = da8xx_fb_var;
808 da8xx_fb_info->fbops = &da8xx_fb_ops;
809 da8xx_fb_info->pseudo_palette = par->pseudo_palette;
810
811 ret = fb_alloc_cmap(&da8xx_fb_info->cmap, PALETTE_SIZE, 0);
812 if (ret)
813 goto err_free_irq;
814
815 /* First palette_sz byte of the frame buffer is the palette */
816 da8xx_fb_info->cmap.len = par->palette_sz;
817
818 /* Flush the buffer to the screen. */
819 lcd_blit(LOAD_DATA, par);
820
821 /* initialize var_screeninfo */
822 da8xx_fb_var.activate = FB_ACTIVATE_FORCE;
823 fb_set_var(da8xx_fb_info, &da8xx_fb_var);
824
825 dev_set_drvdata(&device->dev, da8xx_fb_info);
826 /* Register the Frame Buffer */
827 if (register_framebuffer(da8xx_fb_info) < 0) {
828 dev_err(&device->dev,
829 "GLCD: Frame Buffer Registration Failed!\n");
830 ret = -EINVAL;
831 goto err_dealloc_cmap;
832 }
833
834 /* enable raster engine */
835 lcdc_write(lcdc_read(LCD_RASTER_CTRL_REG) |
836 LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG);
837
838 return 0;
839
840err_dealloc_cmap:
841 fb_dealloc_cmap(&da8xx_fb_info->cmap);
842
843err_free_irq:
844 free_irq(par->irq, par);
845
846err_release_fb_mem:
847 dma_free_coherent(NULL, par->databuf_sz + PAGE_SIZE,
848 da8xx_fb_info->screen_base,
849 da8xx_fb_info->fix.smem_start);
850
851err_release_fb:
852 framebuffer_release(da8xx_fb_info);
853
854err_clk_disable:
855 clk_disable(fb_clk);
856
857err_clk_put:
858 clk_put(fb_clk);
859
860err_ioremap:
861 iounmap((void __iomem *)da8xx_fb_reg_base);
862
863err_request_mem:
864 release_mem_region(lcdc_regs->start, len);
865
866 return ret;
867}
868
869#ifdef CONFIG_PM
870static int fb_suspend(struct platform_device *dev, pm_message_t state)
871{
872 return -EBUSY;
873}
874static int fb_resume(struct platform_device *dev)
875{
876 return -EBUSY;
877}
878#else
879#define fb_suspend NULL
880#define fb_resume NULL
881#endif
882
883static struct platform_driver da8xx_fb_driver = {
884 .probe = fb_probe,
885 .remove = fb_remove,
886 .suspend = fb_suspend,
887 .resume = fb_resume,
888 .driver = {
889 .name = DRIVER_NAME,
890 .owner = THIS_MODULE,
891 },
892};
893
894static int __init da8xx_fb_init(void)
895{
896 return platform_driver_register(&da8xx_fb_driver);
897}
898
899static void __exit da8xx_fb_cleanup(void)
900{
901 platform_driver_unregister(&da8xx_fb_driver);
902}
903
904module_init(da8xx_fb_init);
905module_exit(da8xx_fb_cleanup);
906
907MODULE_DESCRIPTION("Framebuffer driver for TI da8xx/omap-l1xx");
908MODULE_AUTHOR("Texas Instruments");
909MODULE_LICENSE("GPL");