blob: cc4c038a1b3f3c8c22821aab37a54f564ba41d8b [file] [log] [blame]
Jaya Kumarde7c6d12008-03-19 17:01:10 -07001/*
2 * linux/drivers/video/metronomefb.c -- FB driver for Metronome controller
3 *
4 * Copyright (C) 2008, Jaya Kumar
5 *
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.
9 *
10 * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven.
11 *
12 * This work was made possible by help and equipment support from E-Ink
13 * Corporation. http://support.eink.com/community
14 *
15 * This driver is written to be used with the Metronome display controller.
Jaya Kumar03c33a42008-04-28 02:15:38 -070016 * 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
Jaya Kumarde7c6d12008-03-19 17:01:10 -070019 *
Jaya Kumarde7c6d12008-03-19 17:01:10 -070020 */
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>
38
Jaya Kumar03c33a42008-04-28 02:15:38 -070039#include <video/metronomefb.h>
40
Jaya Kumarde7c6d12008-03-19 17:01:10 -070041#include <asm/unaligned.h>
42
Jaya Kumar03c33a42008-04-28 02:15:38 -070043
Jaya Kumarde7c6d12008-03-19 17:01:10 -070044#define DEBUG 1
45#ifdef DEBUG
46#define DPRINTK(f, a...) printk(KERN_DEBUG "%s: " f, __func__ , ## a)
47#else
48#define DPRINTK(f, a...)
49#endif
50
51
52/* Display specific information */
53#define DPY_W 832
54#define DPY_H 622
55
Jaya Kumarde7c6d12008-03-19 17:01:10 -070056/* frame differs from image. frame includes non-visible pixels */
57struct epd_frame {
58 int fw; /* frame width */
59 int fh; /* frame height */
60};
61
62static struct epd_frame epd_frame_table[] = {
63 {
64 .fw = 832,
65 .fh = 622
66 },
67};
68
69static struct fb_fix_screeninfo metronomefb_fix __devinitdata = {
70 .id = "metronomefb",
71 .type = FB_TYPE_PACKED_PIXELS,
72 .visual = FB_VISUAL_STATIC_PSEUDOCOLOR,
73 .xpanstep = 0,
74 .ypanstep = 0,
75 .ywrapstep = 0,
76 .line_length = DPY_W,
77 .accel = FB_ACCEL_NONE,
78};
79
80static struct fb_var_screeninfo metronomefb_var __devinitdata = {
81 .xres = DPY_W,
82 .yres = DPY_H,
83 .xres_virtual = DPY_W,
84 .yres_virtual = DPY_H,
85 .bits_per_pixel = 8,
86 .grayscale = 1,
87 .nonstd = 1,
88 .red = { 4, 3, 0 },
89 .green = { 0, 0, 0 },
90 .blue = { 0, 0, 0 },
91 .transp = { 0, 0, 0 },
92};
93
Jaya Kumar03c33a42008-04-28 02:15:38 -070094/* the waveform structure that is coming from userspace firmware */
Jaya Kumarde7c6d12008-03-19 17:01:10 -070095struct waveform_hdr {
96 u8 stuff[32];
97
98 u8 wmta[3];
99 u8 fvsn;
100
101 u8 luts;
102 u8 mc;
103 u8 trc;
104 u8 stuff3;
105
106 u8 endb;
107 u8 swtb;
108 u8 stuff2a[2];
109
110 u8 stuff2b[3];
111 u8 wfm_cs;
112} __attribute__ ((packed));
113
114/* main metronomefb functions */
115static u8 calc_cksum(int start, int end, u8 *mem)
116{
117 u8 tmp = 0;
118 int i;
119
120 for (i = start; i < end; i++)
121 tmp += mem[i];
122
123 return tmp;
124}
125
126static u16 calc_img_cksum(u16 *start, int length)
127{
128 u16 tmp = 0;
129
130 while (length--)
131 tmp += *start++;
132
133 return tmp;
134}
135
136/* here we decode the incoming waveform file and populate metromem */
137#define EXP_WFORM_SIZE 47001
138static int load_waveform(u8 *mem, size_t size, u8 *metromem, int m, int t,
139 u8 *frame_count)
140{
141 int tta;
142 int wmta;
143 int trn = 0;
144 int i;
145 unsigned char v;
146 u8 cksum;
147 int cksum_idx;
148 int wfm_idx, owfm_idx;
149 int mem_idx = 0;
150 struct waveform_hdr *wfm_hdr;
151
152 if (size != EXP_WFORM_SIZE) {
153 printk(KERN_ERR "Error: unexpected size %d != %d\n", size,
154 EXP_WFORM_SIZE);
155 return -EINVAL;
156 }
157
158 wfm_hdr = (struct waveform_hdr *) mem;
159
160 if (wfm_hdr->fvsn != 1) {
161 printk(KERN_ERR "Error: bad fvsn %x\n", wfm_hdr->fvsn);
162 return -EINVAL;
163 }
164 if (wfm_hdr->luts != 0) {
165 printk(KERN_ERR "Error: bad luts %x\n", wfm_hdr->luts);
166 return -EINVAL;
167 }
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,
171 wfm_hdr->wfm_cs);
172 return -EINVAL;
173 }
174 wfm_hdr->mc += 1;
175 wfm_hdr->trc += 1;
176 for (i = 0; i < 5; i++) {
177 if (*(wfm_hdr->stuff2a + i) != 0) {
178 printk(KERN_ERR "Error: unexpected value in padding\n");
179 return -EINVAL;
180 }
181 }
182
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)
188 return -EINVAL;
189
190 for (i = sizeof(*wfm_hdr); i <= sizeof(*wfm_hdr) + wfm_hdr->trc; i++) {
191 if (mem[i] > t) {
192 trn = i - sizeof(*wfm_hdr) - 1;
193 break;
194 }
195 }
196
197 /* check temperature range table checksum */
198 cksum_idx = sizeof(*wfm_hdr) + wfm_hdr->trc + 1;
199 if (cksum_idx > size)
200 return -EINVAL;
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]);
205 return -EINVAL;
206 }
207
208 /* check waveform mode table address checksum */
Harvey Harrisond15c0a42008-04-29 01:03:41 -0700209 wmta = get_unaligned_le32(wfm_hdr->wmta) & 0x00FFFFFF;
Jaya Kumarde7c6d12008-03-19 17:01:10 -0700210 cksum_idx = wmta + m*4 + 3;
211 if (cksum_idx > size)
212 return -EINVAL;
213 cksum = calc_cksum(cksum_idx - 3, cksum_idx, mem);
214 if (cksum != mem[cksum_idx]) {
215 printk(KERN_ERR "Error: bad mode table address cksum"
216 " %x != %x\n", cksum, mem[cksum_idx]);
217 return -EINVAL;
218 }
219
220 /* check waveform temperature table address checksum */
Harvey Harrisond15c0a42008-04-29 01:03:41 -0700221 tta = get_unaligned_le32(mem + wmta + m * 4) & 0x00FFFFFF;
Jaya Kumarde7c6d12008-03-19 17:01:10 -0700222 cksum_idx = tta + trn*4 + 3;
223 if (cksum_idx > size)
224 return -EINVAL;
225 cksum = calc_cksum(cksum_idx - 3, cksum_idx, mem);
226 if (cksum != mem[cksum_idx]) {
227 printk(KERN_ERR "Error: bad temperature table address cksum"
228 " %x != %x\n", cksum, mem[cksum_idx]);
229 return -EINVAL;
230 }
231
232 /* here we do the real work of putting the waveform into the
233 metromem buffer. this does runlength decoding of the waveform */
Harvey Harrisond15c0a42008-04-29 01:03:41 -0700234 wfm_idx = get_unaligned_le32(mem + tta + trn * 4) & 0x00FFFFFF;
Jaya Kumarde7c6d12008-03-19 17:01:10 -0700235 owfm_idx = wfm_idx;
236 if (wfm_idx > size)
237 return -EINVAL;
238 while (wfm_idx < size) {
239 unsigned char rl;
240 v = mem[wfm_idx++];
241 if (v == wfm_hdr->swtb) {
242 while (((v = mem[wfm_idx++]) != wfm_hdr->swtb) &&
243 wfm_idx < size)
244 metromem[mem_idx++] = v;
245
246 continue;
247 }
248
249 if (v == wfm_hdr->endb)
250 break;
251
252 rl = mem[wfm_idx++];
253 for (i = 0; i <= rl; i++)
254 metromem[mem_idx++] = v;
255 }
256
257 cksum_idx = wfm_idx;
258 if (cksum_idx > size)
259 return -EINVAL;
260 cksum = calc_cksum(owfm_idx, cksum_idx, mem);
261 if (cksum != mem[cksum_idx]) {
262 printk(KERN_ERR "Error: bad waveform data cksum"
263 " %x != %x\n", cksum, mem[cksum_idx]);
264 return -EINVAL;
265 }
266 *frame_count = (mem_idx/64);
267
268 return 0;
269}
270
Jaya Kumarde7c6d12008-03-19 17:01:10 -0700271static int metronome_display_cmd(struct metronomefb_par *par)
272{
273 int i;
274 u16 cs;
275 u16 opcode;
276 static u8 borderval;
277 u8 *ptr;
278
279 /* setup display command
280 we can't immediately set the opcode since the controller
281 will try parse the command before we've set it all up
282 so we just set cs here and set the opcode at the end */
283
284 ptr = par->metromem;
285
286 if (par->metromem_cmd->opcode == 0xCC40)
287 opcode = cs = 0xCC41;
288 else
289 opcode = cs = 0xCC40;
290
291 /* set the args ( 2 bytes ) for display */
292 i = 0;
293 par->metromem_cmd->args[i] = 1 << 3 /* border update */
294 | ((borderval++ % 4) & 0x0F) << 4
295 | (par->frame_count - 1) << 8;
296 cs += par->metromem_cmd->args[i++];
297
298 /* the rest are 0 */
299 memset((u8 *) (par->metromem_cmd->args + i), 0, (32-i)*2);
300
301 par->metromem_cmd->csum = cs;
302 par->metromem_cmd->opcode = opcode; /* display cmd */
303
Jaya Kumar03c33a42008-04-28 02:15:38 -0700304 return par->board->met_wait_event_intr(par);
Jaya Kumarde7c6d12008-03-19 17:01:10 -0700305}
306
307static int __devinit metronome_powerup_cmd(struct metronomefb_par *par)
308{
309 int i;
310 u16 cs;
311
312 /* setup power up command */
313 par->metromem_cmd->opcode = 0x1234; /* pwr up pseudo cmd */
314 cs = par->metromem_cmd->opcode;
315
316 /* set pwr1,2,3 to 1024 */
317 for (i = 0; i < 3; i++) {
318 par->metromem_cmd->args[i] = 1024;
319 cs += par->metromem_cmd->args[i];
320 }
321
322 /* the rest are 0 */
323 memset((u8 *) (par->metromem_cmd->args + i), 0, (32-i)*2);
324
325 par->metromem_cmd->csum = cs;
326
327 msleep(1);
Jaya Kumar03c33a42008-04-28 02:15:38 -0700328 par->board->set_rst(par, 1);
Jaya Kumarde7c6d12008-03-19 17:01:10 -0700329
330 msleep(1);
Jaya Kumar03c33a42008-04-28 02:15:38 -0700331 par->board->set_stdby(par, 1);
Jaya Kumarde7c6d12008-03-19 17:01:10 -0700332
Jaya Kumar03c33a42008-04-28 02:15:38 -0700333 return par->board->met_wait_event(par);
Jaya Kumarde7c6d12008-03-19 17:01:10 -0700334}
335
336static int __devinit metronome_config_cmd(struct metronomefb_par *par)
337{
338 int i;
339 u16 cs;
340
341 /* setup config command
342 we can't immediately set the opcode since the controller
343 will try parse the command before we've set it all up
344 so we just set cs here and set the opcode at the end */
345
346 cs = 0xCC10;
347
348 /* set the 12 args ( 8 bytes ) for config. see spec for meanings */
349 i = 0;
350 par->metromem_cmd->args[i] = 15 /* sdlew */
351 | 2 << 8 /* sdosz */
352 | 0 << 11 /* sdor */
353 | 0 << 12 /* sdces */
354 | 0 << 15; /* sdcer */
355 cs += par->metromem_cmd->args[i++];
356
357 par->metromem_cmd->args[i] = 42 /* gdspl */
358 | 1 << 8 /* gdr1 */
359 | 1 << 9 /* sdshr */
360 | 0 << 15; /* gdspp */
361 cs += par->metromem_cmd->args[i++];
362
363 par->metromem_cmd->args[i] = 18 /* gdspw */
364 | 0 << 15; /* dispc */
365 cs += par->metromem_cmd->args[i++];
366
367 par->metromem_cmd->args[i] = 599 /* vdlc */
368 | 0 << 11 /* dsi */
369 | 0 << 12; /* dsic */
370 cs += par->metromem_cmd->args[i++];
371
372 /* the rest are 0 */
373 memset((u8 *) (par->metromem_cmd->args + i), 0, (32-i)*2);
374
375 par->metromem_cmd->csum = cs;
376 par->metromem_cmd->opcode = 0xCC10; /* config cmd */
377
Jaya Kumar03c33a42008-04-28 02:15:38 -0700378 return par->board->met_wait_event(par);
Jaya Kumarde7c6d12008-03-19 17:01:10 -0700379}
380
381static int __devinit metronome_init_cmd(struct metronomefb_par *par)
382{
383 int i;
384 u16 cs;
385
386 /* setup init command
387 we can't immediately set the opcode since the controller
388 will try parse the command before we've set it all up
389 so we just set cs here and set the opcode at the end */
390
391 cs = 0xCC20;
392
393 /* set the args ( 2 bytes ) for init */
394 i = 0;
395 par->metromem_cmd->args[i] = 0;
396 cs += par->metromem_cmd->args[i++];
397
398 /* the rest are 0 */
399 memset((u8 *) (par->metromem_cmd->args + i), 0, (32-i)*2);
400
401 par->metromem_cmd->csum = cs;
402 par->metromem_cmd->opcode = 0xCC20; /* init cmd */
403
Jaya Kumar03c33a42008-04-28 02:15:38 -0700404 return par->board->met_wait_event(par);
Jaya Kumarde7c6d12008-03-19 17:01:10 -0700405}
406
407static int __devinit metronome_init_regs(struct metronomefb_par *par)
408{
409 int res;
410
Jaya Kumar03c33a42008-04-28 02:15:38 -0700411 par->board->init_gpio_regs(par);
412
413 par->board->init_lcdc_regs(par);
414
415 /* now that lcd is setup, setup dma descriptor */
416 par->board->post_dma_setup(par);
Jaya Kumarde7c6d12008-03-19 17:01:10 -0700417
418 res = metronome_powerup_cmd(par);
419 if (res)
420 return res;
421
422 res = metronome_config_cmd(par);
423 if (res)
424 return res;
425
426 res = metronome_init_cmd(par);
Jaya Kumarde7c6d12008-03-19 17:01:10 -0700427
428 return res;
429}
430
431static void metronomefb_dpy_update(struct metronomefb_par *par)
432{
433 u16 cksum;
434 unsigned char *buf = (unsigned char __force *)par->info->screen_base;
435
436 /* copy from vm to metromem */
437 memcpy(par->metromem_img, buf, DPY_W*DPY_H);
438
439 cksum = calc_img_cksum((u16 *) par->metromem_img,
440 (epd_frame_table[0].fw * DPY_H)/2);
Jaya Kumar03c33a42008-04-28 02:15:38 -0700441 *((u16 *)(par->metromem_img) +
Jaya Kumarde7c6d12008-03-19 17:01:10 -0700442 (epd_frame_table[0].fw * DPY_H)/2) = cksum;
443 metronome_display_cmd(par);
444}
445
446static u16 metronomefb_dpy_update_page(struct metronomefb_par *par, int index)
447{
448 int i;
449 u16 csum = 0;
Jaya Kumar03c33a42008-04-28 02:15:38 -0700450 u16 *buf = (u16 __force *)(par->info->screen_base + index);
451 u16 *img = (u16 *)(par->metromem_img + index);
Jaya Kumarde7c6d12008-03-19 17:01:10 -0700452
453 /* swizzle from vm to metromem and recalc cksum at the same time*/
454 for (i = 0; i < PAGE_SIZE/2; i++) {
455 *(img + i) = (buf[i] << 5) & 0xE0E0;
456 csum += *(img + i);
457 }
458 return csum;
459}
460
461/* this is called back from the deferred io workqueue */
462static void metronomefb_dpy_deferred_io(struct fb_info *info,
463 struct list_head *pagelist)
464{
465 u16 cksum;
466 struct page *cur;
467 struct fb_deferred_io *fbdefio = info->fbdefio;
468 struct metronomefb_par *par = info->par;
469
470 /* walk the written page list and swizzle the data */
471 list_for_each_entry(cur, &fbdefio->pagelist, lru) {
472 cksum = metronomefb_dpy_update_page(par,
473 (cur->index << PAGE_SHIFT));
474 par->metromem_img_csum -= par->csum_table[cur->index];
475 par->csum_table[cur->index] = cksum;
476 par->metromem_img_csum += cksum;
477 }
478
479 metronome_display_cmd(par);
480}
481
482static void metronomefb_fillrect(struct fb_info *info,
483 const struct fb_fillrect *rect)
484{
485 struct metronomefb_par *par = info->par;
486
Jaya Kumar555514f2008-04-28 02:15:36 -0700487 sys_fillrect(info, rect);
Jaya Kumarde7c6d12008-03-19 17:01:10 -0700488 metronomefb_dpy_update(par);
489}
490
491static void metronomefb_copyarea(struct fb_info *info,
492 const struct fb_copyarea *area)
493{
494 struct metronomefb_par *par = info->par;
495
Jaya Kumar555514f2008-04-28 02:15:36 -0700496 sys_copyarea(info, area);
Jaya Kumarde7c6d12008-03-19 17:01:10 -0700497 metronomefb_dpy_update(par);
498}
499
500static void metronomefb_imageblit(struct fb_info *info,
501 const struct fb_image *image)
502{
503 struct metronomefb_par *par = info->par;
504
Jaya Kumar555514f2008-04-28 02:15:36 -0700505 sys_imageblit(info, image);
Jaya Kumarde7c6d12008-03-19 17:01:10 -0700506 metronomefb_dpy_update(par);
507}
508
509/*
510 * this is the slow path from userspace. they can seek and write to
511 * the fb. it is based on fb_sys_write
512 */
513static ssize_t metronomefb_write(struct fb_info *info, const char __user *buf,
514 size_t count, loff_t *ppos)
515{
516 struct metronomefb_par *par = info->par;
517 unsigned long p = *ppos;
518 void *dst;
519 int err = 0;
520 unsigned long total_size;
521
522 if (info->state != FBINFO_STATE_RUNNING)
523 return -EPERM;
524
525 total_size = info->fix.smem_len;
526
527 if (p > total_size)
528 return -EFBIG;
529
530 if (count > total_size) {
531 err = -EFBIG;
532 count = total_size;
533 }
534
535 if (count + p > total_size) {
536 if (!err)
537 err = -ENOSPC;
538
539 count = total_size - p;
540 }
541
Jaya Kumar03c33a42008-04-28 02:15:38 -0700542 dst = (void __force *)(info->screen_base + p);
Jaya Kumarde7c6d12008-03-19 17:01:10 -0700543
544 if (copy_from_user(dst, buf, count))
545 err = -EFAULT;
546
547 if (!err)
548 *ppos += count;
549
550 metronomefb_dpy_update(par);
551
552 return (err) ? err : count;
553}
554
555static struct fb_ops metronomefb_ops = {
556 .owner = THIS_MODULE,
557 .fb_write = metronomefb_write,
558 .fb_fillrect = metronomefb_fillrect,
559 .fb_copyarea = metronomefb_copyarea,
560 .fb_imageblit = metronomefb_imageblit,
561};
562
563static struct fb_deferred_io metronomefb_defio = {
564 .delay = HZ,
565 .deferred_io = metronomefb_dpy_deferred_io,
566};
567
Jaya Kumarde7c6d12008-03-19 17:01:10 -0700568static int __devinit metronomefb_probe(struct platform_device *dev)
569{
570 struct fb_info *info;
Jaya Kumar03c33a42008-04-28 02:15:38 -0700571 struct metronome_board *board;
Jaya Kumarde7c6d12008-03-19 17:01:10 -0700572 int retval = -ENOMEM;
573 int videomemorysize;
574 unsigned char *videomemory;
575 struct metronomefb_par *par;
576 const struct firmware *fw_entry;
577 int cmd_size, wfm_size, img_size, padding_size, totalsize;
578 int i;
579
Jaya Kumar03c33a42008-04-28 02:15:38 -0700580 /* pick up board specific routines */
581 board = dev->dev.platform_data;
582 if (!board)
583 return -EINVAL;
584
585 /* try to count device specific driver, if can't, platform recalls */
586 if (!try_module_get(board->owner))
587 return -ENODEV;
588
Jaya Kumarde7c6d12008-03-19 17:01:10 -0700589 /* we have two blocks of memory.
590 info->screen_base which is vm, and is the fb used by apps.
591 par->metromem which is physically contiguous memory and
592 contains the display controller commands, waveform,
593 processed image data and padding. this is the data pulled
Jaya Kumar03c33a42008-04-28 02:15:38 -0700594 by the device's LCD controller and pushed to Metronome */
Jaya Kumarde7c6d12008-03-19 17:01:10 -0700595
596 videomemorysize = (DPY_W*DPY_H);
597 videomemory = vmalloc(videomemorysize);
598 if (!videomemory)
Jaya Kumar03c33a42008-04-28 02:15:38 -0700599 return -ENOMEM;
Jaya Kumarde7c6d12008-03-19 17:01:10 -0700600
601 memset(videomemory, 0, videomemorysize);
602
603 info = framebuffer_alloc(sizeof(struct metronomefb_par), &dev->dev);
604 if (!info)
605 goto err_vfree;
606
Jaya Kumar03c33a42008-04-28 02:15:38 -0700607 info->screen_base = (char __force __iomem *)videomemory;
Jaya Kumarde7c6d12008-03-19 17:01:10 -0700608 info->fbops = &metronomefb_ops;
609
610 info->var = metronomefb_var;
611 info->fix = metronomefb_fix;
612 info->fix.smem_len = videomemorysize;
613 par = info->par;
614 par->info = info;
Jaya Kumar03c33a42008-04-28 02:15:38 -0700615 par->board = board;
Jaya Kumarde7c6d12008-03-19 17:01:10 -0700616 init_waitqueue_head(&par->waitq);
617
618 /* this table caches per page csum values. */
619 par->csum_table = vmalloc(videomemorysize/PAGE_SIZE);
620 if (!par->csum_table)
621 goto err_csum_table;
622
623 /* the metromem buffer is divided as follows:
624 command | CRC | padding
625 16kb waveform data | CRC | padding
626 image data | CRC
627 and an extra 256 bytes for dma descriptors
628 eg: IW=832 IH=622 WS=128
629 */
630
631 cmd_size = 1 * epd_frame_table[0].fw;
632 wfm_size = ((16*1024 + 2 + epd_frame_table[0].fw - 1)
633 / epd_frame_table[0].fw) * epd_frame_table[0].fw;
634 img_size = epd_frame_table[0].fh * epd_frame_table[0].fw;
635 padding_size = 4 * epd_frame_table[0].fw;
636 totalsize = cmd_size + wfm_size + img_size + padding_size;
637 par->metromemsize = PAGE_ALIGN(totalsize + 256);
638 DPRINTK("desired memory size = %d\n", par->metromemsize);
639 dev->dev.coherent_dma_mask = 0xffffffffull;
640 par->metromem = dma_alloc_writecombine(&dev->dev, par->metromemsize,
641 &par->metromem_dma, GFP_KERNEL);
642 if (!par->metromem) {
643 printk(KERN_ERR
644 "metronomefb: unable to allocate dma buffer\n");
645 goto err_vfree;
646 }
647
648 info->fix.smem_start = par->metromem_dma;
649 par->metromem_cmd = (struct metromem_cmd *) par->metromem;
650 par->metromem_wfm = par->metromem + cmd_size;
651 par->metromem_img = par->metromem + cmd_size + wfm_size;
652 par->metromem_img_csum = (u16 *) (par->metromem_img +
653 (epd_frame_table[0].fw * DPY_H));
654 DPRINTK("img offset=0x%x\n", cmd_size + wfm_size);
655 par->metromem_desc = (struct metromem_desc *) (par->metromem + cmd_size
656 + wfm_size + img_size + padding_size);
657 par->metromem_desc_dma = par->metromem_dma + cmd_size + wfm_size
658 + img_size + padding_size;
659
Jaya Kumar03c33a42008-04-28 02:15:38 -0700660 /* load the waveform in. assume mode 3, temp 31 for now
661 a) request the waveform file from userspace
Jaya Kumarde7c6d12008-03-19 17:01:10 -0700662 b) process waveform and decode into metromem */
Jaya Kumar03c33a42008-04-28 02:15:38 -0700663 retval = request_firmware(&fw_entry, "metronome.wbf", &dev->dev);
Jaya Kumarde7c6d12008-03-19 17:01:10 -0700664 if (retval < 0) {
665 printk(KERN_ERR "metronomefb: couldn't get waveform\n");
666 goto err_dma_free;
667 }
668
669 retval = load_waveform((u8 *) fw_entry->data, fw_entry->size,
670 par->metromem_wfm, 3, 31, &par->frame_count);
Sebastian Siewior2422fbb2008-04-28 02:15:39 -0700671 release_firmware(fw_entry);
Jaya Kumarde7c6d12008-03-19 17:01:10 -0700672 if (retval < 0) {
673 printk(KERN_ERR "metronomefb: couldn't process waveform\n");
Sebastian Siewior2422fbb2008-04-28 02:15:39 -0700674 goto err_dma_free;
Jaya Kumarde7c6d12008-03-19 17:01:10 -0700675 }
Jaya Kumarde7c6d12008-03-19 17:01:10 -0700676
Jaya Kumar03c33a42008-04-28 02:15:38 -0700677 if (board->setup_irq(info))
Sebastian Siewior2422fbb2008-04-28 02:15:39 -0700678 goto err_dma_free;
Jaya Kumarde7c6d12008-03-19 17:01:10 -0700679
680 retval = metronome_init_regs(par);
681 if (retval < 0)
682 goto err_free_irq;
683
684 info->flags = FBINFO_FLAG_DEFAULT;
685
686 info->fbdefio = &metronomefb_defio;
687 fb_deferred_io_init(info);
688
689 retval = fb_alloc_cmap(&info->cmap, 8, 0);
690 if (retval < 0) {
691 printk(KERN_ERR "Failed to allocate colormap\n");
692 goto err_fb_rel;
693 }
694
695 /* set cmap */
696 for (i = 0; i < 8; i++)
697 info->cmap.red[i] = (((2*i)+1)*(0xFFFF))/16;
698 memcpy(info->cmap.green, info->cmap.red, sizeof(u16)*8);
699 memcpy(info->cmap.blue, info->cmap.red, sizeof(u16)*8);
700
701 retval = register_framebuffer(info);
702 if (retval < 0)
703 goto err_cmap;
704
705 platform_set_drvdata(dev, info);
706
707 printk(KERN_INFO
708 "fb%d: Metronome frame buffer device, using %dK of video"
709 " memory\n", info->node, videomemorysize >> 10);
710
711 return 0;
712
713err_cmap:
714 fb_dealloc_cmap(&info->cmap);
715err_fb_rel:
716 framebuffer_release(info);
717err_free_irq:
Jaya Kumar03c33a42008-04-28 02:15:38 -0700718 board->free_irq(info);
Jaya Kumarde7c6d12008-03-19 17:01:10 -0700719err_dma_free:
720 dma_free_writecombine(&dev->dev, par->metromemsize, par->metromem,
721 par->metromem_dma);
722err_csum_table:
723 vfree(par->csum_table);
724err_vfree:
725 vfree(videomemory);
Jaya Kumar03c33a42008-04-28 02:15:38 -0700726 module_put(board->owner);
Jaya Kumarde7c6d12008-03-19 17:01:10 -0700727 return retval;
728}
729
730static int __devexit metronomefb_remove(struct platform_device *dev)
731{
732 struct fb_info *info = platform_get_drvdata(dev);
733
734 if (info) {
735 struct metronomefb_par *par = info->par;
736 fb_deferred_io_cleanup(info);
737 dma_free_writecombine(&dev->dev, par->metromemsize,
738 par->metromem, par->metromem_dma);
739 fb_dealloc_cmap(&info->cmap);
740 vfree(par->csum_table);
741 unregister_framebuffer(info);
742 vfree((void __force *)info->screen_base);
Jaya Kumar03c33a42008-04-28 02:15:38 -0700743 par->board->free_irq(info);
744 module_put(par->board->owner);
Jaya Kumarde7c6d12008-03-19 17:01:10 -0700745 framebuffer_release(info);
746 }
747 return 0;
748}
749
750static struct platform_driver metronomefb_driver = {
751 .probe = metronomefb_probe,
752 .remove = metronomefb_remove,
753 .driver = {
Jaya Kumar03c33a42008-04-28 02:15:38 -0700754 .owner = THIS_MODULE,
Jaya Kumarde7c6d12008-03-19 17:01:10 -0700755 .name = "metronomefb",
756 },
757};
758
Jaya Kumarde7c6d12008-03-19 17:01:10 -0700759static int __init metronomefb_init(void)
760{
Jaya Kumar03c33a42008-04-28 02:15:38 -0700761 return platform_driver_register(&metronomefb_driver);
Jaya Kumarde7c6d12008-03-19 17:01:10 -0700762}
763
764static void __exit metronomefb_exit(void)
765{
Jaya Kumarde7c6d12008-03-19 17:01:10 -0700766 platform_driver_unregister(&metronomefb_driver);
767}
768
Jaya Kumarde7c6d12008-03-19 17:01:10 -0700769module_init(metronomefb_init);
770module_exit(metronomefb_exit);
771
772MODULE_DESCRIPTION("fbdev driver for Metronome controller");
773MODULE_AUTHOR("Jaya Kumar");
774MODULE_LICENSE("GPL");