aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/metronomefb.c
diff options
context:
space:
mode:
authorJaya Kumar <jayakumar.lkml@gmail.com>2008-08-19 06:17:55 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2008-08-26 12:01:12 -0400
commite935508515cc5592d7c80d7f51f21103f73efb2d (patch)
treeeba61a65739b10329150099b49bb313b772c5e8a /drivers/video/metronomefb.c
parent28501336f8b9fb5ec6c2d7bb07b4dfa88ceed272 (diff)
[ARM] 5209/1: metronomefb: changes to use platform framebuffer
These changes are used in order to support the use of the framebuffer provided by the platform device driver rather than to directly allocate one. Other changes are cleanup to error handling and order of release. Signed-off-by: Jaya Kumar <jayakumar.lkml@gmail.com> Acked-by: Krzysztof Helt <krzysztof.h1@wp.pl> Acked-by: Eric Miao <eric.miao@marvell.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'drivers/video/metronomefb.c')
-rw-r--r--drivers/video/metronomefb.c241
1 files changed, 134 insertions, 107 deletions
diff --git a/drivers/video/metronomefb.c b/drivers/video/metronomefb.c
index 7cda4f80af52..afeed0611e3e 100644
--- a/drivers/video/metronomefb.c
+++ b/drivers/video/metronomefb.c
@@ -44,16 +44,59 @@
44#define DPY_W 832 44#define DPY_W 832
45#define DPY_H 622 45#define DPY_H 622
46 46
47static int user_wfm_size;
48
47/* frame differs from image. frame includes non-visible pixels */ 49/* frame differs from image. frame includes non-visible pixels */
48struct epd_frame { 50struct epd_frame {
49 int fw; /* frame width */ 51 int fw; /* frame width */
50 int fh; /* frame height */ 52 int fh; /* frame height */
53 u16 config[4];
54 int wfm_size;
51}; 55};
52 56
53static struct epd_frame epd_frame_table[] = { 57static struct epd_frame epd_frame_table[] = {
54 { 58 {
55 .fw = 832, 59 .fw = 832,
56 .fh = 622 60 .fh = 622,
61 .config = {
62 15 /* sdlew */
63 | 2 << 8 /* sdosz */
64 | 0 << 11 /* sdor */
65 | 0 << 12 /* sdces */
66 | 0 << 15, /* sdcer */
67 42 /* gdspl */
68 | 1 << 8 /* gdr1 */
69 | 1 << 9 /* sdshr */
70 | 0 << 15, /* gdspp */
71 18 /* gdspw */
72 | 0 << 15, /* dispc */
73 599 /* vdlc */
74 | 0 << 11 /* dsi */
75 | 0 << 12, /* dsic */
76 },
77 .wfm_size = 47001,
78 },
79 {
80 .fw = 1088,
81 .fh = 791,
82 .config = {
83 0x0104,
84 0x031f,
85 0x0088,
86 0x02ff,
87 },
88 .wfm_size = 46770,
89 },
90 {
91 .fw = 1200,
92 .fh = 842,
93 .config = {
94 0x0101,
95 0x030e,
96 0x0012,
97 0x0280,
98 },
99 .wfm_size = 46770,
57 }, 100 },
58}; 101};
59 102
@@ -125,7 +168,6 @@ static u16 calc_img_cksum(u16 *start, int length)
125} 168}
126 169
127/* here we decode the incoming waveform file and populate metromem */ 170/* here we decode the incoming waveform file and populate metromem */
128#define EXP_WFORM_SIZE 47001
129static int __devinit load_waveform(u8 *mem, size_t size, int m, int t, 171static int __devinit load_waveform(u8 *mem, size_t size, int m, int t,
130 struct metronomefb_par *par) 172 struct metronomefb_par *par)
131{ 173{
@@ -142,9 +184,12 @@ static int __devinit load_waveform(u8 *mem, size_t size, int m, int t,
142 u8 *metromem = par->metromem_wfm; 184 u8 *metromem = par->metromem_wfm;
143 struct device *dev = par->info->dev; 185 struct device *dev = par->info->dev;
144 186
145 if (size != EXP_WFORM_SIZE) { 187 if (user_wfm_size)
188 epd_frame_table[par->dt].wfm_size = user_wfm_size;
189
190 if (size != epd_frame_table[par->dt].wfm_size) {
146 dev_err(dev, "Error: unexpected size %d != %d\n", size, 191 dev_err(dev, "Error: unexpected size %d != %d\n", size,
147 EXP_WFORM_SIZE); 192 epd_frame_table[par->dt].wfm_size);
148 return -EINVAL; 193 return -EINVAL;
149 } 194 }
150 195
@@ -267,15 +312,12 @@ static int metronome_display_cmd(struct metronomefb_par *par)
267 u16 cs; 312 u16 cs;
268 u16 opcode; 313 u16 opcode;
269 static u8 borderval; 314 static u8 borderval;
270 u8 *ptr;
271 315
272 /* setup display command 316 /* setup display command
273 we can't immediately set the opcode since the controller 317 we can't immediately set the opcode since the controller
274 will try parse the command before we've set it all up 318 will try parse the command before we've set it all up
275 so we just set cs here and set the opcode at the end */ 319 so we just set cs here and set the opcode at the end */
276 320
277 ptr = par->metromem;
278
279 if (par->metromem_cmd->opcode == 0xCC40) 321 if (par->metromem_cmd->opcode == 0xCC40)
280 opcode = cs = 0xCC41; 322 opcode = cs = 0xCC41;
281 else 323 else
@@ -328,44 +370,17 @@ static int __devinit metronome_powerup_cmd(struct metronomefb_par *par)
328 370
329static int __devinit metronome_config_cmd(struct metronomefb_par *par) 371static int __devinit metronome_config_cmd(struct metronomefb_par *par)
330{ 372{
331 int i;
332 u16 cs;
333
334 /* setup config command 373 /* setup config command
335 we can't immediately set the opcode since the controller 374 we can't immediately set the opcode since the controller
336 will try parse the command before we've set it all up 375 will try parse the command before we've set it all up */
337 so we just set cs here and set the opcode at the end */
338
339 cs = 0xCC10;
340
341 /* set the 12 args ( 8 bytes ) for config. see spec for meanings */
342 i = 0;
343 par->metromem_cmd->args[i] = 15 /* sdlew */
344 | 2 << 8 /* sdosz */
345 | 0 << 11 /* sdor */
346 | 0 << 12 /* sdces */
347 | 0 << 15; /* sdcer */
348 cs += par->metromem_cmd->args[i++];
349
350 par->metromem_cmd->args[i] = 42 /* gdspl */
351 | 1 << 8 /* gdr1 */
352 | 1 << 9 /* sdshr */
353 | 0 << 15; /* gdspp */
354 cs += par->metromem_cmd->args[i++];
355
356 par->metromem_cmd->args[i] = 18 /* gdspw */
357 | 0 << 15; /* dispc */
358 cs += par->metromem_cmd->args[i++];
359
360 par->metromem_cmd->args[i] = 599 /* vdlc */
361 | 0 << 11 /* dsi */
362 | 0 << 12; /* dsic */
363 cs += par->metromem_cmd->args[i++];
364 376
377 memcpy(par->metromem_cmd->args, epd_frame_table[par->dt].config,
378 sizeof(epd_frame_table[par->dt].config));
365 /* the rest are 0 */ 379 /* the rest are 0 */
366 memset((u8 *) (par->metromem_cmd->args + i), 0, (32-i)*2); 380 memset((u8 *) (par->metromem_cmd->args + 4), 0, (32-4)*2);
367 381
368 par->metromem_cmd->csum = cs; 382 par->metromem_cmd->csum = 0xCC10;
383 par->metromem_cmd->csum += calc_img_cksum(par->metromem_cmd->args, 4);
369 par->metromem_cmd->opcode = 0xCC10; /* config cmd */ 384 par->metromem_cmd->opcode = 0xCC10; /* config cmd */
370 385
371 return par->board->met_wait_event(par); 386 return par->board->met_wait_event(par);
@@ -401,12 +416,9 @@ static int __devinit metronome_init_regs(struct metronomefb_par *par)
401{ 416{
402 int res; 417 int res;
403 418
404 par->board->init_gpio_regs(par); 419 res = par->board->setup_io(par);
405 420 if (res)
406 par->board->init_lcdc_regs(par); 421 return res;
407
408 /* now that lcd is setup, setup dma descriptor */
409 par->board->post_dma_setup(par);
410 422
411 res = metronome_powerup_cmd(par); 423 res = metronome_powerup_cmd(par);
412 if (res) 424 if (res)
@@ -423,16 +435,16 @@ static int __devinit metronome_init_regs(struct metronomefb_par *par)
423 435
424static void metronomefb_dpy_update(struct metronomefb_par *par) 436static void metronomefb_dpy_update(struct metronomefb_par *par)
425{ 437{
438 int fbsize;
426 u16 cksum; 439 u16 cksum;
427 unsigned char *buf = (unsigned char __force *)par->info->screen_base; 440 unsigned char *buf = (unsigned char __force *)par->info->screen_base;
428 441
442 fbsize = par->info->fix.smem_len;
429 /* copy from vm to metromem */ 443 /* copy from vm to metromem */
430 memcpy(par->metromem_img, buf, DPY_W*DPY_H); 444 memcpy(par->metromem_img, buf, fbsize);
431 445
432 cksum = calc_img_cksum((u16 *) par->metromem_img, 446 cksum = calc_img_cksum((u16 *) par->metromem_img, fbsize/2);
433 (epd_frame_table[0].fw * DPY_H)/2); 447 *((u16 *)(par->metromem_img) + fbsize/2) = cksum;
434 *((u16 *)(par->metromem_img) +
435 (epd_frame_table[0].fw * DPY_H)/2) = cksum;
436 metronome_display_cmd(par); 448 metronome_display_cmd(par);
437} 449}
438 450
@@ -567,8 +579,10 @@ static int __devinit metronomefb_probe(struct platform_device *dev)
567 unsigned char *videomemory; 579 unsigned char *videomemory;
568 struct metronomefb_par *par; 580 struct metronomefb_par *par;
569 const struct firmware *fw_entry; 581 const struct firmware *fw_entry;
570 int cmd_size, wfm_size, img_size, padding_size, totalsize;
571 int i; 582 int i;
583 int panel_type;
584 int fw, fh;
585 int epd_dt_index;
572 586
573 /* pick up board specific routines */ 587 /* pick up board specific routines */
574 board = dev->dev.platform_data; 588 board = dev->dev.platform_data;
@@ -579,76 +593,88 @@ static int __devinit metronomefb_probe(struct platform_device *dev)
579 if (!try_module_get(board->owner)) 593 if (!try_module_get(board->owner))
580 return -ENODEV; 594 return -ENODEV;
581 595
596 info = framebuffer_alloc(sizeof(struct metronomefb_par), &dev->dev);
597 if (!info)
598 goto err;
599
582 /* we have two blocks of memory. 600 /* we have two blocks of memory.
583 info->screen_base which is vm, and is the fb used by apps. 601 info->screen_base which is vm, and is the fb used by apps.
584 par->metromem which is physically contiguous memory and 602 par->metromem which is physically contiguous memory and
585 contains the display controller commands, waveform, 603 contains the display controller commands, waveform,
586 processed image data and padding. this is the data pulled 604 processed image data and padding. this is the data pulled
587 by the device's LCD controller and pushed to Metronome */ 605 by the device's LCD controller and pushed to Metronome.
606 the metromem memory is allocated by the board driver and
607 is provided to us */
608
609 panel_type = board->get_panel_type();
610 switch (panel_type) {
611 case 6:
612 epd_dt_index = 0;
613 break;
614 case 8:
615 epd_dt_index = 1;
616 break;
617 case 97:
618 epd_dt_index = 2;
619 break;
620 default:
621 dev_err(&dev->dev, "Unexpected panel type. Defaulting to 6\n");
622 epd_dt_index = 0;
623 break;
624 }
588 625
589 videomemorysize = (DPY_W*DPY_H); 626 fw = epd_frame_table[epd_dt_index].fw;
627 fh = epd_frame_table[epd_dt_index].fh;
628
629 /* we need to add a spare page because our csum caching scheme walks
630 * to the end of the page */
631 videomemorysize = PAGE_SIZE + (fw * fh);
590 videomemory = vmalloc(videomemorysize); 632 videomemory = vmalloc(videomemorysize);
591 if (!videomemory) 633 if (!videomemory)
592 return -ENOMEM; 634 goto err_fb_rel;
593 635
594 memset(videomemory, 0, videomemorysize); 636 memset(videomemory, 0, videomemorysize);
595 637
596 info = framebuffer_alloc(sizeof(struct metronomefb_par), &dev->dev);
597 if (!info)
598 goto err_vfree;
599
600 info->screen_base = (char __force __iomem *)videomemory; 638 info->screen_base = (char __force __iomem *)videomemory;
601 info->fbops = &metronomefb_ops; 639 info->fbops = &metronomefb_ops;
602 640
641 metronomefb_fix.line_length = fw;
642 metronomefb_var.xres = fw;
643 metronomefb_var.yres = fh;
644 metronomefb_var.xres_virtual = fw;
645 metronomefb_var.yres_virtual = fh;
603 info->var = metronomefb_var; 646 info->var = metronomefb_var;
604 info->fix = metronomefb_fix; 647 info->fix = metronomefb_fix;
605 info->fix.smem_len = videomemorysize; 648 info->fix.smem_len = videomemorysize;
606 par = info->par; 649 par = info->par;
607 par->info = info; 650 par->info = info;
608 par->board = board; 651 par->board = board;
652 par->dt = epd_dt_index;
609 init_waitqueue_head(&par->waitq); 653 init_waitqueue_head(&par->waitq);
610 654
611 /* this table caches per page csum values. */ 655 /* this table caches per page csum values. */
612 par->csum_table = vmalloc(videomemorysize/PAGE_SIZE); 656 par->csum_table = vmalloc(videomemorysize/PAGE_SIZE);
613 if (!par->csum_table) 657 if (!par->csum_table)
658 goto err_vfree;
659
660 /* the physical framebuffer that we use is setup by
661 * the platform device driver. It will provide us
662 * with cmd, wfm and image memory in a contiguous area. */
663 retval = board->setup_fb(par);
664 if (retval) {
665 dev_err(&dev->dev, "Failed to setup fb\n");
614 goto err_csum_table; 666 goto err_csum_table;
667 }
615 668
616 /* the metromem buffer is divided as follows: 669 /* after this point we should have a framebuffer */
617 command | CRC | padding 670 if ((!par->metromem_wfm) || (!par->metromem_img) ||
618 16kb waveform data | CRC | padding 671 (!par->metromem_dma)) {
619 image data | CRC 672 dev_err(&dev->dev, "fb access failure\n");
620 and an extra 256 bytes for dma descriptors 673 retval = -EINVAL;
621 eg: IW=832 IH=622 WS=128 674 goto err_csum_table;
622 */
623
624 cmd_size = 1 * epd_frame_table[0].fw;
625 wfm_size = ((16*1024 + 2 + epd_frame_table[0].fw - 1)
626 / epd_frame_table[0].fw) * epd_frame_table[0].fw;
627 img_size = epd_frame_table[0].fh * epd_frame_table[0].fw;
628 padding_size = 4 * epd_frame_table[0].fw;
629 totalsize = cmd_size + wfm_size + img_size + padding_size;
630 par->metromemsize = PAGE_ALIGN(totalsize + 256);
631 DPRINTK("desired memory size = %d\n", par->metromemsize);
632 dev->dev.coherent_dma_mask = 0xffffffffull;
633 par->metromem = dma_alloc_writecombine(&dev->dev, par->metromemsize,
634 &par->metromem_dma, GFP_KERNEL);
635 if (!par->metromem) {
636 printk(KERN_ERR
637 "metronomefb: unable to allocate dma buffer\n");
638 goto err_vfree;
639 } 675 }
640 676
641 info->fix.smem_start = par->metromem_dma; 677 info->fix.smem_start = par->metromem_dma;
642 par->metromem_cmd = (struct metromem_cmd *) par->metromem;
643 par->metromem_wfm = par->metromem + cmd_size;
644 par->metromem_img = par->metromem + cmd_size + wfm_size;
645 par->metromem_img_csum = (u16 *) (par->metromem_img +
646 (epd_frame_table[0].fw * DPY_H));
647 DPRINTK("img offset=0x%x\n", cmd_size + wfm_size);
648 par->metromem_desc = (struct metromem_desc *) (par->metromem + cmd_size
649 + wfm_size + img_size + padding_size);
650 par->metromem_desc_dma = par->metromem_dma + cmd_size + wfm_size
651 + img_size + padding_size;
652 678
653 /* load the waveform in. assume mode 3, temp 31 for now 679 /* load the waveform in. assume mode 3, temp 31 for now
654 a) request the waveform file from userspace 680 a) request the waveform file from userspace
@@ -656,7 +682,7 @@ static int __devinit metronomefb_probe(struct platform_device *dev)
656 retval = request_firmware(&fw_entry, "metronome.wbf", &dev->dev); 682 retval = request_firmware(&fw_entry, "metronome.wbf", &dev->dev);
657 if (retval < 0) { 683 if (retval < 0) {
658 dev_err(&dev->dev, "Failed to get waveform\n"); 684 dev_err(&dev->dev, "Failed to get waveform\n");
659 goto err_dma_free; 685 goto err_csum_table;
660 } 686 }
661 687
662 retval = load_waveform((u8 *) fw_entry->data, fw_entry->size, 3, 31, 688 retval = load_waveform((u8 *) fw_entry->data, fw_entry->size, 3, 31,
@@ -664,11 +690,11 @@ static int __devinit metronomefb_probe(struct platform_device *dev)
664 release_firmware(fw_entry); 690 release_firmware(fw_entry);
665 if (retval < 0) { 691 if (retval < 0) {
666 dev_err(&dev->dev, "Failed processing waveform\n"); 692 dev_err(&dev->dev, "Failed processing waveform\n");
667 goto err_dma_free; 693 goto err_csum_table;
668 } 694 }
669 695
670 if (board->setup_irq(info)) 696 if (board->setup_irq(info))
671 goto err_dma_free; 697 goto err_csum_table;
672 698
673 retval = metronome_init_regs(par); 699 retval = metronome_init_regs(par);
674 if (retval < 0) 700 if (retval < 0)
@@ -682,7 +708,7 @@ static int __devinit metronomefb_probe(struct platform_device *dev)
682 retval = fb_alloc_cmap(&info->cmap, 8, 0); 708 retval = fb_alloc_cmap(&info->cmap, 8, 0);
683 if (retval < 0) { 709 if (retval < 0) {
684 dev_err(&dev->dev, "Failed to allocate colormap\n"); 710 dev_err(&dev->dev, "Failed to allocate colormap\n");
685 goto err_fb_rel; 711 goto err_free_irq;
686 } 712 }
687 713
688 /* set cmap */ 714 /* set cmap */
@@ -705,17 +731,15 @@ static int __devinit metronomefb_probe(struct platform_device *dev)
705 731
706err_cmap: 732err_cmap:
707 fb_dealloc_cmap(&info->cmap); 733 fb_dealloc_cmap(&info->cmap);
708err_fb_rel:
709 framebuffer_release(info);
710err_free_irq: 734err_free_irq:
711 board->free_irq(info); 735 board->cleanup(par);
712err_dma_free:
713 dma_free_writecombine(&dev->dev, par->metromemsize, par->metromem,
714 par->metromem_dma);
715err_csum_table: 736err_csum_table:
716 vfree(par->csum_table); 737 vfree(par->csum_table);
717err_vfree: 738err_vfree:
718 vfree(videomemory); 739 vfree(videomemory);
740err_fb_rel:
741 framebuffer_release(info);
742err:
719 module_put(board->owner); 743 module_put(board->owner);
720 return retval; 744 return retval;
721} 745}
@@ -726,15 +750,15 @@ static int __devexit metronomefb_remove(struct platform_device *dev)
726 750
727 if (info) { 751 if (info) {
728 struct metronomefb_par *par = info->par; 752 struct metronomefb_par *par = info->par;
753
754 unregister_framebuffer(info);
729 fb_deferred_io_cleanup(info); 755 fb_deferred_io_cleanup(info);
730 dma_free_writecombine(&dev->dev, par->metromemsize,
731 par->metromem, par->metromem_dma);
732 fb_dealloc_cmap(&info->cmap); 756 fb_dealloc_cmap(&info->cmap);
757 par->board->cleanup(par);
733 vfree(par->csum_table); 758 vfree(par->csum_table);
734 unregister_framebuffer(info);
735 vfree((void __force *)info->screen_base); 759 vfree((void __force *)info->screen_base);
736 par->board->free_irq(info);
737 module_put(par->board->owner); 760 module_put(par->board->owner);
761 dev_dbg(&dev->dev, "calling release\n");
738 framebuffer_release(info); 762 framebuffer_release(info);
739 } 763 }
740 return 0; 764 return 0;
@@ -759,6 +783,9 @@ static void __exit metronomefb_exit(void)
759 platform_driver_unregister(&metronomefb_driver); 783 platform_driver_unregister(&metronomefb_driver);
760} 784}
761 785
786module_param(user_wfm_size, uint, 0);
787MODULE_PARM_DESC(user_wfm_size, "Set custom waveform size");
788
762module_init(metronomefb_init); 789module_init(metronomefb_init);
763module_exit(metronomefb_exit); 790module_exit(metronomefb_exit);
764 791