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://www.eink.com/
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/vmalloc.h>
27 #include <linux/delay.h>
28 #include <linux/interrupt.h>
30 #include <linux/init.h>
31 #include <linux/platform_device.h>
32 #include <linux/list.h>
33 #include <linux/firmware.h>
34 #include <linux/dma-mapping.h>
35 #include <linux/uaccess.h>
36 #include <linux/irq.h>
38 #include <video/metronomefb.h>
40 #include <asm/unaligned.h>
42 /* Display specific information */
46 static int user_wfm_size
;
48 /* frame differs from image. frame includes non-visible pixels */
50 int fw
; /* frame width */
51 int fh
; /* frame height */
56 static struct epd_frame epd_frame_table
[] = {
65 | 0 << 15, /* sdcer */
69 | 0 << 15, /* gdspp */
71 | 0 << 15, /* dispc */
102 static struct fb_fix_screeninfo metronomefb_fix
= {
104 .type
= FB_TYPE_PACKED_PIXELS
,
105 .visual
= FB_VISUAL_STATIC_PSEUDOCOLOR
,
109 .line_length
= DPY_W
,
110 .accel
= FB_ACCEL_NONE
,
113 static struct fb_var_screeninfo metronomefb_var
= {
116 .xres_virtual
= DPY_W
,
117 .yres_virtual
= DPY_H
,
122 .green
= { 0, 0, 0 },
124 .transp
= { 0, 0, 0 },
127 /* the waveform structure that is coming from userspace firmware */
128 struct waveform_hdr
{
145 } __attribute__ ((packed
));
147 /* main metronomefb functions */
148 static u8
calc_cksum(int start
, int end
, u8
*mem
)
153 for (i
= start
; i
< end
; i
++)
159 static u16
calc_img_cksum(u16
*start
, int length
)
169 /* here we decode the incoming waveform file and populate metromem */
170 static int load_waveform(u8
*mem
, size_t size
, int m
, int t
,
171 struct metronomefb_par
*par
)
180 int wfm_idx
, owfm_idx
;
182 struct waveform_hdr
*wfm_hdr
;
183 u8
*metromem
= par
->metromem_wfm
;
184 struct device
*dev
= par
->info
->dev
;
187 epd_frame_table
[par
->dt
].wfm_size
= user_wfm_size
;
189 if (size
!= epd_frame_table
[par
->dt
].wfm_size
) {
190 dev_err(dev
, "Error: unexpected size %zd != %d\n", size
,
191 epd_frame_table
[par
->dt
].wfm_size
);
195 wfm_hdr
= (struct waveform_hdr
*) mem
;
197 if (wfm_hdr
->fvsn
!= 1) {
198 dev_err(dev
, "Error: bad fvsn %x\n", wfm_hdr
->fvsn
);
201 if (wfm_hdr
->luts
!= 0) {
202 dev_err(dev
, "Error: bad luts %x\n", wfm_hdr
->luts
);
205 cksum
= calc_cksum(32, 47, mem
);
206 if (cksum
!= wfm_hdr
->wfm_cs
) {
207 dev_err(dev
, "Error: bad cksum %x != %x\n", cksum
,
213 for (i
= 0; i
< 5; i
++) {
214 if (*(wfm_hdr
->stuff2a
+ i
) != 0) {
215 dev_err(dev
, "Error: unexpected value in padding\n");
220 /* calculating trn. trn is something used to index into
221 the waveform. presumably selecting the right one for the
222 desired temperature. it works out the offset of the first
223 v that exceeds the specified temperature */
224 if ((sizeof(*wfm_hdr
) + wfm_hdr
->trc
) > size
)
227 for (i
= sizeof(*wfm_hdr
); i
<= sizeof(*wfm_hdr
) + wfm_hdr
->trc
; i
++) {
229 trn
= i
- sizeof(*wfm_hdr
) - 1;
234 /* check temperature range table checksum */
235 cksum_idx
= sizeof(*wfm_hdr
) + wfm_hdr
->trc
+ 1;
236 if (cksum_idx
>= size
)
238 cksum
= calc_cksum(sizeof(*wfm_hdr
), cksum_idx
, mem
);
239 if (cksum
!= mem
[cksum_idx
]) {
240 dev_err(dev
, "Error: bad temperature range table cksum"
241 " %x != %x\n", cksum
, mem
[cksum_idx
]);
245 /* check waveform mode table address checksum */
246 wmta
= get_unaligned_le32(wfm_hdr
->wmta
) & 0x00FFFFFF;
247 cksum_idx
= wmta
+ m
*4 + 3;
248 if (cksum_idx
>= size
)
250 cksum
= calc_cksum(cksum_idx
- 3, cksum_idx
, mem
);
251 if (cksum
!= mem
[cksum_idx
]) {
252 dev_err(dev
, "Error: bad mode table address cksum"
253 " %x != %x\n", cksum
, mem
[cksum_idx
]);
257 /* check waveform temperature table address checksum */
258 tta
= get_unaligned_le32(mem
+ wmta
+ m
* 4) & 0x00FFFFFF;
259 cksum_idx
= tta
+ trn
*4 + 3;
260 if (cksum_idx
>= size
)
262 cksum
= calc_cksum(cksum_idx
- 3, cksum_idx
, mem
);
263 if (cksum
!= mem
[cksum_idx
]) {
264 dev_err(dev
, "Error: bad temperature table address cksum"
265 " %x != %x\n", cksum
, mem
[cksum_idx
]);
269 /* here we do the real work of putting the waveform into the
270 metromem buffer. this does runlength decoding of the waveform */
271 wfm_idx
= get_unaligned_le32(mem
+ tta
+ trn
* 4) & 0x00FFFFFF;
275 while (wfm_idx
< size
) {
278 if (v
== wfm_hdr
->swtb
) {
279 while (((v
= mem
[wfm_idx
++]) != wfm_hdr
->swtb
) &&
281 metromem
[mem_idx
++] = v
;
286 if (v
== wfm_hdr
->endb
)
290 for (i
= 0; i
<= rl
; i
++)
291 metromem
[mem_idx
++] = v
;
295 if (cksum_idx
>= size
)
297 cksum
= calc_cksum(owfm_idx
, cksum_idx
, mem
);
298 if (cksum
!= mem
[cksum_idx
]) {
299 dev_err(dev
, "Error: bad waveform data cksum"
300 " %x != %x\n", cksum
, mem
[cksum_idx
]);
303 par
->frame_count
= (mem_idx
/64);
308 static int metronome_display_cmd(struct metronomefb_par
*par
)
315 /* setup display command
316 we can't immediately set the opcode since the controller
317 will try parse the command before we've set it all up
318 so we just set cs here and set the opcode at the end */
320 if (par
->metromem_cmd
->opcode
== 0xCC40)
321 opcode
= cs
= 0xCC41;
323 opcode
= cs
= 0xCC40;
325 /* set the args ( 2 bytes ) for display */
327 par
->metromem_cmd
->args
[i
] = 1 << 3 /* border update */
328 | ((borderval
++ % 4) & 0x0F) << 4
329 | (par
->frame_count
- 1) << 8;
330 cs
+= par
->metromem_cmd
->args
[i
++];
333 memset((u8
*) (par
->metromem_cmd
->args
+ i
), 0, (32-i
)*2);
335 par
->metromem_cmd
->csum
= cs
;
336 par
->metromem_cmd
->opcode
= opcode
; /* display cmd */
338 return par
->board
->met_wait_event_intr(par
);
341 static int metronome_powerup_cmd(struct metronomefb_par
*par
)
346 /* setup power up command */
347 par
->metromem_cmd
->opcode
= 0x1234; /* pwr up pseudo cmd */
348 cs
= par
->metromem_cmd
->opcode
;
350 /* set pwr1,2,3 to 1024 */
351 for (i
= 0; i
< 3; i
++) {
352 par
->metromem_cmd
->args
[i
] = 1024;
353 cs
+= par
->metromem_cmd
->args
[i
];
357 memset(&par
->metromem_cmd
->args
[i
], 0,
358 (ARRAY_SIZE(par
->metromem_cmd
->args
) - 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 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(&par
->metromem_cmd
->args
[4], 0,
381 (ARRAY_SIZE(par
->metromem_cmd
->args
) - 4) * 2);
383 par
->metromem_cmd
->csum
= 0xCC10;
384 par
->metromem_cmd
->csum
+= calc_img_cksum(par
->metromem_cmd
->args
, 4);
385 par
->metromem_cmd
->opcode
= 0xCC10; /* config cmd */
387 return par
->board
->met_wait_event(par
);
390 static int metronome_init_cmd(struct metronomefb_par
*par
)
395 /* setup init command
396 we can't immediately set the opcode since the controller
397 will try parse the command before we've set it all up
398 so we just set cs here and set the opcode at the end */
402 /* set the args ( 2 bytes ) for init */
404 par
->metromem_cmd
->args
[i
] = 0;
405 cs
+= par
->metromem_cmd
->args
[i
++];
408 memset((u8
*) (par
->metromem_cmd
->args
+ i
), 0, (32-i
)*2);
410 par
->metromem_cmd
->csum
= cs
;
411 par
->metromem_cmd
->opcode
= 0xCC20; /* init cmd */
413 return par
->board
->met_wait_event(par
);
416 static int metronome_init_regs(struct metronomefb_par
*par
)
420 res
= par
->board
->setup_io(par
);
424 res
= metronome_powerup_cmd(par
);
428 res
= metronome_config_cmd(par
);
432 res
= metronome_init_cmd(par
);
437 static void metronomefb_dpy_update(struct metronomefb_par
*par
)
441 unsigned char *buf
= (unsigned char __force
*)par
->info
->screen_base
;
443 fbsize
= par
->info
->fix
.smem_len
;
444 /* copy from vm to metromem */
445 memcpy(par
->metromem_img
, buf
, fbsize
);
447 cksum
= calc_img_cksum((u16
*) par
->metromem_img
, fbsize
/2);
448 *((u16
*)(par
->metromem_img
) + fbsize
/2) = cksum
;
449 metronome_display_cmd(par
);
452 static u16
metronomefb_dpy_update_page(struct metronomefb_par
*par
, int index
)
456 u16
*buf
= (u16 __force
*)(par
->info
->screen_base
+ index
);
457 u16
*img
= (u16
*)(par
->metromem_img
+ index
);
459 /* swizzle from vm to metromem and recalc cksum at the same time*/
460 for (i
= 0; i
< PAGE_SIZE
/2; i
++) {
461 *(img
+ i
) = (buf
[i
] << 5) & 0xE0E0;
467 /* this is called back from the deferred io workqueue */
468 static void metronomefb_dpy_deferred_io(struct fb_info
*info
,
469 struct list_head
*pagelist
)
473 struct fb_deferred_io
*fbdefio
= info
->fbdefio
;
474 struct metronomefb_par
*par
= info
->par
;
476 /* walk the written page list and swizzle the data */
477 list_for_each_entry(cur
, &fbdefio
->pagelist
, lru
) {
478 cksum
= metronomefb_dpy_update_page(par
,
479 (cur
->index
<< PAGE_SHIFT
));
480 par
->metromem_img_csum
-= par
->csum_table
[cur
->index
];
481 par
->csum_table
[cur
->index
] = cksum
;
482 par
->metromem_img_csum
+= cksum
;
485 metronome_display_cmd(par
);
488 static void metronomefb_fillrect(struct fb_info
*info
,
489 const struct fb_fillrect
*rect
)
491 struct metronomefb_par
*par
= info
->par
;
493 sys_fillrect(info
, rect
);
494 metronomefb_dpy_update(par
);
497 static void metronomefb_copyarea(struct fb_info
*info
,
498 const struct fb_copyarea
*area
)
500 struct metronomefb_par
*par
= info
->par
;
502 sys_copyarea(info
, area
);
503 metronomefb_dpy_update(par
);
506 static void metronomefb_imageblit(struct fb_info
*info
,
507 const struct fb_image
*image
)
509 struct metronomefb_par
*par
= info
->par
;
511 sys_imageblit(info
, image
);
512 metronomefb_dpy_update(par
);
516 * this is the slow path from userspace. they can seek and write to
517 * the fb. it is based on fb_sys_write
519 static ssize_t
metronomefb_write(struct fb_info
*info
, const char __user
*buf
,
520 size_t count
, loff_t
*ppos
)
522 struct metronomefb_par
*par
= info
->par
;
523 unsigned long p
= *ppos
;
526 unsigned long total_size
;
528 if (info
->state
!= FBINFO_STATE_RUNNING
)
531 total_size
= info
->fix
.smem_len
;
536 if (count
> total_size
) {
541 if (count
+ p
> total_size
) {
545 count
= total_size
- p
;
548 dst
= (void __force
*)(info
->screen_base
+ p
);
550 if (copy_from_user(dst
, buf
, count
))
556 metronomefb_dpy_update(par
);
558 return (err
) ? err
: count
;
561 static struct fb_ops metronomefb_ops
= {
562 .owner
= THIS_MODULE
,
563 .fb_write
= metronomefb_write
,
564 .fb_fillrect
= metronomefb_fillrect
,
565 .fb_copyarea
= metronomefb_copyarea
,
566 .fb_imageblit
= metronomefb_imageblit
,
569 static struct fb_deferred_io metronomefb_defio
= {
571 .deferred_io
= metronomefb_dpy_deferred_io
,
574 static int metronomefb_probe(struct platform_device
*dev
)
576 struct fb_info
*info
;
577 struct metronome_board
*board
;
578 int retval
= -ENOMEM
;
580 unsigned char *videomemory
;
581 struct metronomefb_par
*par
;
582 const struct firmware
*fw_entry
;
588 /* pick up board specific routines */
589 board
= dev
->dev
.platform_data
;
593 /* try to count device specific driver, if can't, platform recalls */
594 if (!try_module_get(board
->owner
))
597 info
= framebuffer_alloc(sizeof(struct metronomefb_par
), &dev
->dev
);
601 /* we have two blocks of memory.
602 info->screen_base which is vm, and is the fb used by apps.
603 par->metromem which is physically contiguous memory and
604 contains the display controller commands, waveform,
605 processed image data and padding. this is the data pulled
606 by the device's LCD controller and pushed to Metronome.
607 the metromem memory is allocated by the board driver and
610 panel_type
= board
->get_panel_type();
611 switch (panel_type
) {
622 dev_err(&dev
->dev
, "Unexpected panel type. Defaulting to 6\n");
627 fw
= epd_frame_table
[epd_dt_index
].fw
;
628 fh
= epd_frame_table
[epd_dt_index
].fh
;
630 /* we need to add a spare page because our csum caching scheme walks
631 * to the end of the page */
632 videomemorysize
= PAGE_SIZE
+ (fw
* fh
);
633 videomemory
= vzalloc(videomemorysize
);
637 info
->screen_base
= (char __force __iomem
*)videomemory
;
638 info
->fbops
= &metronomefb_ops
;
640 metronomefb_fix
.line_length
= fw
;
641 metronomefb_var
.xres
= fw
;
642 metronomefb_var
.yres
= fh
;
643 metronomefb_var
.xres_virtual
= fw
;
644 metronomefb_var
.yres_virtual
= fh
;
645 info
->var
= metronomefb_var
;
646 info
->fix
= metronomefb_fix
;
647 info
->fix
.smem_len
= videomemorysize
;
651 par
->dt
= epd_dt_index
;
652 init_waitqueue_head(&par
->waitq
);
654 /* this table caches per page csum values. */
655 par
->csum_table
= vmalloc(videomemorysize
/PAGE_SIZE
);
656 if (!par
->csum_table
)
659 /* the physical framebuffer that we use is setup by
660 * the platform device driver. It will provide us
661 * with cmd, wfm and image memory in a contiguous area. */
662 retval
= board
->setup_fb(par
);
664 dev_err(&dev
->dev
, "Failed to setup fb\n");
668 /* after this point we should have a framebuffer */
669 if ((!par
->metromem_wfm
) || (!par
->metromem_img
) ||
670 (!par
->metromem_dma
)) {
671 dev_err(&dev
->dev
, "fb access failure\n");
676 info
->fix
.smem_start
= par
->metromem_dma
;
678 /* load the waveform in. assume mode 3, temp 31 for now
679 a) request the waveform file from userspace
680 b) process waveform and decode into metromem */
681 retval
= request_firmware(&fw_entry
, "metronome.wbf", &dev
->dev
);
683 dev_err(&dev
->dev
, "Failed to get waveform\n");
687 retval
= load_waveform((u8
*) fw_entry
->data
, fw_entry
->size
, 3, 31,
689 release_firmware(fw_entry
);
691 dev_err(&dev
->dev
, "Failed processing waveform\n");
695 retval
= 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 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 .name
= "metronomefb",
774 module_platform_driver(metronomefb_driver
);
776 module_param(user_wfm_size
, uint
, 0);
777 MODULE_PARM_DESC(user_wfm_size
, "Set custom waveform size");
779 MODULE_DESCRIPTION("fbdev driver for Metronome controller");
780 MODULE_AUTHOR("Jaya Kumar");
781 MODULE_LICENSE("GPL");