1/*
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. https://www.eink.com/
14 *
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
19 *
20 */
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/vmalloc.h>
27#include <linux/delay.h>
28#include <linux/interrupt.h>
29#include <linux/fb.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>
37
38#include <video/metronomefb.h>
39
40#include <asm/unaligned.h>
41
42/* Display specific information */
43#define DPY_W 832
44#define DPY_H 622
45
46static int user_wfm_size;
47
48/* frame differs from image. frame includes non-visible pixels */
49struct epd_frame {
50	int fw; /* frame width */
51	int fh; /* frame height */
52	u16 config[4];
53	int wfm_size;
54};
55
56static struct epd_frame epd_frame_table[] = {
57	{
58		.fw = 832,
59		.fh = 622,
60		.config = {
61			15 /* sdlew */
62			| 2 << 8 /* sdosz */
63			| 0 << 11 /* sdor */
64			| 0 << 12 /* sdces */
65			| 0 << 15, /* sdcer */
66			42 /* gdspl */
67			| 1 << 8 /* gdr1 */
68			| 1 << 9 /* sdshr */
69			| 0 << 15, /* gdspp */
70			18 /* gdspw */
71			| 0 << 15, /* dispc */
72			599 /* vdlc */
73			| 0 << 11 /* dsi */
74			| 0 << 12, /* dsic */
75		},
76		.wfm_size = 47001,
77	},
78	{
79		.fw = 1088,
80		.fh = 791,
81		.config = {
82			0x0104,
83			0x031f,
84			0x0088,
85			0x02ff,
86		},
87		.wfm_size = 46770,
88	},
89	{
90		.fw = 1200,
91		.fh = 842,
92		.config = {
93			0x0101,
94			0x030e,
95			0x0012,
96			0x0280,
97		},
98		.wfm_size = 46770,
99	},
100};
101
102static struct fb_fix_screeninfo metronomefb_fix = {
103	.id =		"metronomefb",
104	.type =		FB_TYPE_PACKED_PIXELS,
105	.visual =	FB_VISUAL_STATIC_PSEUDOCOLOR,
106	.xpanstep =	0,
107	.ypanstep =	0,
108	.ywrapstep =	0,
109	.line_length =	DPY_W,
110	.accel =	FB_ACCEL_NONE,
111};
112
113static struct fb_var_screeninfo metronomefb_var = {
114	.xres		= DPY_W,
115	.yres		= DPY_H,
116	.xres_virtual	= DPY_W,
117	.yres_virtual	= DPY_H,
118	.bits_per_pixel	= 8,
119	.grayscale	= 1,
120	.nonstd		= 1,
121	.red =		{ 4, 3, 0 },
122	.green =	{ 0, 0, 0 },
123	.blue =		{ 0, 0, 0 },
124	.transp =	{ 0, 0, 0 },
125};
126
127/* the waveform structure that is coming from userspace firmware */
128struct waveform_hdr {
129	u8 stuff[32];
130
131	u8 wmta[3];
132	u8 fvsn;
133
134	u8 luts;
135	u8 mc;
136	u8 trc;
137	u8 stuff3;
138
139	u8 endb;
140	u8 swtb;
141	u8 stuff2a[2];
142
143	u8 stuff2b[3];
144	u8 wfm_cs;
145} __attribute__ ((packed));
146
147/* main metronomefb functions */
148static u8 calc_cksum(int start, int end, u8 *mem)
149{
150	u8 tmp = 0;
151	int i;
152
153	for (i = start; i < end; i++)
154		tmp += mem[i];
155
156	return tmp;
157}
158
159static u16 calc_img_cksum(u16 *start, int length)
160{
161	u16 tmp = 0;
162
163	while (length--)
164		tmp += *start++;
165
166	return tmp;
167}
168
169/* here we decode the incoming waveform file and populate metromem */
170static int load_waveform(u8 *mem, size_t size, int m, int t,
171			 struct metronomefb_par *par)
172{
173	int tta;
174	int wmta;
175	int trn = 0;
176	int i;
177	unsigned char v;
178	u8 cksum;
179	int cksum_idx;
180	int wfm_idx, owfm_idx;
181	int mem_idx = 0;
182	struct waveform_hdr *wfm_hdr;
183	u8 *metromem = par->metromem_wfm;
184	struct device *dev = par->info->device;
185
186	if (user_wfm_size)
187		epd_frame_table[par->dt].wfm_size = user_wfm_size;
188
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);
192		return -EINVAL;
193	}
194
195	wfm_hdr = (struct waveform_hdr *) mem;
196
197	if (wfm_hdr->fvsn != 1) {
198		dev_err(dev, "Error: bad fvsn %x\n", wfm_hdr->fvsn);
199		return -EINVAL;
200	}
201	if (wfm_hdr->luts != 0) {
202		dev_err(dev, "Error: bad luts %x\n", wfm_hdr->luts);
203		return -EINVAL;
204	}
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,
208					wfm_hdr->wfm_cs);
209		return -EINVAL;
210	}
211	wfm_hdr->mc += 1;
212	wfm_hdr->trc += 1;
213	for (i = 0; i < 5; i++) {
214		if (*(wfm_hdr->stuff2a + i) != 0) {
215			dev_err(dev, "Error: unexpected value in padding\n");
216			return -EINVAL;
217		}
218	}
219
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)
225		return -EINVAL;
226
227	for (i = sizeof(*wfm_hdr); i <= sizeof(*wfm_hdr) + wfm_hdr->trc; i++) {
228		if (mem[i] > t) {
229			trn = i - sizeof(*wfm_hdr) - 1;
230			break;
231		}
232	}
233
234	/* check temperature range table checksum */
235	cksum_idx = sizeof(*wfm_hdr) + wfm_hdr->trc + 1;
236	if (cksum_idx >= size)
237		return -EINVAL;
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]);
242		return -EINVAL;
243	}
244
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)
249		return -EINVAL;
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]);
254		return -EINVAL;
255	}
256
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)
261		return -EINVAL;
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]);
266		return -EINVAL;
267	}
268
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;
272	owfm_idx = wfm_idx;
273	if (wfm_idx >= size)
274		return -EINVAL;
275	while (wfm_idx < size) {
276		unsigned char rl;
277		v = mem[wfm_idx++];
278		if (v == wfm_hdr->swtb) {
279			while (((v = mem[wfm_idx++]) != wfm_hdr->swtb) &&
280				wfm_idx < size)
281				metromem[mem_idx++] = v;
282
283			continue;
284		}
285
286		if (v == wfm_hdr->endb)
287			break;
288
289		rl = mem[wfm_idx++];
290		for (i = 0; i <= rl; i++)
291			metromem[mem_idx++] = v;
292	}
293
294	cksum_idx = wfm_idx;
295	if (cksum_idx >= size)
296		return -EINVAL;
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]);
301		return -EINVAL;
302	}
303	par->frame_count = (mem_idx/64);
304
305	return 0;
306}
307
308static int metronome_display_cmd(struct metronomefb_par *par)
309{
310	int i;
311	u16 cs;
312	u16 opcode;
313	static u8 borderval;
314
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 */
319
320	if (par->metromem_cmd->opcode == 0xCC40)
321		opcode = cs = 0xCC41;
322	else
323		opcode = cs = 0xCC40;
324
325	/* set the args ( 2 bytes ) for display */
326	i = 0;
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++];
331
332	/* the rest are 0 */
333	memset((u8 *) (par->metromem_cmd->args + i), 0, (32-i)*2);
334
335	par->metromem_cmd->csum = cs;
336	par->metromem_cmd->opcode = opcode; /* display cmd */
337
338	return par->board->met_wait_event_intr(par);
339}
340
341static int metronome_powerup_cmd(struct metronomefb_par *par)
342{
343	int i;
344	u16 cs;
345
346	/* setup power up command */
347	par->metromem_cmd->opcode = 0x1234; /* pwr up pseudo cmd */
348	cs = par->metromem_cmd->opcode;
349
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];
354	}
355
356	/* the rest are 0 */
357	memset(&par->metromem_cmd->args[i], 0,
358	       (ARRAY_SIZE(par->metromem_cmd->args) - i) * 2);
359
360	par->metromem_cmd->csum = cs;
361
362	msleep(1);
363	par->board->set_rst(par, 1);
364
365	msleep(1);
366	par->board->set_stdby(par, 1);
367
368	return par->board->met_wait_event(par);
369}
370
371static int metronome_config_cmd(struct metronomefb_par *par)
372{
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 */
376
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(&par->metromem_cmd->args[4], 0,
381	       (ARRAY_SIZE(par->metromem_cmd->args) - 4) * 2);
382
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 */
386
387	return par->board->met_wait_event(par);
388}
389
390static int metronome_init_cmd(struct metronomefb_par *par)
391{
392	int i;
393	u16 cs;
394
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 */
399
400	cs = 0xCC20;
401
402	/* set the args ( 2 bytes ) for init */
403	i = 0;
404	par->metromem_cmd->args[i] = 0;
405	cs += par->metromem_cmd->args[i++];
406
407	/* the rest are 0 */
408	memset((u8 *) (par->metromem_cmd->args + i), 0, (32-i)*2);
409
410	par->metromem_cmd->csum = cs;
411	par->metromem_cmd->opcode = 0xCC20; /* init cmd */
412
413	return par->board->met_wait_event(par);
414}
415
416static int metronome_init_regs(struct metronomefb_par *par)
417{
418	int res;
419
420	res = par->board->setup_io(par);
421	if (res)
422		return res;
423
424	res = metronome_powerup_cmd(par);
425	if (res)
426		return res;
427
428	res = metronome_config_cmd(par);
429	if (res)
430		return res;
431
432	res = metronome_init_cmd(par);
433
434	return res;
435}
436
437static void metronomefb_dpy_update(struct metronomefb_par *par)
438{
439	int fbsize;
440	u16 cksum;
441	unsigned char *buf = par->info->screen_buffer;
442
443	fbsize = par->info->fix.smem_len;
444	/* copy from vm to metromem */
445	memcpy(par->metromem_img, buf, fbsize);
446
447	cksum = calc_img_cksum((u16 *) par->metromem_img, fbsize/2);
448	*((u16 *)(par->metromem_img) + fbsize/2) = cksum;
449	metronome_display_cmd(par);
450}
451
452static u16 metronomefb_dpy_update_page(struct metronomefb_par *par, int index)
453{
454	int i;
455	u16 csum = 0;
456	u16 *buf = (u16 *)(par->info->screen_buffer + index);
457	u16 *img = (u16 *)(par->metromem_img + index);
458
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;
462		csum += *(img + i);
463	}
464	return csum;
465}
466
467/* this is called back from the deferred io workqueue */
468static void metronomefb_dpy_deferred_io(struct fb_info *info, struct list_head *pagereflist)
469{
470	u16 cksum;
471	struct fb_deferred_io_pageref *pageref;
472	struct metronomefb_par *par = info->par;
473
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;
481	}
482
483	metronome_display_cmd(par);
484}
485
486static void metronomefb_defio_damage_range(struct fb_info *info, off_t off, size_t len)
487{
488	struct metronomefb_par *par = info->par;
489
490	metronomefb_dpy_update(par);
491}
492
493static void metronomefb_defio_damage_area(struct fb_info *info, u32 x, u32 y,
494					  u32 width, u32 height)
495{
496	struct metronomefb_par *par = info->par;
497
498	metronomefb_dpy_update(par);
499}
500
501FB_GEN_DEFAULT_DEFERRED_SYSMEM_OPS(metronomefb,
502				   metronomefb_defio_damage_range,
503				   metronomefb_defio_damage_area)
504
505static const struct fb_ops metronomefb_ops = {
506	.owner	= THIS_MODULE,
507	FB_DEFAULT_DEFERRED_OPS(metronomefb),
508};
509
510static struct fb_deferred_io metronomefb_defio = {
511	.delay			= HZ,
512	.sort_pagereflist	= true,
513	.deferred_io		= metronomefb_dpy_deferred_io,
514};
515
516static int metronomefb_probe(struct platform_device *dev)
517{
518	struct fb_info *info;
519	struct metronome_board *board;
520	int retval = -ENOMEM;
521	int videomemorysize;
522	unsigned char *videomemory;
523	struct metronomefb_par *par;
524	const struct firmware *fw_entry;
525	int i;
526	int panel_type;
527	int fw, fh;
528	int epd_dt_index;
529
530	/* pick up board specific routines */
531	board = dev->dev.platform_data;
532	if (!board)
533		return -EINVAL;
534
535	/* try to count device specific driver, if can't, platform recalls */
536	if (!try_module_get(board->owner))
537		return -ENODEV;
538
539	info = framebuffer_alloc(sizeof(struct metronomefb_par), &dev->dev);
540	if (!info)
541		goto err;
542
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
550	is provided to us */
551
552	panel_type = board->get_panel_type();
553	switch (panel_type) {
554	case 6:
555		epd_dt_index = 0;
556		break;
557	case 8:
558		epd_dt_index = 1;
559		break;
560	case 97:
561		epd_dt_index = 2;
562		break;
563	default:
564		dev_err(&dev->dev, "Unexpected panel type. Defaulting to 6\n");
565		epd_dt_index = 0;
566		break;
567	}
568
569	fw = epd_frame_table[epd_dt_index].fw;
570	fh = epd_frame_table[epd_dt_index].fh;
571
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);
576	if (!videomemory)
577		goto err_fb_rel;
578
579	info->screen_buffer = videomemory;
580	info->fbops = &metronomefb_ops;
581
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;
590	par = info->par;
591	par->info = info;
592	par->board = board;
593	par->dt = epd_dt_index;
594	init_waitqueue_head(&par->waitq);
595
596	/* this table caches per page csum values. */
597	par->csum_table = vmalloc(videomemorysize/PAGE_SIZE);
598	if (!par->csum_table)
599		goto err_vfree;
600
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);
605	if (retval) {
606		dev_err(&dev->dev, "Failed to setup fb\n");
607		goto err_csum_table;
608	}
609
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");
614		retval = -EINVAL;
615		goto err_csum_table;
616	}
617
618	info->fix.smem_start = par->metromem_dma;
619
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);
624	if (retval < 0) {
625		dev_err(&dev->dev, "Failed to get waveform\n");
626		goto err_csum_table;
627	}
628
629	retval = load_waveform((u8 *) fw_entry->data, fw_entry->size, 3, 31,
630				par);
631	release_firmware(fw_entry);
632	if (retval < 0) {
633		dev_err(&dev->dev, "Failed processing waveform\n");
634		goto err_csum_table;
635	}
636
637	retval = board->setup_irq(info);
638	if (retval)
639		goto err_csum_table;
640
641	retval = metronome_init_regs(par);
642	if (retval < 0)
643		goto err_free_irq;
644
645	info->flags = FBINFO_VIRTFB;
646
647	info->fbdefio = &metronomefb_defio;
648	fb_deferred_io_init(info);
649
650	retval = fb_alloc_cmap(&info->cmap, 8, 0);
651	if (retval < 0) {
652		dev_err(&dev->dev, "Failed to allocate colormap\n");
653		goto err_free_irq;
654	}
655
656	/* set cmap */
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);
661
662	retval = register_framebuffer(info);
663	if (retval < 0)
664		goto err_cmap;
665
666	platform_set_drvdata(dev, info);
667
668	dev_dbg(&dev->dev,
669		"fb%d: Metronome frame buffer device, using %dK of video"
670		" memory\n", info->node, videomemorysize >> 10);
671
672	return 0;
673
674err_cmap:
675	fb_dealloc_cmap(&info->cmap);
676err_free_irq:
677	board->cleanup(par);
678err_csum_table:
679	vfree(par->csum_table);
680err_vfree:
681	vfree(videomemory);
682err_fb_rel:
683	framebuffer_release(info);
684err:
685	module_put(board->owner);
686	return retval;
687}
688
689static void metronomefb_remove(struct platform_device *dev)
690{
691	struct fb_info *info = platform_get_drvdata(dev);
692
693	if (info) {
694		struct metronomefb_par *par = info->par;
695
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);
705	}
706}
707
708static struct platform_driver metronomefb_driver = {
709	.probe	= metronomefb_probe,
710	.remove_new = metronomefb_remove,
711	.driver	= {
712		.name	= "metronomefb",
713	},
714};
715module_platform_driver(metronomefb_driver);
716
717module_param(user_wfm_size, uint, 0);
718MODULE_PARM_DESC(user_wfm_size, "Set custom waveform size");
719
720MODULE_DESCRIPTION("fbdev driver for Metronome controller");
721MODULE_AUTHOR("Jaya Kumar");
722MODULE_LICENSE("GPL");
723
724MODULE_FIRMWARE("metronome.wbf");
725