Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

authored by

Jaya Kumar and committed by
Russell King
e9355085 28501336

+163 -133
+13 -5
drivers/video/Kconfig
··· 172 172 bool 173 173 depends on FB 174 174 175 - config FB_METRONOME 176 - tristate 177 - depends on FB 178 - depends on FB_DEFERRED_IO 179 - 180 175 config FB_HECUBA 181 176 tristate 182 177 depends on FB ··· 2035 2040 This driver implements the front-end of the Xen virtual 2036 2041 frame buffer driver. It communicates with a back-end 2037 2042 in another domain. 2043 + 2044 + config FB_METRONOME 2045 + tristate "E-Ink Metronome/8track controller support" 2046 + depends on FB 2047 + select FB_SYS_FILLRECT 2048 + select FB_SYS_COPYAREA 2049 + select FB_SYS_IMAGEBLIT 2050 + select FB_SYS_FOPS 2051 + select FB_DEFERRED_IO 2052 + help 2053 + This driver implements support for the E-Ink Metronome 2054 + controller. The pre-release name for this device was 8track 2055 + and could also have been called by some vendors as PVI-nnnn. 2038 2056 2039 2057 source "drivers/video/omap/Kconfig" 2040 2058
+137 -110
drivers/video/metronomefb.c
··· 44 44 #define DPY_W 832 45 45 #define DPY_H 622 46 46 47 + static int user_wfm_size; 48 + 47 49 /* frame differs from image. frame includes non-visible pixels */ 48 50 struct epd_frame { 49 51 int fw; /* frame width */ 50 52 int fh; /* frame height */ 53 + u16 config[4]; 54 + int wfm_size; 51 55 }; 52 56 53 57 static struct epd_frame epd_frame_table[] = { 54 58 { 55 - .fw = 832, 56 - .fh = 622 59 + .fw = 832, 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 ··· 168 125 } 169 126 170 127 /* here we decode the incoming waveform file and populate metromem */ 171 - #define EXP_WFORM_SIZE 47001 172 128 static int __devinit load_waveform(u8 *mem, size_t size, int m, int t, 173 129 struct metronomefb_par *par) 174 130 { ··· 184 142 u8 *metromem = par->metromem_wfm; 185 143 struct device *dev = par->info->dev; 186 144 187 - if (size != EXP_WFORM_SIZE) { 145 + if (user_wfm_size) 146 + epd_frame_table[par->dt].wfm_size = user_wfm_size; 147 + 148 + if (size != epd_frame_table[par->dt].wfm_size) { 188 149 dev_err(dev, "Error: unexpected size %d != %d\n", size, 189 - EXP_WFORM_SIZE); 150 + epd_frame_table[par->dt].wfm_size); 190 151 return -EINVAL; 191 152 } 192 153 ··· 312 267 u16 cs; 313 268 u16 opcode; 314 269 static u8 borderval; 315 - u8 *ptr; 316 270 317 271 /* setup display command 318 272 we can't immediately set the opcode since the controller 319 273 will try parse the command before we've set it all up 320 274 so we just set cs here and set the opcode at the end */ 321 - 322 - ptr = par->metromem; 323 275 324 276 if (par->metromem_cmd->opcode == 0xCC40) 325 277 opcode = cs = 0xCC41; ··· 370 328 371 329 static int __devinit metronome_config_cmd(struct metronomefb_par *par) 372 330 { 373 - int i; 374 - u16 cs; 375 - 376 331 /* setup config command 377 332 we can't immediately set the opcode since the controller 378 - will try parse the command before we've set it all up 379 - so we just set cs here and set the opcode at the end */ 333 + will try parse the command before we've set it all up */ 380 334 381 - cs = 0xCC10; 382 - 383 - /* set the 12 args ( 8 bytes ) for config. see spec for meanings */ 384 - i = 0; 385 - par->metromem_cmd->args[i] = 15 /* sdlew */ 386 - | 2 << 8 /* sdosz */ 387 - | 0 << 11 /* sdor */ 388 - | 0 << 12 /* sdces */ 389 - | 0 << 15; /* sdcer */ 390 - cs += par->metromem_cmd->args[i++]; 391 - 392 - par->metromem_cmd->args[i] = 42 /* gdspl */ 393 - | 1 << 8 /* gdr1 */ 394 - | 1 << 9 /* sdshr */ 395 - | 0 << 15; /* gdspp */ 396 - cs += par->metromem_cmd->args[i++]; 397 - 398 - par->metromem_cmd->args[i] = 18 /* gdspw */ 399 - | 0 << 15; /* dispc */ 400 - cs += par->metromem_cmd->args[i++]; 401 - 402 - par->metromem_cmd->args[i] = 599 /* vdlc */ 403 - | 0 << 11 /* dsi */ 404 - | 0 << 12; /* dsic */ 405 - cs += par->metromem_cmd->args[i++]; 406 - 335 + memcpy(par->metromem_cmd->args, epd_frame_table[par->dt].config, 336 + sizeof(epd_frame_table[par->dt].config)); 407 337 /* the rest are 0 */ 408 - memset((u8 *) (par->metromem_cmd->args + i), 0, (32-i)*2); 338 + memset((u8 *) (par->metromem_cmd->args + 4), 0, (32-4)*2); 409 339 410 - par->metromem_cmd->csum = cs; 340 + par->metromem_cmd->csum = 0xCC10; 341 + par->metromem_cmd->csum += calc_img_cksum(par->metromem_cmd->args, 4); 411 342 par->metromem_cmd->opcode = 0xCC10; /* config cmd */ 412 343 413 344 return par->board->met_wait_event(par); ··· 416 401 { 417 402 int res; 418 403 419 - par->board->init_gpio_regs(par); 420 - 421 - par->board->init_lcdc_regs(par); 422 - 423 - /* now that lcd is setup, setup dma descriptor */ 424 - par->board->post_dma_setup(par); 404 + res = par->board->setup_io(par); 405 + if (res) 406 + return res; 425 407 426 408 res = metronome_powerup_cmd(par); 427 409 if (res) ··· 435 423 436 424 static void metronomefb_dpy_update(struct metronomefb_par *par) 437 425 { 426 + int fbsize; 438 427 u16 cksum; 439 428 unsigned char *buf = (unsigned char __force *)par->info->screen_base; 440 429 430 + fbsize = par->info->fix.smem_len; 441 431 /* copy from vm to metromem */ 442 - memcpy(par->metromem_img, buf, DPY_W*DPY_H); 432 + memcpy(par->metromem_img, buf, fbsize); 443 433 444 - cksum = calc_img_cksum((u16 *) par->metromem_img, 445 - (epd_frame_table[0].fw * DPY_H)/2); 446 - *((u16 *)(par->metromem_img) + 447 - (epd_frame_table[0].fw * DPY_H)/2) = cksum; 434 + cksum = calc_img_cksum((u16 *) par->metromem_img, fbsize/2); 435 + *((u16 *)(par->metromem_img) + fbsize/2) = cksum; 448 436 metronome_display_cmd(par); 449 437 } 450 438 ··· 579 567 unsigned char *videomemory; 580 568 struct metronomefb_par *par; 581 569 const struct firmware *fw_entry; 582 - int cmd_size, wfm_size, img_size, padding_size, totalsize; 583 570 int i; 571 + int panel_type; 572 + int fw, fh; 573 + int epd_dt_index; 584 574 585 575 /* pick up board specific routines */ 586 576 board = dev->dev.platform_data; ··· 593 579 if (!try_module_get(board->owner)) 594 580 return -ENODEV; 595 581 582 + info = framebuffer_alloc(sizeof(struct metronomefb_par), &dev->dev); 583 + if (!info) 584 + goto err; 585 + 596 586 /* we have two blocks of memory. 597 587 info->screen_base which is vm, and is the fb used by apps. 598 588 par->metromem which is physically contiguous memory and 599 589 contains the display controller commands, waveform, 600 590 processed image data and padding. this is the data pulled 601 - by the device's LCD controller and pushed to Metronome */ 591 + by the device's LCD controller and pushed to Metronome. 592 + the metromem memory is allocated by the board driver and 593 + is provided to us */ 602 594 603 - videomemorysize = (DPY_W*DPY_H); 595 + panel_type = board->get_panel_type(); 596 + switch (panel_type) { 597 + case 6: 598 + epd_dt_index = 0; 599 + break; 600 + case 8: 601 + epd_dt_index = 1; 602 + break; 603 + case 97: 604 + epd_dt_index = 2; 605 + break; 606 + default: 607 + dev_err(&dev->dev, "Unexpected panel type. Defaulting to 6\n"); 608 + epd_dt_index = 0; 609 + break; 610 + } 611 + 612 + fw = epd_frame_table[epd_dt_index].fw; 613 + fh = epd_frame_table[epd_dt_index].fh; 614 + 615 + /* we need to add a spare page because our csum caching scheme walks 616 + * to the end of the page */ 617 + videomemorysize = PAGE_SIZE + (fw * fh); 604 618 videomemory = vmalloc(videomemorysize); 605 619 if (!videomemory) 606 - return -ENOMEM; 620 + goto err_fb_rel; 607 621 608 622 memset(videomemory, 0, videomemorysize); 609 - 610 - info = framebuffer_alloc(sizeof(struct metronomefb_par), &dev->dev); 611 - if (!info) 612 - goto err_vfree; 613 623 614 624 info->screen_base = (char __force __iomem *)videomemory; 615 625 info->fbops = &metronomefb_ops; 616 626 627 + metronomefb_fix.line_length = fw; 628 + metronomefb_var.xres = fw; 629 + metronomefb_var.yres = fh; 630 + metronomefb_var.xres_virtual = fw; 631 + metronomefb_var.yres_virtual = fh; 617 632 info->var = metronomefb_var; 618 633 info->fix = metronomefb_fix; 619 634 info->fix.smem_len = videomemorysize; 620 635 par = info->par; 621 636 par->info = info; 622 637 par->board = board; 638 + par->dt = epd_dt_index; 623 639 init_waitqueue_head(&par->waitq); 624 640 625 641 /* this table caches per page csum values. */ 626 642 par->csum_table = vmalloc(videomemorysize/PAGE_SIZE); 627 643 if (!par->csum_table) 628 - goto err_csum_table; 629 - 630 - /* the metromem buffer is divided as follows: 631 - command | CRC | padding 632 - 16kb waveform data | CRC | padding 633 - image data | CRC 634 - and an extra 256 bytes for dma descriptors 635 - eg: IW=832 IH=622 WS=128 636 - */ 637 - 638 - cmd_size = 1 * epd_frame_table[0].fw; 639 - wfm_size = ((16*1024 + 2 + epd_frame_table[0].fw - 1) 640 - / epd_frame_table[0].fw) * epd_frame_table[0].fw; 641 - img_size = epd_frame_table[0].fh * epd_frame_table[0].fw; 642 - padding_size = 4 * epd_frame_table[0].fw; 643 - totalsize = cmd_size + wfm_size + img_size + padding_size; 644 - par->metromemsize = PAGE_ALIGN(totalsize + 256); 645 - DPRINTK("desired memory size = %d\n", par->metromemsize); 646 - dev->dev.coherent_dma_mask = 0xffffffffull; 647 - par->metromem = dma_alloc_writecombine(&dev->dev, par->metromemsize, 648 - &par->metromem_dma, GFP_KERNEL); 649 - if (!par->metromem) { 650 - printk(KERN_ERR 651 - "metronomefb: unable to allocate dma buffer\n"); 652 644 goto err_vfree; 645 + 646 + /* the physical framebuffer that we use is setup by 647 + * the platform device driver. It will provide us 648 + * with cmd, wfm and image memory in a contiguous area. */ 649 + retval = board->setup_fb(par); 650 + if (retval) { 651 + dev_err(&dev->dev, "Failed to setup fb\n"); 652 + goto err_csum_table; 653 + } 654 + 655 + /* after this point we should have a framebuffer */ 656 + if ((!par->metromem_wfm) || (!par->metromem_img) || 657 + (!par->metromem_dma)) { 658 + dev_err(&dev->dev, "fb access failure\n"); 659 + retval = -EINVAL; 660 + goto err_csum_table; 653 661 } 654 662 655 663 info->fix.smem_start = par->metromem_dma; 656 - par->metromem_cmd = (struct metromem_cmd *) par->metromem; 657 - par->metromem_wfm = par->metromem + cmd_size; 658 - par->metromem_img = par->metromem + cmd_size + wfm_size; 659 - par->metromem_img_csum = (u16 *) (par->metromem_img + 660 - (epd_frame_table[0].fw * DPY_H)); 661 - DPRINTK("img offset=0x%x\n", cmd_size + wfm_size); 662 - par->metromem_desc = (struct metromem_desc *) (par->metromem + cmd_size 663 - + wfm_size + img_size + padding_size); 664 - par->metromem_desc_dma = par->metromem_dma + cmd_size + wfm_size 665 - + img_size + padding_size; 666 664 667 665 /* load the waveform in. assume mode 3, temp 31 for now 668 666 a) request the waveform file from userspace ··· 682 656 retval = request_firmware(&fw_entry, "metronome.wbf", &dev->dev); 683 657 if (retval < 0) { 684 658 dev_err(&dev->dev, "Failed to get waveform\n"); 685 - goto err_dma_free; 659 + goto err_csum_table; 686 660 } 687 661 688 662 retval = load_waveform((u8 *) fw_entry->data, fw_entry->size, 3, 31, ··· 690 664 release_firmware(fw_entry); 691 665 if (retval < 0) { 692 666 dev_err(&dev->dev, "Failed processing waveform\n"); 693 - goto err_dma_free; 667 + goto err_csum_table; 694 668 } 695 669 696 670 if (board->setup_irq(info)) 697 - goto err_dma_free; 671 + goto err_csum_table; 698 672 699 673 retval = metronome_init_regs(par); 700 674 if (retval < 0) ··· 708 682 retval = fb_alloc_cmap(&info->cmap, 8, 0); 709 683 if (retval < 0) { 710 684 dev_err(&dev->dev, "Failed to allocate colormap\n"); 711 - goto err_fb_rel; 685 + goto err_free_irq; 712 686 } 713 687 714 688 /* set cmap */ ··· 731 705 732 706 err_cmap: 733 707 fb_dealloc_cmap(&info->cmap); 734 - err_fb_rel: 735 - framebuffer_release(info); 736 708 err_free_irq: 737 - board->free_irq(info); 738 - err_dma_free: 739 - dma_free_writecombine(&dev->dev, par->metromemsize, par->metromem, 740 - par->metromem_dma); 709 + board->cleanup(par); 741 710 err_csum_table: 742 711 vfree(par->csum_table); 743 712 err_vfree: 744 713 vfree(videomemory); 714 + err_fb_rel: 715 + framebuffer_release(info); 716 + err: 745 717 module_put(board->owner); 746 718 return retval; 747 719 } ··· 750 726 751 727 if (info) { 752 728 struct metronomefb_par *par = info->par; 753 - fb_deferred_io_cleanup(info); 754 - dma_free_writecombine(&dev->dev, par->metromemsize, 755 - par->metromem, par->metromem_dma); 756 - fb_dealloc_cmap(&info->cmap); 757 - vfree(par->csum_table); 729 + 758 730 unregister_framebuffer(info); 731 + fb_deferred_io_cleanup(info); 732 + fb_dealloc_cmap(&info->cmap); 733 + par->board->cleanup(par); 734 + vfree(par->csum_table); 759 735 vfree((void __force *)info->screen_base); 760 - par->board->free_irq(info); 761 736 module_put(par->board->owner); 737 + dev_dbg(&dev->dev, "calling release\n"); 762 738 framebuffer_release(info); 763 739 } 764 740 return 0; ··· 782 758 { 783 759 platform_driver_unregister(&metronomefb_driver); 784 760 } 761 + 762 + module_param(user_wfm_size, uint, 0); 763 + MODULE_PARM_DESC(user_wfm_size, "Set custom waveform size"); 785 764 786 765 module_init(metronomefb_init); 787 766 module_exit(metronomefb_exit);
+13 -18
include/video/metronomefb.h
··· 12 12 #ifndef _LINUX_METRONOMEFB_H_ 13 13 #define _LINUX_METRONOMEFB_H_ 14 14 15 - /* address and control descriptors used by metronome controller */ 16 - struct metromem_desc { 17 - u32 mFDADR0; 18 - u32 mFSADR0; 19 - u32 mFIDR0; 20 - u32 mLDCMD0; 21 - }; 22 - 23 15 /* command structure used by metronome controller */ 24 16 struct metromem_cmd { 25 17 u16 opcode; ··· 21 29 22 30 /* struct used by metronome. board specific stuff comes from *board */ 23 31 struct metronomefb_par { 24 - unsigned char *metromem; 25 - struct metromem_desc *metromem_desc; 26 32 struct metromem_cmd *metromem_cmd; 27 33 unsigned char *metromem_wfm; 28 34 unsigned char *metromem_img; 29 35 u16 *metromem_img_csum; 30 36 u16 *csum_table; 31 - int metromemsize; 32 37 dma_addr_t metromem_dma; 33 - dma_addr_t metromem_desc_dma; 34 38 struct fb_info *info; 35 39 struct metronome_board *board; 36 40 wait_queue_head_t waitq; 37 41 u8 frame_count; 42 + int extra_size; 43 + int dt; 38 44 }; 39 45 40 - /* board specific routines */ 46 + /* board specific routines and data */ 41 47 struct metronome_board { 42 - struct module *owner; 43 - void (*free_irq)(struct fb_info *); 44 - void (*init_gpio_regs)(struct metronomefb_par *); 45 - void (*init_lcdc_regs)(struct metronomefb_par *); 46 - void (*post_dma_setup)(struct metronomefb_par *); 48 + struct module *owner; /* the platform device */ 47 49 void (*set_rst)(struct metronomefb_par *, int); 48 50 void (*set_stdby)(struct metronomefb_par *, int); 51 + void (*cleanup)(struct metronomefb_par *); 49 52 int (*met_wait_event)(struct metronomefb_par *); 50 53 int (*met_wait_event_intr)(struct metronomefb_par *); 51 54 int (*setup_irq)(struct fb_info *); 55 + int (*setup_fb)(struct metronomefb_par *); 56 + int (*setup_io)(struct metronomefb_par *); 57 + int (*get_panel_type)(void); 58 + unsigned char *metromem; 59 + int fw; 60 + int fh; 61 + int wfm_size; 62 + struct fb_info *host_fbinfo; /* the host LCD controller's fbi */ 52 63 }; 53 64 54 65 #endif