aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/atmel_lcdfb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/atmel_lcdfb.c')
-rw-r--r--drivers/video/atmel_lcdfb.c165
1 files changed, 138 insertions, 27 deletions
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
index b004036d4087..75dac578104f 100644
--- a/drivers/video/atmel_lcdfb.c
+++ b/drivers/video/atmel_lcdfb.c
@@ -18,9 +18,9 @@
18#include <linux/delay.h> 18#include <linux/delay.h>
19#include <linux/backlight.h> 19#include <linux/backlight.h>
20 20
21#include <asm/arch/board.h> 21#include <mach/board.h>
22#include <asm/arch/cpu.h> 22#include <mach/cpu.h>
23#include <asm/arch/gpio.h> 23#include <mach/gpio.h>
24 24
25#include <video/atmel_lcdc.h> 25#include <video/atmel_lcdc.h>
26 26
@@ -39,7 +39,9 @@
39#endif 39#endif
40 40
41#if defined(CONFIG_ARCH_AT91) 41#if defined(CONFIG_ARCH_AT91)
42#define ATMEL_LCDFB_FBINFO_DEFAULT FBINFO_DEFAULT 42#define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \
43 | FBINFO_PARTIAL_PAN_OK \
44 | FBINFO_HWACCEL_YPAN)
43 45
44static inline void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo, 46static inline void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
45 struct fb_var_screeninfo *var) 47 struct fb_var_screeninfo *var)
@@ -177,7 +179,7 @@ static struct fb_fix_screeninfo atmel_lcdfb_fix __initdata = {
177 .type = FB_TYPE_PACKED_PIXELS, 179 .type = FB_TYPE_PACKED_PIXELS,
178 .visual = FB_VISUAL_TRUECOLOR, 180 .visual = FB_VISUAL_TRUECOLOR,
179 .xpanstep = 0, 181 .xpanstep = 0,
180 .ypanstep = 0, 182 .ypanstep = 1,
181 .ywrapstep = 0, 183 .ywrapstep = 0,
182 .accel = FB_ACCEL_NONE, 184 .accel = FB_ACCEL_NONE,
183}; 185};
@@ -206,6 +208,36 @@ static unsigned long compute_hozval(unsigned long xres, unsigned long lcdcon2)
206 return value; 208 return value;
207} 209}
208 210
211static void atmel_lcdfb_stop_nowait(struct atmel_lcdfb_info *sinfo)
212{
213 /* Turn off the LCD controller and the DMA controller */
214 lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
215 sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET);
216
217 /* Wait for the LCDC core to become idle */
218 while (lcdc_readl(sinfo, ATMEL_LCDC_PWRCON) & ATMEL_LCDC_BUSY)
219 msleep(10);
220
221 lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0);
222}
223
224static void atmel_lcdfb_stop(struct atmel_lcdfb_info *sinfo)
225{
226 atmel_lcdfb_stop_nowait(sinfo);
227
228 /* Wait for DMA engine to become idle... */
229 while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
230 msleep(10);
231}
232
233static void atmel_lcdfb_start(struct atmel_lcdfb_info *sinfo)
234{
235 lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon);
236 lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
237 (sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET)
238 | ATMEL_LCDC_PWR);
239}
240
209static void atmel_lcdfb_update_dma(struct fb_info *info, 241static void atmel_lcdfb_update_dma(struct fb_info *info,
210 struct fb_var_screeninfo *var) 242 struct fb_var_screeninfo *var)
211{ 243{
@@ -240,9 +272,11 @@ static int atmel_lcdfb_alloc_video_memory(struct atmel_lcdfb_info *sinfo)
240{ 272{
241 struct fb_info *info = sinfo->info; 273 struct fb_info *info = sinfo->info;
242 struct fb_var_screeninfo *var = &info->var; 274 struct fb_var_screeninfo *var = &info->var;
275 unsigned int smem_len;
243 276
244 info->fix.smem_len = (var->xres_virtual * var->yres_virtual 277 smem_len = (var->xres_virtual * var->yres_virtual
245 * ((var->bits_per_pixel + 7) / 8)); 278 * ((var->bits_per_pixel + 7) / 8));
279 info->fix.smem_len = max(smem_len, sinfo->smem_len);
246 280
247 info->screen_base = dma_alloc_writecombine(info->device, info->fix.smem_len, 281 info->screen_base = dma_alloc_writecombine(info->device, info->fix.smem_len,
248 (dma_addr_t *)&info->fix.smem_start, GFP_KERNEL); 282 (dma_addr_t *)&info->fix.smem_start, GFP_KERNEL);
@@ -256,6 +290,20 @@ static int atmel_lcdfb_alloc_video_memory(struct atmel_lcdfb_info *sinfo)
256 return 0; 290 return 0;
257} 291}
258 292
293static const struct fb_videomode *atmel_lcdfb_choose_mode(struct fb_var_screeninfo *var,
294 struct fb_info *info)
295{
296 struct fb_videomode varfbmode;
297 const struct fb_videomode *fbmode = NULL;
298
299 fb_var_to_videomode(&varfbmode, var);
300 fbmode = fb_find_nearest_mode(&varfbmode, &info->modelist);
301 if (fbmode)
302 fb_videomode_to_var(var, fbmode);
303 return fbmode;
304}
305
306
259/** 307/**
260 * atmel_lcdfb_check_var - Validates a var passed in. 308 * atmel_lcdfb_check_var - Validates a var passed in.
261 * @var: frame buffer variable screen structure 309 * @var: frame buffer variable screen structure
@@ -289,6 +337,15 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
289 clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000; 337 clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
290 338
291 dev_dbg(dev, "%s:\n", __func__); 339 dev_dbg(dev, "%s:\n", __func__);
340
341 if (!(var->pixclock && var->bits_per_pixel)) {
342 /* choose a suitable mode if possible */
343 if (!atmel_lcdfb_choose_mode(var, info)) {
344 dev_err(dev, "needed value not specified\n");
345 return -EINVAL;
346 }
347 }
348
292 dev_dbg(dev, " resolution: %ux%u\n", var->xres, var->yres); 349 dev_dbg(dev, " resolution: %ux%u\n", var->xres, var->yres);
293 dev_dbg(dev, " pixclk: %lu KHz\n", PICOS2KHZ(var->pixclock)); 350 dev_dbg(dev, " pixclk: %lu KHz\n", PICOS2KHZ(var->pixclock));
294 dev_dbg(dev, " bpp: %u\n", var->bits_per_pixel); 351 dev_dbg(dev, " bpp: %u\n", var->bits_per_pixel);
@@ -299,6 +356,13 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
299 return -EINVAL; 356 return -EINVAL;
300 } 357 }
301 358
359 /* Do not allow to have real resoulution larger than virtual */
360 if (var->xres > var->xres_virtual)
361 var->xres_virtual = var->xres;
362
363 if (var->yres > var->yres_virtual)
364 var->yres_virtual = var->yres;
365
302 /* Force same alignment for each line */ 366 /* Force same alignment for each line */
303 var->xres = (var->xres + 3) & ~3UL; 367 var->xres = (var->xres + 3) & ~3UL;
304 var->xres_virtual = (var->xres_virtual + 3) & ~3UL; 368 var->xres_virtual = (var->xres_virtual + 3) & ~3UL;
@@ -379,6 +443,17 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
379 return 0; 443 return 0;
380} 444}
381 445
446/*
447 * LCD reset sequence
448 */
449static void atmel_lcdfb_reset(struct atmel_lcdfb_info *sinfo)
450{
451 might_sleep();
452
453 atmel_lcdfb_stop(sinfo);
454 atmel_lcdfb_start(sinfo);
455}
456
382/** 457/**
383 * atmel_lcdfb_set_par - Alters the hardware state. 458 * atmel_lcdfb_set_par - Alters the hardware state.
384 * @info: frame buffer structure that represents a single frame buffer 459 * @info: frame buffer structure that represents a single frame buffer
@@ -401,19 +476,14 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
401 unsigned long clk_value_khz; 476 unsigned long clk_value_khz;
402 unsigned long bits_per_line; 477 unsigned long bits_per_line;
403 478
479 might_sleep();
480
404 dev_dbg(info->device, "%s:\n", __func__); 481 dev_dbg(info->device, "%s:\n", __func__);
405 dev_dbg(info->device, " * resolution: %ux%u (%ux%u virtual)\n", 482 dev_dbg(info->device, " * resolution: %ux%u (%ux%u virtual)\n",
406 info->var.xres, info->var.yres, 483 info->var.xres, info->var.yres,
407 info->var.xres_virtual, info->var.yres_virtual); 484 info->var.xres_virtual, info->var.yres_virtual);
408 485
409 /* Turn off the LCD controller and the DMA controller */ 486 atmel_lcdfb_stop_nowait(sinfo);
410 lcdc_writel(sinfo, ATMEL_LCDC_PWRCON, sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET);
411
412 /* Wait for the LCDC core to become idle */
413 while (lcdc_readl(sinfo, ATMEL_LCDC_PWRCON) & ATMEL_LCDC_BUSY)
414 msleep(10);
415
416 lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0);
417 487
418 if (info->var.bits_per_pixel == 1) 488 if (info->var.bits_per_pixel == 1)
419 info->fix.visual = FB_VISUAL_MONO01; 489 info->fix.visual = FB_VISUAL_MONO01;
@@ -511,18 +581,14 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
511 581
512 /* Disable all interrupts */ 582 /* Disable all interrupts */
513 lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL); 583 lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
584 /* Enable FIFO & DMA errors */
585 lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI);
514 586
515 /* ...wait for DMA engine to become idle... */ 587 /* ...wait for DMA engine to become idle... */
516 while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY) 588 while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
517 msleep(10); 589 msleep(10);
518 590
519 dev_dbg(info->device, " * re-enable DMA engine\n"); 591 atmel_lcdfb_start(sinfo);
520 /* ...and enable it with updated configuration */
521 lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon);
522
523 dev_dbg(info->device, " * re-enable LCDC core\n");
524 lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
525 (sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET) | ATMEL_LCDC_PWR);
526 592
527 dev_dbg(info->device, " * DONE\n"); 593 dev_dbg(info->device, " * DONE\n");
528 594
@@ -645,10 +711,26 @@ static irqreturn_t atmel_lcdfb_interrupt(int irq, void *dev_id)
645 u32 status; 711 u32 status;
646 712
647 status = lcdc_readl(sinfo, ATMEL_LCDC_ISR); 713 status = lcdc_readl(sinfo, ATMEL_LCDC_ISR);
648 lcdc_writel(sinfo, ATMEL_LCDC_IDR, status); 714 if (status & ATMEL_LCDC_UFLWI) {
715 dev_warn(info->device, "FIFO underflow %#x\n", status);
716 /* reset DMA and FIFO to avoid screen shifting */
717 schedule_work(&sinfo->task);
718 }
719 lcdc_writel(sinfo, ATMEL_LCDC_ICR, status);
649 return IRQ_HANDLED; 720 return IRQ_HANDLED;
650} 721}
651 722
723/*
724 * LCD controller task (to reset the LCD)
725 */
726static void atmel_lcdfb_task(struct work_struct *work)
727{
728 struct atmel_lcdfb_info *sinfo =
729 container_of(work, struct atmel_lcdfb_info, task);
730
731 atmel_lcdfb_reset(sinfo);
732}
733
652static int __init atmel_lcdfb_init_fbinfo(struct atmel_lcdfb_info *sinfo) 734static int __init atmel_lcdfb_init_fbinfo(struct atmel_lcdfb_info *sinfo)
653{ 735{
654 struct fb_info *info = sinfo->info; 736 struct fb_info *info = sinfo->info;
@@ -691,6 +773,7 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
691 struct fb_info *info; 773 struct fb_info *info;
692 struct atmel_lcdfb_info *sinfo; 774 struct atmel_lcdfb_info *sinfo;
693 struct atmel_lcdfb_info *pdata_sinfo; 775 struct atmel_lcdfb_info *pdata_sinfo;
776 struct fb_videomode fbmode;
694 struct resource *regs = NULL; 777 struct resource *regs = NULL;
695 struct resource *map = NULL; 778 struct resource *map = NULL;
696 int ret; 779 int ret;
@@ -714,6 +797,7 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
714 sinfo->default_monspecs = pdata_sinfo->default_monspecs; 797 sinfo->default_monspecs = pdata_sinfo->default_monspecs;
715 sinfo->atmel_lcdfb_power_control = pdata_sinfo->atmel_lcdfb_power_control; 798 sinfo->atmel_lcdfb_power_control = pdata_sinfo->atmel_lcdfb_power_control;
716 sinfo->guard_time = pdata_sinfo->guard_time; 799 sinfo->guard_time = pdata_sinfo->guard_time;
800 sinfo->smem_len = pdata_sinfo->smem_len;
717 sinfo->lcdcon_is_backlight = pdata_sinfo->lcdcon_is_backlight; 801 sinfo->lcdcon_is_backlight = pdata_sinfo->lcdcon_is_backlight;
718 sinfo->lcd_wiring_mode = pdata_sinfo->lcd_wiring_mode; 802 sinfo->lcd_wiring_mode = pdata_sinfo->lcd_wiring_mode;
719 } else { 803 } else {
@@ -824,6 +908,10 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
824 goto unmap_mmio; 908 goto unmap_mmio;
825 } 909 }
826 910
911 /* Some operations on the LCDC might sleep and
912 * require a preemptible task context */
913 INIT_WORK(&sinfo->task, atmel_lcdfb_task);
914
827 ret = atmel_lcdfb_init_fbinfo(sinfo); 915 ret = atmel_lcdfb_init_fbinfo(sinfo);
828 if (ret < 0) { 916 if (ret < 0) {
829 dev_err(dev, "init fbinfo failed: %d\n", ret); 917 dev_err(dev, "init fbinfo failed: %d\n", ret);
@@ -850,9 +938,13 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
850 ret = register_framebuffer(info); 938 ret = register_framebuffer(info);
851 if (ret < 0) { 939 if (ret < 0) {
852 dev_err(dev, "failed to register framebuffer device: %d\n", ret); 940 dev_err(dev, "failed to register framebuffer device: %d\n", ret);
853 goto free_cmap; 941 goto reset_drvdata;
854 } 942 }
855 943
944 /* add selected videomode to modelist */
945 fb_var_to_videomode(&fbmode, &info->var);
946 fb_add_videomode(&fbmode, &info->modelist);
947
856 /* Power up the LCDC screen */ 948 /* Power up the LCDC screen */
857 if (sinfo->atmel_lcdfb_power_control) 949 if (sinfo->atmel_lcdfb_power_control)
858 sinfo->atmel_lcdfb_power_control(1); 950 sinfo->atmel_lcdfb_power_control(1);
@@ -862,10 +954,12 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
862 954
863 return 0; 955 return 0;
864 956
865 957reset_drvdata:
958 dev_set_drvdata(dev, NULL);
866free_cmap: 959free_cmap:
867 fb_dealloc_cmap(&info->cmap); 960 fb_dealloc_cmap(&info->cmap);
868unregister_irqs: 961unregister_irqs:
962 cancel_work_sync(&sinfo->task);
869 free_irq(sinfo->irq_base, info); 963 free_irq(sinfo->irq_base, info);
870unmap_mmio: 964unmap_mmio:
871 exit_backlight(sinfo); 965 exit_backlight(sinfo);
@@ -898,11 +992,13 @@ static int __exit atmel_lcdfb_remove(struct platform_device *pdev)
898{ 992{
899 struct device *dev = &pdev->dev; 993 struct device *dev = &pdev->dev;
900 struct fb_info *info = dev_get_drvdata(dev); 994 struct fb_info *info = dev_get_drvdata(dev);
901 struct atmel_lcdfb_info *sinfo = info->par; 995 struct atmel_lcdfb_info *sinfo;
902 996
903 if (!sinfo) 997 if (!info || !info->par)
904 return 0; 998 return 0;
999 sinfo = info->par;
905 1000
1001 cancel_work_sync(&sinfo->task);
906 exit_backlight(sinfo); 1002 exit_backlight(sinfo);
907 if (sinfo->atmel_lcdfb_power_control) 1003 if (sinfo->atmel_lcdfb_power_control)
908 sinfo->atmel_lcdfb_power_control(0); 1004 sinfo->atmel_lcdfb_power_control(0);
@@ -935,11 +1031,20 @@ static int atmel_lcdfb_suspend(struct platform_device *pdev, pm_message_t mesg)
935 struct fb_info *info = platform_get_drvdata(pdev); 1031 struct fb_info *info = platform_get_drvdata(pdev);
936 struct atmel_lcdfb_info *sinfo = info->par; 1032 struct atmel_lcdfb_info *sinfo = info->par;
937 1033
1034 /*
1035 * We don't want to handle interrupts while the clock is
1036 * stopped. It may take forever.
1037 */
1038 lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
1039
938 sinfo->saved_lcdcon = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL); 1040 sinfo->saved_lcdcon = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
939 lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, 0); 1041 lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, 0);
940 if (sinfo->atmel_lcdfb_power_control) 1042 if (sinfo->atmel_lcdfb_power_control)
941 sinfo->atmel_lcdfb_power_control(0); 1043 sinfo->atmel_lcdfb_power_control(0);
1044
1045 atmel_lcdfb_stop(sinfo);
942 atmel_lcdfb_stop_clock(sinfo); 1046 atmel_lcdfb_stop_clock(sinfo);
1047
943 return 0; 1048 return 0;
944} 1049}
945 1050
@@ -949,9 +1054,15 @@ static int atmel_lcdfb_resume(struct platform_device *pdev)
949 struct atmel_lcdfb_info *sinfo = info->par; 1054 struct atmel_lcdfb_info *sinfo = info->par;
950 1055
951 atmel_lcdfb_start_clock(sinfo); 1056 atmel_lcdfb_start_clock(sinfo);
1057 atmel_lcdfb_start(sinfo);
952 if (sinfo->atmel_lcdfb_power_control) 1058 if (sinfo->atmel_lcdfb_power_control)
953 sinfo->atmel_lcdfb_power_control(1); 1059 sinfo->atmel_lcdfb_power_control(1);
954 lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, sinfo->saved_lcdcon); 1060 lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, sinfo->saved_lcdcon);
1061
1062 /* Enable FIFO & DMA errors */
1063 lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI
1064 | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI);
1065
955 return 0; 1066 return 0;
956} 1067}
957 1068