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. https://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 <linux/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
->device
;
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
= par
->info
->screen_buffer
;
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
*)(par
->info
->screen_buffer
+ 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
, struct list_head
*pagereflist
)
471 struct fb_deferred_io_pageref
*pageref
;
472 struct metronomefb_par
*par
= info
->par
;
474 /* walk the written page list and swizzle the data */
475 list_for_each_entry(pageref
, pagereflist
, list
) {
476 unsigned long pgoffset
= pageref
->offset
>> PAGE_SHIFT
;
477 cksum
= metronomefb_dpy_update_page(par
, pageref
->offset
);
478 par
->metromem_img_csum
-= par
->csum_table
[pgoffset
];
479 par
->csum_table
[pgoffset
] = cksum
;
480 par
->metromem_img_csum
+= cksum
;
483 metronome_display_cmd(par
);
486 static void metronomefb_defio_damage_range(struct fb_info
*info
, off_t off
, size_t len
)
488 struct metronomefb_par
*par
= info
->par
;
490 metronomefb_dpy_update(par
);
493 static void metronomefb_defio_damage_area(struct fb_info
*info
, u32 x
, u32 y
,
494 u32 width
, u32 height
)
496 struct metronomefb_par
*par
= info
->par
;
498 metronomefb_dpy_update(par
);
501 FB_GEN_DEFAULT_DEFERRED_SYSMEM_OPS(metronomefb
,
502 metronomefb_defio_damage_range
,
503 metronomefb_defio_damage_area
)
505 static const struct fb_ops metronomefb_ops
= {
506 .owner
= THIS_MODULE
,
507 FB_DEFAULT_DEFERRED_OPS(metronomefb
),
510 static struct fb_deferred_io metronomefb_defio
= {
512 .sort_pagereflist
= true,
513 .deferred_io
= metronomefb_dpy_deferred_io
,
516 static int metronomefb_probe(struct platform_device
*dev
)
518 struct fb_info
*info
;
519 struct metronome_board
*board
;
520 int retval
= -ENOMEM
;
522 unsigned char *videomemory
;
523 struct metronomefb_par
*par
;
524 const struct firmware
*fw_entry
;
530 /* pick up board specific routines */
531 board
= dev
->dev
.platform_data
;
535 /* try to count device specific driver, if can't, platform recalls */
536 if (!try_module_get(board
->owner
))
539 info
= framebuffer_alloc(sizeof(struct metronomefb_par
), &dev
->dev
);
543 /* we have two blocks of memory.
544 info->screen_buffer which is vm, and is the fb used by apps.
545 par->metromem which is physically contiguous memory and
546 contains the display controller commands, waveform,
547 processed image data and padding. this is the data pulled
548 by the device's LCD controller and pushed to Metronome.
549 the metromem memory is allocated by the board driver and
552 panel_type
= board
->get_panel_type();
553 switch (panel_type
) {
564 dev_err(&dev
->dev
, "Unexpected panel type. Defaulting to 6\n");
569 fw
= epd_frame_table
[epd_dt_index
].fw
;
570 fh
= epd_frame_table
[epd_dt_index
].fh
;
572 /* we need to add a spare page because our csum caching scheme walks
573 * to the end of the page */
574 videomemorysize
= PAGE_SIZE
+ (fw
* fh
);
575 videomemory
= vzalloc(videomemorysize
);
579 info
->screen_buffer
= videomemory
;
580 info
->fbops
= &metronomefb_ops
;
582 metronomefb_fix
.line_length
= fw
;
583 metronomefb_var
.xres
= fw
;
584 metronomefb_var
.yres
= fh
;
585 metronomefb_var
.xres_virtual
= fw
;
586 metronomefb_var
.yres_virtual
= fh
;
587 info
->var
= metronomefb_var
;
588 info
->fix
= metronomefb_fix
;
589 info
->fix
.smem_len
= videomemorysize
;
593 par
->dt
= epd_dt_index
;
594 init_waitqueue_head(&par
->waitq
);
596 /* this table caches per page csum values. */
597 par
->csum_table
= vmalloc(videomemorysize
/PAGE_SIZE
);
598 if (!par
->csum_table
)
601 /* the physical framebuffer that we use is setup by
602 * the platform device driver. It will provide us
603 * with cmd, wfm and image memory in a contiguous area. */
604 retval
= board
->setup_fb(par
);
606 dev_err(&dev
->dev
, "Failed to setup fb\n");
610 /* after this point we should have a framebuffer */
611 if ((!par
->metromem_wfm
) || (!par
->metromem_img
) ||
612 (!par
->metromem_dma
)) {
613 dev_err(&dev
->dev
, "fb access failure\n");
618 info
->fix
.smem_start
= par
->metromem_dma
;
620 /* load the waveform in. assume mode 3, temp 31 for now
621 a) request the waveform file from userspace
622 b) process waveform and decode into metromem */
623 retval
= request_firmware(&fw_entry
, "metronome.wbf", &dev
->dev
);
625 dev_err(&dev
->dev
, "Failed to get waveform\n");
629 retval
= load_waveform((u8
*) fw_entry
->data
, fw_entry
->size
, 3, 31,
631 release_firmware(fw_entry
);
633 dev_err(&dev
->dev
, "Failed processing waveform\n");
637 retval
= board
->setup_irq(info
);
641 retval
= metronome_init_regs(par
);
645 info
->flags
= FBINFO_VIRTFB
;
647 info
->fbdefio
= &metronomefb_defio
;
648 fb_deferred_io_init(info
);
650 retval
= fb_alloc_cmap(&info
->cmap
, 8, 0);
652 dev_err(&dev
->dev
, "Failed to allocate colormap\n");
657 for (i
= 0; i
< 8; i
++)
658 info
->cmap
.red
[i
] = (((2*i
)+1)*(0xFFFF))/16;
659 memcpy(info
->cmap
.green
, info
->cmap
.red
, sizeof(u16
)*8);
660 memcpy(info
->cmap
.blue
, info
->cmap
.red
, sizeof(u16
)*8);
662 retval
= register_framebuffer(info
);
666 platform_set_drvdata(dev
, info
);
669 "fb%d: Metronome frame buffer device, using %dK of video"
670 " memory\n", info
->node
, videomemorysize
>> 10);
675 fb_dealloc_cmap(&info
->cmap
);
679 vfree(par
->csum_table
);
683 framebuffer_release(info
);
685 module_put(board
->owner
);
689 static void metronomefb_remove(struct platform_device
*dev
)
691 struct fb_info
*info
= platform_get_drvdata(dev
);
694 struct metronomefb_par
*par
= info
->par
;
696 unregister_framebuffer(info
);
697 fb_deferred_io_cleanup(info
);
698 fb_dealloc_cmap(&info
->cmap
);
699 par
->board
->cleanup(par
);
700 vfree(par
->csum_table
);
701 vfree(info
->screen_buffer
);
702 module_put(par
->board
->owner
);
703 dev_dbg(&dev
->dev
, "calling release\n");
704 framebuffer_release(info
);
708 static struct platform_driver metronomefb_driver
= {
709 .probe
= metronomefb_probe
,
710 .remove
= metronomefb_remove
,
712 .name
= "metronomefb",
715 module_platform_driver(metronomefb_driver
);
717 module_param(user_wfm_size
, uint
, 0);
718 MODULE_PARM_DESC(user_wfm_size
, "Set custom waveform size");
720 MODULE_DESCRIPTION("fbdev driver for Metronome controller");
721 MODULE_AUTHOR("Jaya Kumar");
722 MODULE_LICENSE("GPL");
724 MODULE_FIRMWARE("metronome.wbf");