2 * linux/drivers/video/metronomefb.c -- FB driver for Metronome controller
4 * Copyright (C) 2008, Jaya Kumar
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file COPYING in the main directory of this archive for
10 * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven.
12 * This work was made possible by help and equipment support from E-Ink
13 * Corporation. http://support.eink.com/community
15 * This driver is written to be used with the Metronome display controller.
16 * It is intended to be architecture independent. A board specific driver
17 * must be used to perform all the physical IO interactions. An example
18 * is provided as am200epd.c
21 #include <linux/module.h>
22 #include <linux/kernel.h>
23 #include <linux/errno.h>
24 #include <linux/string.h>
26 #include <linux/slab.h>
27 #include <linux/vmalloc.h>
28 #include <linux/delay.h>
29 #include <linux/interrupt.h>
31 #include <linux/init.h>
32 #include <linux/platform_device.h>
33 #include <linux/list.h>
34 #include <linux/firmware.h>
35 #include <linux/dma-mapping.h>
36 #include <linux/uaccess.h>
37 #include <linux/irq.h>
39 #include <video/metronomefb.h>
41 #include <asm/unaligned.h>
46 #define DPRINTK(f, a...) printk(KERN_DEBUG "%s: " f, __func__ , ## a)
48 #define DPRINTK(f, a...)
52 /* Display specific information */
56 /* frame differs from image. frame includes non-visible pixels */
58 int fw
; /* frame width */
59 int fh
; /* frame height */
62 static struct epd_frame epd_frame_table
[] = {
69 static struct fb_fix_screeninfo metronomefb_fix __devinitdata
= {
71 .type
= FB_TYPE_PACKED_PIXELS
,
72 .visual
= FB_VISUAL_STATIC_PSEUDOCOLOR
,
77 .accel
= FB_ACCEL_NONE
,
80 static struct fb_var_screeninfo metronomefb_var __devinitdata
= {
83 .xres_virtual
= DPY_W
,
84 .yres_virtual
= DPY_H
,
91 .transp
= { 0, 0, 0 },
94 /* the waveform structure that is coming from userspace firmware */
112 } __attribute__ ((packed
));
114 /* main metronomefb functions */
115 static u8
calc_cksum(int start
, int end
, u8
*mem
)
120 for (i
= start
; i
< end
; i
++)
126 static u16
calc_img_cksum(u16
*start
, int length
)
136 /* here we decode the incoming waveform file and populate metromem */
137 #define EXP_WFORM_SIZE 47001
138 static int load_waveform(u8
*mem
, size_t size
, u8
*metromem
, int m
, int t
,
148 int wfm_idx
, owfm_idx
;
150 struct waveform_hdr
*wfm_hdr
;
152 if (size
!= EXP_WFORM_SIZE
) {
153 printk(KERN_ERR
"Error: unexpected size %d != %d\n", size
,
158 wfm_hdr
= (struct waveform_hdr
*) mem
;
160 if (wfm_hdr
->fvsn
!= 1) {
161 printk(KERN_ERR
"Error: bad fvsn %x\n", wfm_hdr
->fvsn
);
164 if (wfm_hdr
->luts
!= 0) {
165 printk(KERN_ERR
"Error: bad luts %x\n", wfm_hdr
->luts
);
168 cksum
= calc_cksum(32, 47, mem
);
169 if (cksum
!= wfm_hdr
->wfm_cs
) {
170 printk(KERN_ERR
"Error: bad cksum %x != %x\n", cksum
,
176 for (i
= 0; i
< 5; i
++) {
177 if (*(wfm_hdr
->stuff2a
+ i
) != 0) {
178 printk(KERN_ERR
"Error: unexpected value in padding\n");
183 /* calculating trn. trn is something used to index into
184 the waveform. presumably selecting the right one for the
185 desired temperature. it works out the offset of the first
186 v that exceeds the specified temperature */
187 if ((sizeof(*wfm_hdr
) + wfm_hdr
->trc
) > size
)
190 for (i
= sizeof(*wfm_hdr
); i
<= sizeof(*wfm_hdr
) + wfm_hdr
->trc
; i
++) {
192 trn
= i
- sizeof(*wfm_hdr
) - 1;
197 /* check temperature range table checksum */
198 cksum_idx
= sizeof(*wfm_hdr
) + wfm_hdr
->trc
+ 1;
199 if (cksum_idx
> size
)
201 cksum
= calc_cksum(sizeof(*wfm_hdr
), cksum_idx
, mem
);
202 if (cksum
!= mem
[cksum_idx
]) {
203 printk(KERN_ERR
"Error: bad temperature range table cksum"
204 " %x != %x\n", cksum
, mem
[cksum_idx
]);
208 /* check waveform mode table address checksum */
209 wmta
= le32_to_cpu(get_unaligned((__le32
*) wfm_hdr
->wmta
));
211 cksum_idx
= wmta
+ m
*4 + 3;
212 if (cksum_idx
> size
)
214 cksum
= calc_cksum(cksum_idx
- 3, cksum_idx
, mem
);
215 if (cksum
!= mem
[cksum_idx
]) {
216 printk(KERN_ERR
"Error: bad mode table address cksum"
217 " %x != %x\n", cksum
, mem
[cksum_idx
]);
221 /* check waveform temperature table address checksum */
222 tta
= le32_to_cpu(get_unaligned((int *) (mem
+ wmta
+ m
*4)));
224 cksum_idx
= tta
+ trn
*4 + 3;
225 if (cksum_idx
> size
)
227 cksum
= calc_cksum(cksum_idx
- 3, cksum_idx
, mem
);
228 if (cksum
!= mem
[cksum_idx
]) {
229 printk(KERN_ERR
"Error: bad temperature table address cksum"
230 " %x != %x\n", cksum
, mem
[cksum_idx
]);
234 /* here we do the real work of putting the waveform into the
235 metromem buffer. this does runlength decoding of the waveform */
236 wfm_idx
= le32_to_cpu(get_unaligned((__le32
*) (mem
+ tta
+ trn
*4)));
237 wfm_idx
&= 0x00FFFFFF;
241 while (wfm_idx
< size
) {
244 if (v
== wfm_hdr
->swtb
) {
245 while (((v
= mem
[wfm_idx
++]) != wfm_hdr
->swtb
) &&
247 metromem
[mem_idx
++] = v
;
252 if (v
== wfm_hdr
->endb
)
256 for (i
= 0; i
<= rl
; i
++)
257 metromem
[mem_idx
++] = v
;
261 if (cksum_idx
> size
)
263 cksum
= calc_cksum(owfm_idx
, cksum_idx
, mem
);
264 if (cksum
!= mem
[cksum_idx
]) {
265 printk(KERN_ERR
"Error: bad waveform data cksum"
266 " %x != %x\n", cksum
, mem
[cksum_idx
]);
269 *frame_count
= (mem_idx
/64);
274 static int metronome_display_cmd(struct metronomefb_par
*par
)
282 /* setup display command
283 we can't immediately set the opcode since the controller
284 will try parse the command before we've set it all up
285 so we just set cs here and set the opcode at the end */
289 if (par
->metromem_cmd
->opcode
== 0xCC40)
290 opcode
= cs
= 0xCC41;
292 opcode
= cs
= 0xCC40;
294 /* set the args ( 2 bytes ) for display */
296 par
->metromem_cmd
->args
[i
] = 1 << 3 /* border update */
297 | ((borderval
++ % 4) & 0x0F) << 4
298 | (par
->frame_count
- 1) << 8;
299 cs
+= par
->metromem_cmd
->args
[i
++];
302 memset((u8
*) (par
->metromem_cmd
->args
+ i
), 0, (32-i
)*2);
304 par
->metromem_cmd
->csum
= cs
;
305 par
->metromem_cmd
->opcode
= opcode
; /* display cmd */
307 return par
->board
->met_wait_event_intr(par
);
310 static int __devinit
metronome_powerup_cmd(struct metronomefb_par
*par
)
315 /* setup power up command */
316 par
->metromem_cmd
->opcode
= 0x1234; /* pwr up pseudo cmd */
317 cs
= par
->metromem_cmd
->opcode
;
319 /* set pwr1,2,3 to 1024 */
320 for (i
= 0; i
< 3; i
++) {
321 par
->metromem_cmd
->args
[i
] = 1024;
322 cs
+= par
->metromem_cmd
->args
[i
];
326 memset((u8
*) (par
->metromem_cmd
->args
+ i
), 0, (32-i
)*2);
328 par
->metromem_cmd
->csum
= cs
;
331 par
->board
->set_rst(par
, 1);
334 par
->board
->set_stdby(par
, 1);
336 return par
->board
->met_wait_event(par
);
339 static int __devinit
metronome_config_cmd(struct metronomefb_par
*par
)
344 /* setup config command
345 we can't immediately set the opcode since the controller
346 will try parse the command before we've set it all up
347 so we just set cs here and set the opcode at the end */
351 /* set the 12 args ( 8 bytes ) for config. see spec for meanings */
353 par
->metromem_cmd
->args
[i
] = 15 /* sdlew */
356 | 0 << 12 /* sdces */
357 | 0 << 15; /* sdcer */
358 cs
+= par
->metromem_cmd
->args
[i
++];
360 par
->metromem_cmd
->args
[i
] = 42 /* gdspl */
363 | 0 << 15; /* gdspp */
364 cs
+= par
->metromem_cmd
->args
[i
++];
366 par
->metromem_cmd
->args
[i
] = 18 /* gdspw */
367 | 0 << 15; /* dispc */
368 cs
+= par
->metromem_cmd
->args
[i
++];
370 par
->metromem_cmd
->args
[i
] = 599 /* vdlc */
372 | 0 << 12; /* dsic */
373 cs
+= par
->metromem_cmd
->args
[i
++];
376 memset((u8
*) (par
->metromem_cmd
->args
+ i
), 0, (32-i
)*2);
378 par
->metromem_cmd
->csum
= cs
;
379 par
->metromem_cmd
->opcode
= 0xCC10; /* config cmd */
381 return par
->board
->met_wait_event(par
);
384 static int __devinit
metronome_init_cmd(struct metronomefb_par
*par
)
389 /* setup init command
390 we can't immediately set the opcode since the controller
391 will try parse the command before we've set it all up
392 so we just set cs here and set the opcode at the end */
396 /* set the args ( 2 bytes ) for init */
398 par
->metromem_cmd
->args
[i
] = 0;
399 cs
+= par
->metromem_cmd
->args
[i
++];
402 memset((u8
*) (par
->metromem_cmd
->args
+ i
), 0, (32-i
)*2);
404 par
->metromem_cmd
->csum
= cs
;
405 par
->metromem_cmd
->opcode
= 0xCC20; /* init cmd */
407 return par
->board
->met_wait_event(par
);
410 static int __devinit
metronome_init_regs(struct metronomefb_par
*par
)
414 par
->board
->init_gpio_regs(par
);
416 par
->board
->init_lcdc_regs(par
);
418 /* now that lcd is setup, setup dma descriptor */
419 par
->board
->post_dma_setup(par
);
421 res
= metronome_powerup_cmd(par
);
425 res
= metronome_config_cmd(par
);
429 res
= metronome_init_cmd(par
);
434 static void metronomefb_dpy_update(struct metronomefb_par
*par
)
437 unsigned char *buf
= (unsigned char __force
*)par
->info
->screen_base
;
439 /* copy from vm to metromem */
440 memcpy(par
->metromem_img
, buf
, DPY_W
*DPY_H
);
442 cksum
= calc_img_cksum((u16
*) par
->metromem_img
,
443 (epd_frame_table
[0].fw
* DPY_H
)/2);
444 *((u16
*)(par
->metromem_img
) +
445 (epd_frame_table
[0].fw
* DPY_H
)/2) = cksum
;
446 metronome_display_cmd(par
);
449 static u16
metronomefb_dpy_update_page(struct metronomefb_par
*par
, int index
)
453 u16
*buf
= (u16 __force
*)(par
->info
->screen_base
+ index
);
454 u16
*img
= (u16
*)(par
->metromem_img
+ index
);
456 /* swizzle from vm to metromem and recalc cksum at the same time*/
457 for (i
= 0; i
< PAGE_SIZE
/2; i
++) {
458 *(img
+ i
) = (buf
[i
] << 5) & 0xE0E0;
464 /* this is called back from the deferred io workqueue */
465 static void metronomefb_dpy_deferred_io(struct fb_info
*info
,
466 struct list_head
*pagelist
)
470 struct fb_deferred_io
*fbdefio
= info
->fbdefio
;
471 struct metronomefb_par
*par
= info
->par
;
473 /* walk the written page list and swizzle the data */
474 list_for_each_entry(cur
, &fbdefio
->pagelist
, lru
) {
475 cksum
= metronomefb_dpy_update_page(par
,
476 (cur
->index
<< PAGE_SHIFT
));
477 par
->metromem_img_csum
-= par
->csum_table
[cur
->index
];
478 par
->csum_table
[cur
->index
] = cksum
;
479 par
->metromem_img_csum
+= cksum
;
482 metronome_display_cmd(par
);
485 static void metronomefb_fillrect(struct fb_info
*info
,
486 const struct fb_fillrect
*rect
)
488 struct metronomefb_par
*par
= info
->par
;
490 sys_fillrect(info
, rect
);
491 metronomefb_dpy_update(par
);
494 static void metronomefb_copyarea(struct fb_info
*info
,
495 const struct fb_copyarea
*area
)
497 struct metronomefb_par
*par
= info
->par
;
499 sys_copyarea(info
, area
);
500 metronomefb_dpy_update(par
);
503 static void metronomefb_imageblit(struct fb_info
*info
,
504 const struct fb_image
*image
)
506 struct metronomefb_par
*par
= info
->par
;
508 sys_imageblit(info
, image
);
509 metronomefb_dpy_update(par
);
513 * this is the slow path from userspace. they can seek and write to
514 * the fb. it is based on fb_sys_write
516 static ssize_t
metronomefb_write(struct fb_info
*info
, const char __user
*buf
,
517 size_t count
, loff_t
*ppos
)
519 struct metronomefb_par
*par
= info
->par
;
520 unsigned long p
= *ppos
;
523 unsigned long total_size
;
525 if (info
->state
!= FBINFO_STATE_RUNNING
)
528 total_size
= info
->fix
.smem_len
;
533 if (count
> total_size
) {
538 if (count
+ p
> total_size
) {
542 count
= total_size
- p
;
545 dst
= (void __force
*)(info
->screen_base
+ p
);
547 if (copy_from_user(dst
, buf
, count
))
553 metronomefb_dpy_update(par
);
555 return (err
) ? err
: count
;
558 static struct fb_ops metronomefb_ops
= {
559 .owner
= THIS_MODULE
,
560 .fb_write
= metronomefb_write
,
561 .fb_fillrect
= metronomefb_fillrect
,
562 .fb_copyarea
= metronomefb_copyarea
,
563 .fb_imageblit
= metronomefb_imageblit
,
566 static struct fb_deferred_io metronomefb_defio
= {
568 .deferred_io
= metronomefb_dpy_deferred_io
,
571 static int __devinit
metronomefb_probe(struct platform_device
*dev
)
573 struct fb_info
*info
;
574 struct metronome_board
*board
;
575 int retval
= -ENOMEM
;
577 unsigned char *videomemory
;
578 struct metronomefb_par
*par
;
579 const struct firmware
*fw_entry
;
580 int cmd_size
, wfm_size
, img_size
, padding_size
, totalsize
;
583 /* pick up board specific routines */
584 board
= dev
->dev
.platform_data
;
588 /* try to count device specific driver, if can't, platform recalls */
589 if (!try_module_get(board
->owner
))
592 /* we have two blocks of memory.
593 info->screen_base which is vm, and is the fb used by apps.
594 par->metromem which is physically contiguous memory and
595 contains the display controller commands, waveform,
596 processed image data and padding. this is the data pulled
597 by the device's LCD controller and pushed to Metronome */
599 videomemorysize
= (DPY_W
*DPY_H
);
600 videomemory
= vmalloc(videomemorysize
);
604 memset(videomemory
, 0, videomemorysize
);
606 info
= framebuffer_alloc(sizeof(struct metronomefb_par
), &dev
->dev
);
610 info
->screen_base
= (char __force __iomem
*)videomemory
;
611 info
->fbops
= &metronomefb_ops
;
613 info
->var
= metronomefb_var
;
614 info
->fix
= metronomefb_fix
;
615 info
->fix
.smem_len
= videomemorysize
;
619 init_waitqueue_head(&par
->waitq
);
621 /* this table caches per page csum values. */
622 par
->csum_table
= vmalloc(videomemorysize
/PAGE_SIZE
);
623 if (!par
->csum_table
)
626 /* the metromem buffer is divided as follows:
627 command | CRC | padding
628 16kb waveform data | CRC | padding
630 and an extra 256 bytes for dma descriptors
631 eg: IW=832 IH=622 WS=128
634 cmd_size
= 1 * epd_frame_table
[0].fw
;
635 wfm_size
= ((16*1024 + 2 + epd_frame_table
[0].fw
- 1)
636 / epd_frame_table
[0].fw
) * epd_frame_table
[0].fw
;
637 img_size
= epd_frame_table
[0].fh
* epd_frame_table
[0].fw
;
638 padding_size
= 4 * epd_frame_table
[0].fw
;
639 totalsize
= cmd_size
+ wfm_size
+ img_size
+ padding_size
;
640 par
->metromemsize
= PAGE_ALIGN(totalsize
+ 256);
641 DPRINTK("desired memory size = %d\n", par
->metromemsize
);
642 dev
->dev
.coherent_dma_mask
= 0xffffffffull
;
643 par
->metromem
= dma_alloc_writecombine(&dev
->dev
, par
->metromemsize
,
644 &par
->metromem_dma
, GFP_KERNEL
);
645 if (!par
->metromem
) {
647 "metronomefb: unable to allocate dma buffer\n");
651 info
->fix
.smem_start
= par
->metromem_dma
;
652 par
->metromem_cmd
= (struct metromem_cmd
*) par
->metromem
;
653 par
->metromem_wfm
= par
->metromem
+ cmd_size
;
654 par
->metromem_img
= par
->metromem
+ cmd_size
+ wfm_size
;
655 par
->metromem_img_csum
= (u16
*) (par
->metromem_img
+
656 (epd_frame_table
[0].fw
* DPY_H
));
657 DPRINTK("img offset=0x%x\n", cmd_size
+ wfm_size
);
658 par
->metromem_desc
= (struct metromem_desc
*) (par
->metromem
+ cmd_size
659 + wfm_size
+ img_size
+ padding_size
);
660 par
->metromem_desc_dma
= par
->metromem_dma
+ cmd_size
+ wfm_size
661 + img_size
+ padding_size
;
663 /* load the waveform in. assume mode 3, temp 31 for now
664 a) request the waveform file from userspace
665 b) process waveform and decode into metromem */
666 retval
= request_firmware(&fw_entry
, "metronome.wbf", &dev
->dev
);
668 printk(KERN_ERR
"metronomefb: couldn't get waveform\n");
672 retval
= load_waveform((u8
*) fw_entry
->data
, fw_entry
->size
,
673 par
->metromem_wfm
, 3, 31, &par
->frame_count
);
674 release_firmware(fw_entry
);
676 printk(KERN_ERR
"metronomefb: couldn't process waveform\n");
680 if (board
->setup_irq(info
))
683 retval
= metronome_init_regs(par
);
687 info
->flags
= FBINFO_FLAG_DEFAULT
;
689 info
->fbdefio
= &metronomefb_defio
;
690 fb_deferred_io_init(info
);
692 retval
= fb_alloc_cmap(&info
->cmap
, 8, 0);
694 printk(KERN_ERR
"Failed to allocate colormap\n");
699 for (i
= 0; i
< 8; i
++)
700 info
->cmap
.red
[i
] = (((2*i
)+1)*(0xFFFF))/16;
701 memcpy(info
->cmap
.green
, info
->cmap
.red
, sizeof(u16
)*8);
702 memcpy(info
->cmap
.blue
, info
->cmap
.red
, sizeof(u16
)*8);
704 retval
= register_framebuffer(info
);
708 platform_set_drvdata(dev
, info
);
711 "fb%d: Metronome frame buffer device, using %dK of video"
712 " memory\n", info
->node
, videomemorysize
>> 10);
717 fb_dealloc_cmap(&info
->cmap
);
719 framebuffer_release(info
);
721 board
->free_irq(info
);
723 dma_free_writecombine(&dev
->dev
, par
->metromemsize
, par
->metromem
,
726 vfree(par
->csum_table
);
729 module_put(board
->owner
);
733 static int __devexit
metronomefb_remove(struct platform_device
*dev
)
735 struct fb_info
*info
= platform_get_drvdata(dev
);
738 struct metronomefb_par
*par
= info
->par
;
739 fb_deferred_io_cleanup(info
);
740 dma_free_writecombine(&dev
->dev
, par
->metromemsize
,
741 par
->metromem
, par
->metromem_dma
);
742 fb_dealloc_cmap(&info
->cmap
);
743 vfree(par
->csum_table
);
744 unregister_framebuffer(info
);
745 vfree((void __force
*)info
->screen_base
);
746 par
->board
->free_irq(info
);
747 module_put(par
->board
->owner
);
748 framebuffer_release(info
);
753 static struct platform_driver metronomefb_driver
= {
754 .probe
= metronomefb_probe
,
755 .remove
= metronomefb_remove
,
757 .owner
= THIS_MODULE
,
758 .name
= "metronomefb",
762 static int __init
metronomefb_init(void)
764 return platform_driver_register(&metronomefb_driver
);
767 static void __exit
metronomefb_exit(void)
769 platform_driver_unregister(&metronomefb_driver
);
772 module_init(metronomefb_init
);
773 module_exit(metronomefb_exit
);
775 MODULE_DESCRIPTION("fbdev driver for Metronome controller");
776 MODULE_AUTHOR("Jaya Kumar");
777 MODULE_LICENSE("GPL");