Full support for Ginger Console
[linux-ginger.git] / drivers / video / metronomefb.c
blobdf1f757a6161cde2f7d189be4501567af96fd6f2
1 /*
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
8 * more details.
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>
25 #include <linux/mm.h>
26 #include <linux/slab.h>
27 #include <linux/vmalloc.h>
28 #include <linux/delay.h>
29 #include <linux/interrupt.h>
30 #include <linux/fb.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 */
44 #define DPY_W 832
45 #define DPY_H 622
47 static int user_wfm_size;
49 /* frame differs from image. frame includes non-visible pixels */
50 struct epd_frame {
51 int fw; /* frame width */
52 int fh; /* frame height */
53 u16 config[4];
54 int wfm_size;
57 static struct epd_frame epd_frame_table[] = {
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 */
77 .wfm_size = 47001,
80 .fw = 1088,
81 .fh = 791,
82 .config = {
83 0x0104,
84 0x031f,
85 0x0088,
86 0x02ff,
88 .wfm_size = 46770,
91 .fw = 1200,
92 .fh = 842,
93 .config = {
94 0x0101,
95 0x030e,
96 0x0012,
97 0x0280,
99 .wfm_size = 46770,
103 static struct fb_fix_screeninfo metronomefb_fix __devinitdata = {
104 .id = "metronomefb",
105 .type = FB_TYPE_PACKED_PIXELS,
106 .visual = FB_VISUAL_STATIC_PSEUDOCOLOR,
107 .xpanstep = 0,
108 .ypanstep = 0,
109 .ywrapstep = 0,
110 .line_length = DPY_W,
111 .accel = FB_ACCEL_NONE,
114 static struct fb_var_screeninfo metronomefb_var __devinitdata = {
115 .xres = DPY_W,
116 .yres = DPY_H,
117 .xres_virtual = DPY_W,
118 .yres_virtual = DPY_H,
119 .bits_per_pixel = 8,
120 .grayscale = 1,
121 .nonstd = 1,
122 .red = { 4, 3, 0 },
123 .green = { 0, 0, 0 },
124 .blue = { 0, 0, 0 },
125 .transp = { 0, 0, 0 },
128 /* the waveform structure that is coming from userspace firmware */
129 struct waveform_hdr {
130 u8 stuff[32];
132 u8 wmta[3];
133 u8 fvsn;
135 u8 luts;
136 u8 mc;
137 u8 trc;
138 u8 stuff3;
140 u8 endb;
141 u8 swtb;
142 u8 stuff2a[2];
144 u8 stuff2b[3];
145 u8 wfm_cs;
146 } __attribute__ ((packed));
148 /* main metronomefb functions */
149 static u8 calc_cksum(int start, int end, u8 *mem)
151 u8 tmp = 0;
152 int i;
154 for (i = start; i < end; i++)
155 tmp += mem[i];
157 return tmp;
160 static u16 calc_img_cksum(u16 *start, int length)
162 u16 tmp = 0;
164 while (length--)
165 tmp += *start++;
167 return tmp;
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)
174 int tta;
175 int wmta;
176 int trn = 0;
177 int i;
178 unsigned char v;
179 u8 cksum;
180 int cksum_idx;
181 int wfm_idx, owfm_idx;
182 int mem_idx = 0;
183 struct waveform_hdr *wfm_hdr;
184 u8 *metromem = par->metromem_wfm;
185 struct device *dev = par->info->dev;
187 if (user_wfm_size)
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);
193 return -EINVAL;
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);
200 return -EINVAL;
202 if (wfm_hdr->luts != 0) {
203 dev_err(dev, "Error: bad luts %x\n", wfm_hdr->luts);
204 return -EINVAL;
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,
209 wfm_hdr->wfm_cs);
210 return -EINVAL;
212 wfm_hdr->mc += 1;
213 wfm_hdr->trc += 1;
214 for (i = 0; i < 5; i++) {
215 if (*(wfm_hdr->stuff2a + i) != 0) {
216 dev_err(dev, "Error: unexpected value in padding\n");
217 return -EINVAL;
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)
226 return -EINVAL;
228 for (i = sizeof(*wfm_hdr); i <= sizeof(*wfm_hdr) + wfm_hdr->trc; i++) {
229 if (mem[i] > t) {
230 trn = i - sizeof(*wfm_hdr) - 1;
231 break;
235 /* check temperature range table checksum */
236 cksum_idx = sizeof(*wfm_hdr) + wfm_hdr->trc + 1;
237 if (cksum_idx > size)
238 return -EINVAL;
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]);
243 return -EINVAL;
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)
250 return -EINVAL;
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]);
255 return -EINVAL;
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)
262 return -EINVAL;
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]);
267 return -EINVAL;
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;
273 owfm_idx = wfm_idx;
274 if (wfm_idx > size)
275 return -EINVAL;
276 while (wfm_idx < size) {
277 unsigned char rl;
278 v = mem[wfm_idx++];
279 if (v == wfm_hdr->swtb) {
280 while (((v = mem[wfm_idx++]) != wfm_hdr->swtb) &&
281 wfm_idx < size)
282 metromem[mem_idx++] = v;
284 continue;
287 if (v == wfm_hdr->endb)
288 break;
290 rl = mem[wfm_idx++];
291 for (i = 0; i <= rl; i++)
292 metromem[mem_idx++] = v;
295 cksum_idx = wfm_idx;
296 if (cksum_idx > size)
297 return -EINVAL;
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]);
302 return -EINVAL;
304 par->frame_count = (mem_idx/64);
306 return 0;
309 static int metronome_display_cmd(struct metronomefb_par *par)
311 int i;
312 u16 cs;
313 u16 opcode;
314 static u8 borderval;
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;
323 else
324 opcode = cs = 0xCC40;
326 /* set the args ( 2 bytes ) for display */
327 i = 0;
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++];
333 /* the rest are 0 */
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)
344 int i;
345 u16 cs;
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];
357 /* the rest are 0 */
358 memset((u8 *) (par->metromem_cmd->args + i), 0, (32-i)*2);
360 par->metromem_cmd->csum = cs;
362 msleep(1);
363 par->board->set_rst(par, 1);
365 msleep(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));
379 /* the rest are 0 */
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)
391 int i;
392 u16 cs;
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 */
399 cs = 0xCC20;
401 /* set the args ( 2 bytes ) for init */
402 i = 0;
403 par->metromem_cmd->args[i] = 0;
404 cs += par->metromem_cmd->args[i++];
406 /* the rest are 0 */
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)
417 int res;
419 res = par->board->setup_io(par);
420 if (res)
421 return res;
423 res = metronome_powerup_cmd(par);
424 if (res)
425 return res;
427 res = metronome_config_cmd(par);
428 if (res)
429 return res;
431 res = metronome_init_cmd(par);
433 return res;
436 static void metronomefb_dpy_update(struct metronomefb_par *par)
438 int fbsize;
439 u16 cksum;
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)
453 int i;
454 u16 csum = 0;
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;
461 csum += *(img + i);
463 return csum;
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)
470 u16 cksum;
471 struct page *cur;
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;
523 void *dst;
524 int err = 0;
525 unsigned long total_size;
527 if (info->state != FBINFO_STATE_RUNNING)
528 return -EPERM;
530 total_size = info->fix.smem_len;
532 if (p > total_size)
533 return -EFBIG;
535 if (count > total_size) {
536 err = -EFBIG;
537 count = total_size;
540 if (count + p > total_size) {
541 if (!err)
542 err = -ENOSPC;
544 count = total_size - p;
547 dst = (void __force *)(info->screen_base + p);
549 if (copy_from_user(dst, buf, count))
550 err = -EFAULT;
552 if (!err)
553 *ppos += 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 = {
569 .delay = HZ,
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;
578 int videomemorysize;
579 unsigned char *videomemory;
580 struct metronomefb_par *par;
581 const struct firmware *fw_entry;
582 int i;
583 int panel_type;
584 int fw, fh;
585 int epd_dt_index;
587 /* pick up board specific routines */
588 board = dev->dev.platform_data;
589 if (!board)
590 return -EINVAL;
592 /* try to count device specific driver, if can't, platform recalls */
593 if (!try_module_get(board->owner))
594 return -ENODEV;
596 info = framebuffer_alloc(sizeof(struct metronomefb_par), &dev->dev);
597 if (!info)
598 goto err;
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
607 is provided to us */
609 panel_type = board->get_panel_type();
610 switch (panel_type) {
611 case 6:
612 epd_dt_index = 0;
613 break;
614 case 8:
615 epd_dt_index = 1;
616 break;
617 case 97:
618 epd_dt_index = 2;
619 break;
620 default:
621 dev_err(&dev->dev, "Unexpected panel type. Defaulting to 6\n");
622 epd_dt_index = 0;
623 break;
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);
633 if (!videomemory)
634 goto err_fb_rel;
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;
649 par = info->par;
650 par->info = info;
651 par->board = board;
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)
658 goto err_vfree;
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);
664 if (retval) {
665 dev_err(&dev->dev, "Failed to setup fb\n");
666 goto err_csum_table;
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");
673 retval = -EINVAL;
674 goto err_csum_table;
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);
683 if (retval < 0) {
684 dev_err(&dev->dev, "Failed to get waveform\n");
685 goto err_csum_table;
688 retval = load_waveform((u8 *) fw_entry->data, fw_entry->size, 3, 31,
689 par);
690 release_firmware(fw_entry);
691 if (retval < 0) {
692 dev_err(&dev->dev, "Failed processing waveform\n");
693 goto err_csum_table;
696 if (board->setup_irq(info))
697 goto err_csum_table;
699 retval = metronome_init_regs(par);
700 if (retval < 0)
701 goto err_free_irq;
703 info->flags = FBINFO_FLAG_DEFAULT;
705 info->fbdefio = &metronomefb_defio;
706 fb_deferred_io_init(info);
708 retval = fb_alloc_cmap(&info->cmap, 8, 0);
709 if (retval < 0) {
710 dev_err(&dev->dev, "Failed to allocate colormap\n");
711 goto err_free_irq;
714 /* set cmap */
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);
721 if (retval < 0)
722 goto err_cmap;
724 platform_set_drvdata(dev, info);
726 dev_dbg(&dev->dev,
727 "fb%d: Metronome frame buffer device, using %dK of video"
728 " memory\n", info->node, videomemorysize >> 10);
730 return 0;
732 err_cmap:
733 fb_dealloc_cmap(&info->cmap);
734 err_free_irq:
735 board->cleanup(par);
736 err_csum_table:
737 vfree(par->csum_table);
738 err_vfree:
739 vfree(videomemory);
740 err_fb_rel:
741 framebuffer_release(info);
742 err:
743 module_put(board->owner);
744 return retval;
747 static int __devexit metronomefb_remove(struct platform_device *dev)
749 struct fb_info *info = platform_get_drvdata(dev);
751 if (info) {
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);
764 return 0;
767 static struct platform_driver metronomefb_driver = {
768 .probe = metronomefb_probe,
769 .remove = metronomefb_remove,
770 .driver = {
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");