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>
43 /* Display specific information */
47 static int user_wfm_size
;
49 /* frame differs from image. frame includes non-visible pixels */
51 int fw
; /* frame width */
52 int fh
; /* frame height */
57 static struct epd_frame epd_frame_table
[] = {
66 | 0 << 15, /* sdcer */
70 | 0 << 15, /* gdspp */
72 | 0 << 15, /* dispc */
103 static struct fb_fix_screeninfo metronomefb_fix __devinitdata
= {
105 .type
= FB_TYPE_PACKED_PIXELS
,
106 .visual
= FB_VISUAL_STATIC_PSEUDOCOLOR
,
110 .line_length
= DPY_W
,
111 .accel
= FB_ACCEL_NONE
,
114 static struct fb_var_screeninfo metronomefb_var __devinitdata
= {
117 .xres_virtual
= DPY_W
,
118 .yres_virtual
= DPY_H
,
123 .green
= { 0, 0, 0 },
125 .transp
= { 0, 0, 0 },
128 /* the waveform structure that is coming from userspace firmware */
129 struct waveform_hdr
{
146 } __attribute__ ((packed
));
148 /* main metronomefb functions */
149 static u8
calc_cksum(int start
, int end
, u8
*mem
)
154 for (i
= start
; i
< end
; i
++)
160 static u16
calc_img_cksum(u16
*start
, int length
)
170 /* here we decode the incoming waveform file and populate metromem */
171 static int __devinit
load_waveform(u8
*mem
, size_t size
, int m
, int t
,
172 struct metronomefb_par
*par
)
181 int wfm_idx
, owfm_idx
;
183 struct waveform_hdr
*wfm_hdr
;
184 u8
*metromem
= par
->metromem_wfm
;
185 struct device
*dev
= par
->info
->dev
;
188 epd_frame_table
[par
->dt
].wfm_size
= user_wfm_size
;
190 if (size
!= epd_frame_table
[par
->dt
].wfm_size
) {
191 dev_err(dev
, "Error: unexpected size %Zd != %d\n", size
,
192 epd_frame_table
[par
->dt
].wfm_size
);
196 wfm_hdr
= (struct waveform_hdr
*) mem
;
198 if (wfm_hdr
->fvsn
!= 1) {
199 dev_err(dev
, "Error: bad fvsn %x\n", wfm_hdr
->fvsn
);
202 if (wfm_hdr
->luts
!= 0) {
203 dev_err(dev
, "Error: bad luts %x\n", wfm_hdr
->luts
);
206 cksum
= calc_cksum(32, 47, mem
);
207 if (cksum
!= wfm_hdr
->wfm_cs
) {
208 dev_err(dev
, "Error: bad cksum %x != %x\n", cksum
,
214 for (i
= 0; i
< 5; i
++) {
215 if (*(wfm_hdr
->stuff2a
+ i
) != 0) {
216 dev_err(dev
, "Error: unexpected value in padding\n");
221 /* calculating trn. trn is something used to index into
222 the waveform. presumably selecting the right one for the
223 desired temperature. it works out the offset of the first
224 v that exceeds the specified temperature */
225 if ((sizeof(*wfm_hdr
) + wfm_hdr
->trc
) > size
)
228 for (i
= sizeof(*wfm_hdr
); i
<= sizeof(*wfm_hdr
) + wfm_hdr
->trc
; i
++) {
230 trn
= i
- sizeof(*wfm_hdr
) - 1;
235 /* check temperature range table checksum */
236 cksum_idx
= sizeof(*wfm_hdr
) + wfm_hdr
->trc
+ 1;
237 if (cksum_idx
> size
)
239 cksum
= calc_cksum(sizeof(*wfm_hdr
), cksum_idx
, mem
);
240 if (cksum
!= mem
[cksum_idx
]) {
241 dev_err(dev
, "Error: bad temperature range table cksum"
242 " %x != %x\n", cksum
, mem
[cksum_idx
]);
246 /* check waveform mode table address checksum */
247 wmta
= get_unaligned_le32(wfm_hdr
->wmta
) & 0x00FFFFFF;
248 cksum_idx
= wmta
+ m
*4 + 3;
249 if (cksum_idx
> size
)
251 cksum
= calc_cksum(cksum_idx
- 3, cksum_idx
, mem
);
252 if (cksum
!= mem
[cksum_idx
]) {
253 dev_err(dev
, "Error: bad mode table address cksum"
254 " %x != %x\n", cksum
, mem
[cksum_idx
]);
258 /* check waveform temperature table address checksum */
259 tta
= get_unaligned_le32(mem
+ wmta
+ m
* 4) & 0x00FFFFFF;
260 cksum_idx
= tta
+ trn
*4 + 3;
261 if (cksum_idx
> size
)
263 cksum
= calc_cksum(cksum_idx
- 3, cksum_idx
, mem
);
264 if (cksum
!= mem
[cksum_idx
]) {
265 dev_err(dev
, "Error: bad temperature table address cksum"
266 " %x != %x\n", cksum
, mem
[cksum_idx
]);
270 /* here we do the real work of putting the waveform into the
271 metromem buffer. this does runlength decoding of the waveform */
272 wfm_idx
= get_unaligned_le32(mem
+ tta
+ trn
* 4) & 0x00FFFFFF;
276 while (wfm_idx
< size
) {
279 if (v
== wfm_hdr
->swtb
) {
280 while (((v
= mem
[wfm_idx
++]) != wfm_hdr
->swtb
) &&
282 metromem
[mem_idx
++] = v
;
287 if (v
== wfm_hdr
->endb
)
291 for (i
= 0; i
<= rl
; i
++)
292 metromem
[mem_idx
++] = v
;
296 if (cksum_idx
> size
)
298 cksum
= calc_cksum(owfm_idx
, cksum_idx
, mem
);
299 if (cksum
!= mem
[cksum_idx
]) {
300 dev_err(dev
, "Error: bad waveform data cksum"
301 " %x != %x\n", cksum
, mem
[cksum_idx
]);
304 par
->frame_count
= (mem_idx
/64);
309 static int metronome_display_cmd(struct metronomefb_par
*par
)
316 /* setup display command
317 we can't immediately set the opcode since the controller
318 will try parse the command before we've set it all up
319 so we just set cs here and set the opcode at the end */
321 if (par
->metromem_cmd
->opcode
== 0xCC40)
322 opcode
= cs
= 0xCC41;
324 opcode
= cs
= 0xCC40;
326 /* set the args ( 2 bytes ) for display */
328 par
->metromem_cmd
->args
[i
] = 1 << 3 /* border update */
329 | ((borderval
++ % 4) & 0x0F) << 4
330 | (par
->frame_count
- 1) << 8;
331 cs
+= par
->metromem_cmd
->args
[i
++];
334 memset((u8
*) (par
->metromem_cmd
->args
+ i
), 0, (32-i
)*2);
336 par
->metromem_cmd
->csum
= cs
;
337 par
->metromem_cmd
->opcode
= opcode
; /* display cmd */
339 return par
->board
->met_wait_event_intr(par
);
342 static int __devinit
metronome_powerup_cmd(struct metronomefb_par
*par
)
347 /* setup power up command */
348 par
->metromem_cmd
->opcode
= 0x1234; /* pwr up pseudo cmd */
349 cs
= par
->metromem_cmd
->opcode
;
351 /* set pwr1,2,3 to 1024 */
352 for (i
= 0; i
< 3; i
++) {
353 par
->metromem_cmd
->args
[i
] = 1024;
354 cs
+= par
->metromem_cmd
->args
[i
];
358 memset((u8
*) (par
->metromem_cmd
->args
+ i
), 0, (32-i
)*2);
360 par
->metromem_cmd
->csum
= cs
;
363 par
->board
->set_rst(par
, 1);
366 par
->board
->set_stdby(par
, 1);
368 return par
->board
->met_wait_event(par
);
371 static int __devinit
metronome_config_cmd(struct metronomefb_par
*par
)
373 /* setup config command
374 we can't immediately set the opcode since the controller
375 will try parse the command before we've set it all up */
377 memcpy(par
->metromem_cmd
->args
, epd_frame_table
[par
->dt
].config
,
378 sizeof(epd_frame_table
[par
->dt
].config
));
380 memset((u8
*) (par
->metromem_cmd
->args
+ 4), 0, (32-4)*2);
382 par
->metromem_cmd
->csum
= 0xCC10;
383 par
->metromem_cmd
->csum
+= calc_img_cksum(par
->metromem_cmd
->args
, 4);
384 par
->metromem_cmd
->opcode
= 0xCC10; /* config cmd */
386 return par
->board
->met_wait_event(par
);
389 static int __devinit
metronome_init_cmd(struct metronomefb_par
*par
)
394 /* setup init command
395 we can't immediately set the opcode since the controller
396 will try parse the command before we've set it all up
397 so we just set cs here and set the opcode at the end */
401 /* set the args ( 2 bytes ) for init */
403 par
->metromem_cmd
->args
[i
] = 0;
404 cs
+= par
->metromem_cmd
->args
[i
++];
407 memset((u8
*) (par
->metromem_cmd
->args
+ i
), 0, (32-i
)*2);
409 par
->metromem_cmd
->csum
= cs
;
410 par
->metromem_cmd
->opcode
= 0xCC20; /* init cmd */
412 return par
->board
->met_wait_event(par
);
415 static int __devinit
metronome_init_regs(struct metronomefb_par
*par
)
419 res
= par
->board
->setup_io(par
);
423 res
= metronome_powerup_cmd(par
);
427 res
= metronome_config_cmd(par
);
431 res
= metronome_init_cmd(par
);
436 static void metronomefb_dpy_update(struct metronomefb_par
*par
)
440 unsigned char *buf
= (unsigned char __force
*)par
->info
->screen_base
;
442 fbsize
= par
->info
->fix
.smem_len
;
443 /* copy from vm to metromem */
444 memcpy(par
->metromem_img
, buf
, fbsize
);
446 cksum
= calc_img_cksum((u16
*) par
->metromem_img
, fbsize
/2);
447 *((u16
*)(par
->metromem_img
) + fbsize
/2) = cksum
;
448 metronome_display_cmd(par
);
451 static u16
metronomefb_dpy_update_page(struct metronomefb_par
*par
, int index
)
455 u16
*buf
= (u16 __force
*)(par
->info
->screen_base
+ index
);
456 u16
*img
= (u16
*)(par
->metromem_img
+ index
);
458 /* swizzle from vm to metromem and recalc cksum at the same time*/
459 for (i
= 0; i
< PAGE_SIZE
/2; i
++) {
460 *(img
+ i
) = (buf
[i
] << 5) & 0xE0E0;
466 /* this is called back from the deferred io workqueue */
467 static void metronomefb_dpy_deferred_io(struct fb_info
*info
,
468 struct list_head
*pagelist
)
472 struct fb_deferred_io
*fbdefio
= info
->fbdefio
;
473 struct metronomefb_par
*par
= info
->par
;
475 /* walk the written page list and swizzle the data */
476 list_for_each_entry(cur
, &fbdefio
->pagelist
, lru
) {
477 cksum
= metronomefb_dpy_update_page(par
,
478 (cur
->index
<< PAGE_SHIFT
));
479 par
->metromem_img_csum
-= par
->csum_table
[cur
->index
];
480 par
->csum_table
[cur
->index
] = cksum
;
481 par
->metromem_img_csum
+= cksum
;
484 metronome_display_cmd(par
);
487 static void metronomefb_fillrect(struct fb_info
*info
,
488 const struct fb_fillrect
*rect
)
490 struct metronomefb_par
*par
= info
->par
;
492 sys_fillrect(info
, rect
);
493 metronomefb_dpy_update(par
);
496 static void metronomefb_copyarea(struct fb_info
*info
,
497 const struct fb_copyarea
*area
)
499 struct metronomefb_par
*par
= info
->par
;
501 sys_copyarea(info
, area
);
502 metronomefb_dpy_update(par
);
505 static void metronomefb_imageblit(struct fb_info
*info
,
506 const struct fb_image
*image
)
508 struct metronomefb_par
*par
= info
->par
;
510 sys_imageblit(info
, image
);
511 metronomefb_dpy_update(par
);
515 * this is the slow path from userspace. they can seek and write to
516 * the fb. it is based on fb_sys_write
518 static ssize_t
metronomefb_write(struct fb_info
*info
, const char __user
*buf
,
519 size_t count
, loff_t
*ppos
)
521 struct metronomefb_par
*par
= info
->par
;
522 unsigned long p
= *ppos
;
525 unsigned long total_size
;
527 if (info
->state
!= FBINFO_STATE_RUNNING
)
530 total_size
= info
->fix
.smem_len
;
535 if (count
> total_size
) {
540 if (count
+ p
> total_size
) {
544 count
= total_size
- p
;
547 dst
= (void __force
*)(info
->screen_base
+ p
);
549 if (copy_from_user(dst
, buf
, count
))
555 metronomefb_dpy_update(par
);
557 return (err
) ? err
: count
;
560 static struct fb_ops metronomefb_ops
= {
561 .owner
= THIS_MODULE
,
562 .fb_write
= metronomefb_write
,
563 .fb_fillrect
= metronomefb_fillrect
,
564 .fb_copyarea
= metronomefb_copyarea
,
565 .fb_imageblit
= metronomefb_imageblit
,
568 static struct fb_deferred_io metronomefb_defio
= {
570 .deferred_io
= metronomefb_dpy_deferred_io
,
573 static int __devinit
metronomefb_probe(struct platform_device
*dev
)
575 struct fb_info
*info
;
576 struct metronome_board
*board
;
577 int retval
= -ENOMEM
;
579 unsigned char *videomemory
;
580 struct metronomefb_par
*par
;
581 const struct firmware
*fw_entry
;
587 /* pick up board specific routines */
588 board
= dev
->dev
.platform_data
;
592 /* try to count device specific driver, if can't, platform recalls */
593 if (!try_module_get(board
->owner
))
596 info
= framebuffer_alloc(sizeof(struct metronomefb_par
), &dev
->dev
);
600 /* we have two blocks of memory.
601 info->screen_base which is vm, and is the fb used by apps.
602 par->metromem which is physically contiguous memory and
603 contains the display controller commands, waveform,
604 processed image data and padding. this is the data pulled
605 by the device's LCD controller and pushed to Metronome.
606 the metromem memory is allocated by the board driver and
609 panel_type
= board
->get_panel_type();
610 switch (panel_type
) {
621 dev_err(&dev
->dev
, "Unexpected panel type. Defaulting to 6\n");
626 fw
= epd_frame_table
[epd_dt_index
].fw
;
627 fh
= epd_frame_table
[epd_dt_index
].fh
;
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
);
632 videomemory
= vmalloc(videomemorysize
);
636 memset(videomemory
, 0, videomemorysize
);
638 info
->screen_base
= (char __force __iomem
*)videomemory
;
639 info
->fbops
= &metronomefb_ops
;
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
;
646 info
->var
= metronomefb_var
;
647 info
->fix
= metronomefb_fix
;
648 info
->fix
.smem_len
= videomemorysize
;
652 par
->dt
= epd_dt_index
;
653 init_waitqueue_head(&par
->waitq
);
655 /* this table caches per page csum values. */
656 par
->csum_table
= vmalloc(videomemorysize
/PAGE_SIZE
);
657 if (!par
->csum_table
)
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
);
665 dev_err(&dev
->dev
, "Failed to setup fb\n");
669 /* after this point we should have a framebuffer */
670 if ((!par
->metromem_wfm
) || (!par
->metromem_img
) ||
671 (!par
->metromem_dma
)) {
672 dev_err(&dev
->dev
, "fb access failure\n");
677 info
->fix
.smem_start
= par
->metromem_dma
;
679 /* load the waveform in. assume mode 3, temp 31 for now
680 a) request the waveform file from userspace
681 b) process waveform and decode into metromem */
682 retval
= request_firmware(&fw_entry
, "metronome.wbf", &dev
->dev
);
684 dev_err(&dev
->dev
, "Failed to get waveform\n");
688 retval
= load_waveform((u8
*) fw_entry
->data
, fw_entry
->size
, 3, 31,
690 release_firmware(fw_entry
);
692 dev_err(&dev
->dev
, "Failed processing waveform\n");
696 if (board
->setup_irq(info
))
699 retval
= metronome_init_regs(par
);
703 info
->flags
= FBINFO_FLAG_DEFAULT
| FBINFO_VIRTFB
;
705 info
->fbdefio
= &metronomefb_defio
;
706 fb_deferred_io_init(info
);
708 retval
= fb_alloc_cmap(&info
->cmap
, 8, 0);
710 dev_err(&dev
->dev
, "Failed to allocate colormap\n");
715 for (i
= 0; i
< 8; i
++)
716 info
->cmap
.red
[i
] = (((2*i
)+1)*(0xFFFF))/16;
717 memcpy(info
->cmap
.green
, info
->cmap
.red
, sizeof(u16
)*8);
718 memcpy(info
->cmap
.blue
, info
->cmap
.red
, sizeof(u16
)*8);
720 retval
= register_framebuffer(info
);
724 platform_set_drvdata(dev
, info
);
727 "fb%d: Metronome frame buffer device, using %dK of video"
728 " memory\n", info
->node
, videomemorysize
>> 10);
733 fb_dealloc_cmap(&info
->cmap
);
737 vfree(par
->csum_table
);
741 framebuffer_release(info
);
743 module_put(board
->owner
);
747 static int __devexit
metronomefb_remove(struct platform_device
*dev
)
749 struct fb_info
*info
= platform_get_drvdata(dev
);
752 struct metronomefb_par
*par
= info
->par
;
754 unregister_framebuffer(info
);
755 fb_deferred_io_cleanup(info
);
756 fb_dealloc_cmap(&info
->cmap
);
757 par
->board
->cleanup(par
);
758 vfree(par
->csum_table
);
759 vfree((void __force
*)info
->screen_base
);
760 module_put(par
->board
->owner
);
761 dev_dbg(&dev
->dev
, "calling release\n");
762 framebuffer_release(info
);
767 static struct platform_driver metronomefb_driver
= {
768 .probe
= metronomefb_probe
,
769 .remove
= metronomefb_remove
,
771 .owner
= THIS_MODULE
,
772 .name
= "metronomefb",
776 static int __init
metronomefb_init(void)
778 return platform_driver_register(&metronomefb_driver
);
781 static void __exit
metronomefb_exit(void)
783 platform_driver_unregister(&metronomefb_driver
);
786 module_param(user_wfm_size
, uint
, 0);
787 MODULE_PARM_DESC(user_wfm_size
, "Set custom waveform size");
789 module_init(metronomefb_init
);
790 module_exit(metronomefb_exit
);
792 MODULE_DESCRIPTION("fbdev driver for Metronome controller");
793 MODULE_AUTHOR("Jaya Kumar");
794 MODULE_LICENSE("GPL");