aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/sh_mobile_lcdcfb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/sh_mobile_lcdcfb.c')
-rw-r--r--drivers/video/sh_mobile_lcdcfb.c91
1 files changed, 68 insertions, 23 deletions
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index f10d2fbeda06..8f24564f77b0 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -17,6 +17,7 @@
17#include <linux/platform_device.h> 17#include <linux/platform_device.h>
18#include <linux/dma-mapping.h> 18#include <linux/dma-mapping.h>
19#include <linux/interrupt.h> 19#include <linux/interrupt.h>
20#include <linux/vmalloc.h>
20#include <video/sh_mobile_lcdc.h> 21#include <video/sh_mobile_lcdc.h>
21#include <asm/atomic.h> 22#include <asm/atomic.h>
22 23
@@ -30,9 +31,10 @@ struct sh_mobile_lcdc_chan {
30 unsigned long enabled; /* ME and SE in LDCNT2R */ 31 unsigned long enabled; /* ME and SE in LDCNT2R */
31 struct sh_mobile_lcdc_chan_cfg cfg; 32 struct sh_mobile_lcdc_chan_cfg cfg;
32 u32 pseudo_palette[PALETTE_NR]; 33 u32 pseudo_palette[PALETTE_NR];
33 struct fb_info info; 34 struct fb_info *info;
34 dma_addr_t dma_handle; 35 dma_addr_t dma_handle;
35 struct fb_deferred_io defio; 36 struct fb_deferred_io defio;
37 struct scatterlist *sglist;
36 unsigned long frame_end; 38 unsigned long frame_end;
37 wait_queue_head_t frame_end_wait; 39 wait_queue_head_t frame_end_wait;
38}; 40};
@@ -206,16 +208,38 @@ static void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv) {}
206static void sh_mobile_lcdc_clk_off(struct sh_mobile_lcdc_priv *priv) {} 208static void sh_mobile_lcdc_clk_off(struct sh_mobile_lcdc_priv *priv) {}
207#endif 209#endif
208 210
211static int sh_mobile_lcdc_sginit(struct fb_info *info,
212 struct list_head *pagelist)
213{
214 struct sh_mobile_lcdc_chan *ch = info->par;
215 unsigned int nr_pages_max = info->fix.smem_len >> PAGE_SHIFT;
216 struct page *page;
217 int nr_pages = 0;
218
219 sg_init_table(ch->sglist, nr_pages_max);
220
221 list_for_each_entry(page, pagelist, lru)
222 sg_set_page(&ch->sglist[nr_pages++], page, PAGE_SIZE, 0);
223
224 return nr_pages;
225}
226
209static void sh_mobile_lcdc_deferred_io(struct fb_info *info, 227static void sh_mobile_lcdc_deferred_io(struct fb_info *info,
210 struct list_head *pagelist) 228 struct list_head *pagelist)
211{ 229{
212 struct sh_mobile_lcdc_chan *ch = info->par; 230 struct sh_mobile_lcdc_chan *ch = info->par;
231 unsigned int nr_pages;
213 232
214 /* enable clocks before accessing hardware */ 233 /* enable clocks before accessing hardware */
215 sh_mobile_lcdc_clk_on(ch->lcdc); 234 sh_mobile_lcdc_clk_on(ch->lcdc);
216 235
236 nr_pages = sh_mobile_lcdc_sginit(info, pagelist);
237 dma_map_sg(info->dev, ch->sglist, nr_pages, DMA_TO_DEVICE);
238
217 /* trigger panel update */ 239 /* trigger panel update */
218 lcdc_write_chan(ch, LDSM2R, 1); 240 lcdc_write_chan(ch, LDSM2R, 1);
241
242 dma_unmap_sg(info->dev, ch->sglist, nr_pages, DMA_TO_DEVICE);
219} 243}
220 244
221static void sh_mobile_lcdc_deferred_io_touch(struct fb_info *info) 245static void sh_mobile_lcdc_deferred_io_touch(struct fb_info *info)
@@ -418,22 +442,22 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
418 /* set bpp format in PKF[4:0] */ 442 /* set bpp format in PKF[4:0] */
419 tmp = lcdc_read_chan(ch, LDDFR); 443 tmp = lcdc_read_chan(ch, LDDFR);
420 tmp &= ~(0x0001001f); 444 tmp &= ~(0x0001001f);
421 tmp |= (priv->ch[k].info.var.bits_per_pixel == 16) ? 3 : 0; 445 tmp |= (ch->info->var.bits_per_pixel == 16) ? 3 : 0;
422 lcdc_write_chan(ch, LDDFR, tmp); 446 lcdc_write_chan(ch, LDDFR, tmp);
423 447
424 /* point out our frame buffer */ 448 /* point out our frame buffer */
425 lcdc_write_chan(ch, LDSA1R, ch->info.fix.smem_start); 449 lcdc_write_chan(ch, LDSA1R, ch->info->fix.smem_start);
426 450
427 /* set line size */ 451 /* set line size */
428 lcdc_write_chan(ch, LDMLSR, ch->info.fix.line_length); 452 lcdc_write_chan(ch, LDMLSR, ch->info->fix.line_length);
429 453
430 /* setup deferred io if SYS bus */ 454 /* setup deferred io if SYS bus */
431 tmp = ch->cfg.sys_bus_cfg.deferred_io_msec; 455 tmp = ch->cfg.sys_bus_cfg.deferred_io_msec;
432 if (ch->ldmt1r_value & (1 << 12) && tmp) { 456 if (ch->ldmt1r_value & (1 << 12) && tmp) {
433 ch->defio.deferred_io = sh_mobile_lcdc_deferred_io; 457 ch->defio.deferred_io = sh_mobile_lcdc_deferred_io;
434 ch->defio.delay = msecs_to_jiffies(tmp); 458 ch->defio.delay = msecs_to_jiffies(tmp);
435 ch->info.fbdefio = &ch->defio; 459 ch->info->fbdefio = &ch->defio;
436 fb_deferred_io_init(&ch->info); 460 fb_deferred_io_init(ch->info);
437 461
438 /* one-shot mode */ 462 /* one-shot mode */
439 lcdc_write_chan(ch, LDSM1R, 1); 463 lcdc_write_chan(ch, LDSM1R, 1);
@@ -479,12 +503,12 @@ static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv)
479 * flush frame, and wait for frame end interrupt 503 * flush frame, and wait for frame end interrupt
480 * clean up deferred io and enable clock 504 * clean up deferred io and enable clock
481 */ 505 */
482 if (ch->info.fbdefio) { 506 if (ch->info->fbdefio) {
483 ch->frame_end = 0; 507 ch->frame_end = 0;
484 schedule_delayed_work(&ch->info.deferred_work, 0); 508 schedule_delayed_work(&ch->info->deferred_work, 0);
485 wait_event(ch->frame_end_wait, ch->frame_end); 509 wait_event(ch->frame_end_wait, ch->frame_end);
486 fb_deferred_io_cleanup(&ch->info); 510 fb_deferred_io_cleanup(ch->info);
487 ch->info.fbdefio = NULL; 511 ch->info->fbdefio = NULL;
488 sh_mobile_lcdc_clk_on(priv); 512 sh_mobile_lcdc_clk_on(priv);
489 } 513 }
490 514
@@ -793,9 +817,16 @@ static int __init sh_mobile_lcdc_probe(struct platform_device *pdev)
793 priv->base = ioremap_nocache(res->start, (res->end - res->start) + 1); 817 priv->base = ioremap_nocache(res->start, (res->end - res->start) + 1);
794 818
795 for (i = 0; i < j; i++) { 819 for (i = 0; i < j; i++) {
796 info = &priv->ch[i].info;
797 cfg = &priv->ch[i].cfg; 820 cfg = &priv->ch[i].cfg;
798 821
822 priv->ch[i].info = framebuffer_alloc(0, &pdev->dev);
823 if (!priv->ch[i].info) {
824 dev_err(&pdev->dev, "unable to allocate fb_info\n");
825 error = -ENOMEM;
826 break;
827 }
828
829 info = priv->ch[i].info;
799 info->fbops = &sh_mobile_lcdc_ops; 830 info->fbops = &sh_mobile_lcdc_ops;
800 info->var.xres = info->var.xres_virtual = cfg->lcd_cfg.xres; 831 info->var.xres = info->var.xres_virtual = cfg->lcd_cfg.xres;
801 info->var.yres = info->var.yres_virtual = cfg->lcd_cfg.yres; 832 info->var.yres = info->var.yres_virtual = cfg->lcd_cfg.yres;
@@ -846,21 +877,31 @@ static int __init sh_mobile_lcdc_probe(struct platform_device *pdev)
846 } 877 }
847 878
848 for (i = 0; i < j; i++) { 879 for (i = 0; i < j; i++) {
849 error = register_framebuffer(&priv->ch[i].info); 880 struct sh_mobile_lcdc_chan *ch = priv->ch + i;
881
882 info = ch->info;
883
884 if (info->fbdefio) {
885 priv->ch->sglist = vmalloc(sizeof(struct scatterlist) *
886 info->fix.smem_len >> PAGE_SHIFT);
887 if (!priv->ch->sglist) {
888 dev_err(&pdev->dev, "cannot allocate sglist\n");
889 goto err1;
890 }
891 }
892
893 error = register_framebuffer(info);
850 if (error < 0) 894 if (error < 0)
851 goto err1; 895 goto err1;
852 }
853 896
854 for (i = 0; i < j; i++) {
855 info = &priv->ch[i].info;
856 dev_info(info->dev, 897 dev_info(info->dev,
857 "registered %s/%s as %dx%d %dbpp.\n", 898 "registered %s/%s as %dx%d %dbpp.\n",
858 pdev->name, 899 pdev->name,
859 (priv->ch[i].cfg.chan == LCDC_CHAN_MAINLCD) ? 900 (ch->cfg.chan == LCDC_CHAN_MAINLCD) ?
860 "mainlcd" : "sublcd", 901 "mainlcd" : "sublcd",
861 (int) priv->ch[i].cfg.lcd_cfg.xres, 902 (int) ch->cfg.lcd_cfg.xres,
862 (int) priv->ch[i].cfg.lcd_cfg.yres, 903 (int) ch->cfg.lcd_cfg.yres,
863 priv->ch[i].cfg.bpp); 904 ch->cfg.bpp);
864 905
865 /* deferred io mode: disable clock to save power */ 906 /* deferred io mode: disable clock to save power */
866 if (info->fbdefio) 907 if (info->fbdefio)
@@ -881,20 +922,24 @@ static int sh_mobile_lcdc_remove(struct platform_device *pdev)
881 int i; 922 int i;
882 923
883 for (i = 0; i < ARRAY_SIZE(priv->ch); i++) 924 for (i = 0; i < ARRAY_SIZE(priv->ch); i++)
884 if (priv->ch[i].info.dev) 925 if (priv->ch[i].info->dev)
885 unregister_framebuffer(&priv->ch[i].info); 926 unregister_framebuffer(priv->ch[i].info);
886 927
887 sh_mobile_lcdc_stop(priv); 928 sh_mobile_lcdc_stop(priv);
888 929
889 for (i = 0; i < ARRAY_SIZE(priv->ch); i++) { 930 for (i = 0; i < ARRAY_SIZE(priv->ch); i++) {
890 info = &priv->ch[i].info; 931 info = priv->ch[i].info;
891 932
892 if (!info->device) 933 if (!info || !info->device)
893 continue; 934 continue;
894 935
936 if (priv->ch[i].sglist)
937 vfree(priv->ch[i].sglist);
938
895 dma_free_coherent(&pdev->dev, info->fix.smem_len, 939 dma_free_coherent(&pdev->dev, info->fix.smem_len,
896 info->screen_base, priv->ch[i].dma_handle); 940 info->screen_base, priv->ch[i].dma_handle);
897 fb_dealloc_cmap(&info->cmap); 941 fb_dealloc_cmap(&info->cmap);
942 framebuffer_release(info);
898 } 943 }
899 944
900#ifdef CONFIG_HAVE_CLK 945#ifdef CONFIG_HAVE_CLK