• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/drivers/video/
1/*
2 * broadsheetfb.c -- FB driver for E-Ink Broadsheet 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 driver is written to be used with the Broadsheet display controller.
13 *
14 * It is intended to be architecture independent. A board specific driver
15 * must be used to perform all the physical IO interactions.
16 *
17 */
18
19#include <linux/module.h>
20#include <linux/kernel.h>
21#include <linux/errno.h>
22#include <linux/string.h>
23#include <linux/mm.h>
24#include <linux/slab.h>
25#include <linux/vmalloc.h>
26#include <linux/delay.h>
27#include <linux/interrupt.h>
28#include <linux/fb.h>
29#include <linux/init.h>
30#include <linux/platform_device.h>
31#include <linux/list.h>
32#include <linux/firmware.h>
33#include <linux/uaccess.h>
34
35#include <video/broadsheetfb.h>
36
37/* track panel specific parameters */
38struct panel_info {
39	int w;
40	int h;
41	u16 sdcfg;
42	u16 gdcfg;
43	u16 lutfmt;
44	u16 fsynclen;
45	u16 fendfbegin;
46	u16 lsynclen;
47	u16 lendlbegin;
48	u16 pixclk;
49};
50
51/* table of panel specific parameters to be indexed into by the board drivers */
52static struct panel_info panel_table[] = {
53	{	/* standard 6" on TFT backplane */
54		.w = 800,
55		.h = 600,
56		.sdcfg = (100 | (1 << 8) | (1 << 9)),
57		.gdcfg = 2,
58		.lutfmt = (4 | (1 << 7)),
59		.fsynclen = 4,
60		.fendfbegin = (10 << 8) | 4,
61		.lsynclen = 10,
62		.lendlbegin = (100 << 8) | 4,
63		.pixclk = 6,
64	},
65	{	/* custom 3.7" flexible on PET or steel */
66		.w = 320,
67		.h = 240,
68		.sdcfg = (67 | (0 << 8) | (0 << 9) | (0 << 10) | (0 << 12)),
69		.gdcfg = 3,
70		.lutfmt = (4 | (1 << 7)),
71		.fsynclen = 0,
72		.fendfbegin = (80 << 8) | 4,
73		.lsynclen = 10,
74		.lendlbegin = (80 << 8) | 20,
75		.pixclk = 14,
76	},
77	{	/* standard 9.7" on TFT backplane */
78		.w = 1200,
79		.h = 825,
80		.sdcfg = (100 | (1 << 8) | (1 << 9) | (0 << 10) | (0 << 12)),
81		.gdcfg = 2,
82		.lutfmt = (4 | (1 << 7)),
83		.fsynclen = 0,
84		.fendfbegin = (4 << 8) | 4,
85		.lsynclen = 4,
86		.lendlbegin = (60 << 8) | 10,
87		.pixclk = 3,
88	},
89};
90
91#define DPY_W 800
92#define DPY_H 600
93
94static struct fb_fix_screeninfo broadsheetfb_fix __devinitdata = {
95	.id =		"broadsheetfb",
96	.type =		FB_TYPE_PACKED_PIXELS,
97	.visual =	FB_VISUAL_STATIC_PSEUDOCOLOR,
98	.xpanstep =	0,
99	.ypanstep =	0,
100	.ywrapstep =	0,
101	.line_length =	DPY_W,
102	.accel =	FB_ACCEL_NONE,
103};
104
105static struct fb_var_screeninfo broadsheetfb_var __devinitdata = {
106	.xres		= DPY_W,
107	.yres		= DPY_H,
108	.xres_virtual	= DPY_W,
109	.yres_virtual	= DPY_H,
110	.bits_per_pixel	= 8,
111	.grayscale	= 1,
112	.red =		{ 0, 4, 0 },
113	.green =	{ 0, 4, 0 },
114	.blue =		{ 0, 4, 0 },
115	.transp =	{ 0, 0, 0 },
116};
117
118/* main broadsheetfb functions */
119static void broadsheet_gpio_issue_data(struct broadsheetfb_par *par, u16 data)
120{
121	par->board->set_ctl(par, BS_WR, 0);
122	par->board->set_hdb(par, data);
123	par->board->set_ctl(par, BS_WR, 1);
124}
125
126static void broadsheet_gpio_issue_cmd(struct broadsheetfb_par *par, u16 data)
127{
128	par->board->set_ctl(par, BS_DC, 0);
129	broadsheet_gpio_issue_data(par, data);
130}
131
132static void broadsheet_gpio_send_command(struct broadsheetfb_par *par, u16 data)
133{
134	par->board->wait_for_rdy(par);
135
136	par->board->set_ctl(par, BS_CS, 0);
137	broadsheet_gpio_issue_cmd(par, data);
138	par->board->set_ctl(par, BS_DC, 1);
139	par->board->set_ctl(par, BS_CS, 1);
140}
141
142static void broadsheet_gpio_send_cmdargs(struct broadsheetfb_par *par, u16 cmd,
143					int argc, u16 *argv)
144{
145	int i;
146
147	par->board->wait_for_rdy(par);
148
149	par->board->set_ctl(par, BS_CS, 0);
150	broadsheet_gpio_issue_cmd(par, cmd);
151	par->board->set_ctl(par, BS_DC, 1);
152
153	for (i = 0; i < argc; i++)
154		broadsheet_gpio_issue_data(par, argv[i]);
155	par->board->set_ctl(par, BS_CS, 1);
156}
157
158static void broadsheet_mmio_send_cmdargs(struct broadsheetfb_par *par, u16 cmd,
159				    int argc, u16 *argv)
160{
161	int i;
162
163	par->board->mmio_write(par, BS_MMIO_CMD, cmd);
164
165	for (i = 0; i < argc; i++)
166		par->board->mmio_write(par, BS_MMIO_DATA, argv[i]);
167}
168
169static void broadsheet_send_command(struct broadsheetfb_par *par, u16 data)
170{
171	if (par->board->mmio_write)
172		par->board->mmio_write(par, BS_MMIO_CMD, data);
173	else
174		broadsheet_gpio_send_command(par, data);
175}
176
177static void broadsheet_send_cmdargs(struct broadsheetfb_par *par, u16 cmd,
178				    int argc, u16 *argv)
179{
180	if (par->board->mmio_write)
181		broadsheet_mmio_send_cmdargs(par, cmd, argc, argv);
182	else
183		broadsheet_gpio_send_cmdargs(par, cmd, argc, argv);
184}
185
186static void broadsheet_gpio_burst_write(struct broadsheetfb_par *par, int size,
187					u16 *data)
188{
189	int i;
190	u16 tmp;
191
192	par->board->set_ctl(par, BS_CS, 0);
193	par->board->set_ctl(par, BS_DC, 1);
194
195	for (i = 0; i < size; i++) {
196		par->board->set_ctl(par, BS_WR, 0);
197		tmp = (data[i] & 0x0F) << 4;
198		tmp |= (data[i] & 0x0F00) << 4;
199		par->board->set_hdb(par, tmp);
200		par->board->set_ctl(par, BS_WR, 1);
201	}
202
203	par->board->set_ctl(par, BS_CS, 1);
204}
205
206static void broadsheet_mmio_burst_write(struct broadsheetfb_par *par, int size,
207				   u16 *data)
208{
209	int i;
210	u16 tmp;
211
212	for (i = 0; i < size; i++) {
213		tmp = (data[i] & 0x0F) << 4;
214		tmp |= (data[i] & 0x0F00) << 4;
215		par->board->mmio_write(par, BS_MMIO_DATA, tmp);
216	}
217
218}
219
220static void broadsheet_burst_write(struct broadsheetfb_par *par, int size,
221				   u16 *data)
222{
223	if (par->board->mmio_write)
224		broadsheet_mmio_burst_write(par, size, data);
225	else
226		broadsheet_gpio_burst_write(par, size, data);
227}
228
229static u16 broadsheet_gpio_get_data(struct broadsheetfb_par *par)
230{
231	u16 res;
232	/* wait for ready to go hi. (lo is busy) */
233	par->board->wait_for_rdy(par);
234
235	/* cs lo, dc lo for cmd, we lo for each data, db as usual */
236	par->board->set_ctl(par, BS_DC, 1);
237	par->board->set_ctl(par, BS_CS, 0);
238	par->board->set_ctl(par, BS_WR, 0);
239
240	res = par->board->get_hdb(par);
241
242	/* strobe wr */
243	par->board->set_ctl(par, BS_WR, 1);
244	par->board->set_ctl(par, BS_CS, 1);
245
246	return res;
247}
248
249
250static u16 broadsheet_get_data(struct broadsheetfb_par *par)
251{
252	if (par->board->mmio_read)
253		return par->board->mmio_read(par);
254	else
255		return broadsheet_gpio_get_data(par);
256}
257
258static void broadsheet_gpio_write_reg(struct broadsheetfb_par *par, u16 reg,
259					u16 data)
260{
261	/* wait for ready to go hi. (lo is busy) */
262	par->board->wait_for_rdy(par);
263
264	/* cs lo, dc lo for cmd, we lo for each data, db as usual */
265	par->board->set_ctl(par, BS_CS, 0);
266
267	broadsheet_gpio_issue_cmd(par, BS_CMD_WR_REG);
268
269	par->board->set_ctl(par, BS_DC, 1);
270
271	broadsheet_gpio_issue_data(par, reg);
272	broadsheet_gpio_issue_data(par, data);
273
274	par->board->set_ctl(par, BS_CS, 1);
275}
276
277static void broadsheet_mmio_write_reg(struct broadsheetfb_par *par, u16 reg,
278				 u16 data)
279{
280	par->board->mmio_write(par, BS_MMIO_CMD, BS_CMD_WR_REG);
281	par->board->mmio_write(par, BS_MMIO_DATA, reg);
282	par->board->mmio_write(par, BS_MMIO_DATA, data);
283
284}
285
286static void broadsheet_write_reg(struct broadsheetfb_par *par, u16 reg,
287					u16 data)
288{
289	if (par->board->mmio_write)
290		broadsheet_mmio_write_reg(par, reg, data);
291	else
292		broadsheet_gpio_write_reg(par, reg, data);
293}
294
295static void broadsheet_write_reg32(struct broadsheetfb_par *par, u16 reg,
296					u32 data)
297{
298	broadsheet_write_reg(par, reg, cpu_to_le32(data) & 0xFFFF);
299	broadsheet_write_reg(par, reg + 2, (cpu_to_le32(data) >> 16) & 0xFFFF);
300}
301
302
303static u16 broadsheet_read_reg(struct broadsheetfb_par *par, u16 reg)
304{
305	broadsheet_send_cmdargs(par, BS_CMD_RD_REG, 1, &reg);
306	par->board->wait_for_rdy(par);
307	return broadsheet_get_data(par);
308}
309
310/* functions for waveform manipulation */
311static int is_broadsheet_pll_locked(struct broadsheetfb_par *par)
312{
313	return broadsheet_read_reg(par, 0x000A) & 0x0001;
314}
315
316static int broadsheet_setup_plls(struct broadsheetfb_par *par)
317{
318	int retry_count = 0;
319	u16 tmp;
320
321	/* disable arral saemipu mode */
322	broadsheet_write_reg(par, 0x0006, 0x0000);
323
324	broadsheet_write_reg(par, 0x0010, 0x0004);
325	broadsheet_write_reg(par, 0x0012, 0x5949);
326	broadsheet_write_reg(par, 0x0014, 0x0040);
327	broadsheet_write_reg(par, 0x0016, 0x0000);
328
329	do {
330		if (retry_count++ > 100)
331			return -ETIMEDOUT;
332		mdelay(1);
333	} while (!is_broadsheet_pll_locked(par));
334
335	tmp = broadsheet_read_reg(par, 0x0006);
336	tmp &= ~0x1;
337	broadsheet_write_reg(par, 0x0006, tmp);
338
339	return 0;
340}
341
342static int broadsheet_setup_spi(struct broadsheetfb_par *par)
343{
344
345	broadsheet_write_reg(par, 0x0204, ((3 << 3) | 1));
346	broadsheet_write_reg(par, 0x0208, 0x0001);
347
348	return 0;
349}
350
351static int broadsheet_setup_spiflash(struct broadsheetfb_par *par,
352						u16 *orig_sfmcd)
353{
354
355	*orig_sfmcd = broadsheet_read_reg(par, 0x0204);
356	broadsheet_write_reg(par, 0x0208, 0);
357	broadsheet_write_reg(par, 0x0204, 0);
358	broadsheet_write_reg(par, 0x0204, ((3 << 3) | 1));
359
360	return 0;
361}
362
363static int broadsheet_spiflash_wait_for_bit(struct broadsheetfb_par *par,
364						u16 reg, int bitnum, int val,
365						int timeout)
366{
367	u16 tmp;
368
369	do {
370		tmp = broadsheet_read_reg(par, reg);
371		if (((tmp >> bitnum) & 1) == val)
372			return 0;
373		mdelay(1);
374	} while (timeout--);
375
376	return -ETIMEDOUT;
377}
378
379static int broadsheet_spiflash_write_byte(struct broadsheetfb_par *par, u8 data)
380{
381	broadsheet_write_reg(par, 0x0202, (data | 0x100));
382
383	return broadsheet_spiflash_wait_for_bit(par, 0x0206, 3, 0, 100);
384}
385
386static int broadsheet_spiflash_read_byte(struct broadsheetfb_par *par, u8 *data)
387{
388	int err;
389	u16 tmp;
390
391	broadsheet_write_reg(par, 0x0202, 0);
392
393	err = broadsheet_spiflash_wait_for_bit(par, 0x0206, 3, 0, 100);
394	if (err)
395		return err;
396
397	tmp = broadsheet_read_reg(par, 0x200);
398
399	*data = tmp & 0xFF;
400
401	return 0;
402}
403
404static int broadsheet_spiflash_wait_for_status(struct broadsheetfb_par *par,
405								int timeout)
406{
407	u8 tmp;
408	int err;
409
410	do {
411		broadsheet_write_reg(par, 0x0208, 1);
412
413		err = broadsheet_spiflash_write_byte(par, 0x05);
414		if (err)
415			goto failout;
416
417		err = broadsheet_spiflash_read_byte(par, &tmp);
418		if (err)
419			goto failout;
420
421		broadsheet_write_reg(par, 0x0208, 0);
422
423		if (!(tmp & 0x1))
424			return 0;
425
426		mdelay(5);
427	} while (timeout--);
428
429	dev_err(par->info->device, "Timed out waiting for spiflash status\n");
430	return -ETIMEDOUT;
431
432failout:
433	broadsheet_write_reg(par, 0x0208, 0);
434	return err;
435}
436
437static int broadsheet_spiflash_op_on_address(struct broadsheetfb_par *par,
438							u8 op, u32 addr)
439{
440	int i;
441	u8 tmp;
442	int err;
443
444	broadsheet_write_reg(par, 0x0208, 1);
445
446	err = broadsheet_spiflash_write_byte(par, op);
447	if (err)
448		return err;
449
450	for (i = 2; i >= 0; i--) {
451		tmp = ((addr >> (i * 8)) & 0xFF);
452		err = broadsheet_spiflash_write_byte(par, tmp);
453		if (err)
454			return err;
455	}
456
457	return err;
458}
459
460static int broadsheet_verify_spiflash(struct broadsheetfb_par *par,
461						int *flash_type)
462{
463	int err = 0;
464	u8 sig;
465
466	err = broadsheet_spiflash_op_on_address(par, 0xAB, 0x00000000);
467	if (err)
468		goto failout;
469
470	err = broadsheet_spiflash_read_byte(par, &sig);
471	if (err)
472		goto failout;
473
474	if ((sig != 0x10) && (sig != 0x11)) {
475		dev_err(par->info->device, "Unexpected flash type\n");
476		err = -EINVAL;
477		goto failout;
478	}
479
480	*flash_type = sig;
481
482failout:
483	broadsheet_write_reg(par, 0x0208, 0);
484	return err;
485}
486
487static int broadsheet_setup_for_wfm_write(struct broadsheetfb_par *par,
488					u16 *initial_sfmcd, int *flash_type)
489
490{
491	int err;
492
493	err = broadsheet_setup_plls(par);
494	if (err)
495		return err;
496
497	broadsheet_write_reg(par, 0x0106, 0x0203);
498
499	err = broadsheet_setup_spi(par);
500	if (err)
501		return err;
502
503	err = broadsheet_setup_spiflash(par, initial_sfmcd);
504	if (err)
505		return err;
506
507	return broadsheet_verify_spiflash(par, flash_type);
508}
509
510static int broadsheet_spiflash_write_control(struct broadsheetfb_par *par,
511						int mode)
512{
513	int err;
514
515	broadsheet_write_reg(par, 0x0208, 1);
516	if (mode)
517		err = broadsheet_spiflash_write_byte(par, 0x06);
518	else
519		err = broadsheet_spiflash_write_byte(par, 0x04);
520
521	broadsheet_write_reg(par, 0x0208, 0);
522	return err;
523}
524
525static int broadsheet_spiflash_erase_sector(struct broadsheetfb_par *par,
526						int addr)
527{
528	int err;
529
530	broadsheet_spiflash_write_control(par, 1);
531
532	err = broadsheet_spiflash_op_on_address(par, 0xD8, addr);
533
534	broadsheet_write_reg(par, 0x0208, 0);
535
536	if (err)
537		return err;
538
539	err = broadsheet_spiflash_wait_for_status(par, 1000);
540
541	return err;
542}
543
544static int broadsheet_spiflash_read_range(struct broadsheetfb_par *par,
545						int addr, int size, char *data)
546{
547	int err;
548	int i;
549
550	err = broadsheet_spiflash_op_on_address(par, 0x03, addr);
551	if (err)
552		goto failout;
553
554	for (i = 0; i < size; i++) {
555		err = broadsheet_spiflash_read_byte(par, &data[i]);
556		if (err)
557			goto failout;
558	}
559
560failout:
561	broadsheet_write_reg(par, 0x0208, 0);
562	return err;
563}
564
565#define BS_SPIFLASH_PAGE_SIZE 256
566static int broadsheet_spiflash_write_page(struct broadsheetfb_par *par,
567						int addr, const char *data)
568{
569	int err;
570	int i;
571
572	broadsheet_spiflash_write_control(par, 1);
573
574	err = broadsheet_spiflash_op_on_address(par, 0x02, addr);
575	if (err)
576		goto failout;
577
578	for (i = 0; i < BS_SPIFLASH_PAGE_SIZE; i++) {
579		err = broadsheet_spiflash_write_byte(par, data[i]);
580		if (err)
581			goto failout;
582	}
583
584	broadsheet_write_reg(par, 0x0208, 0);
585
586	err = broadsheet_spiflash_wait_for_status(par, 100);
587
588failout:
589	return err;
590}
591
592static int broadsheet_spiflash_write_sector(struct broadsheetfb_par *par,
593				int addr, const char *data, int sector_size)
594{
595	int i;
596	int err;
597
598	for (i = 0; i < sector_size; i += BS_SPIFLASH_PAGE_SIZE) {
599		err = broadsheet_spiflash_write_page(par, addr + i, &data[i]);
600		if (err)
601			return err;
602	}
603	return 0;
604}
605
606/*
607 * The caller must guarantee that the data to be rewritten is entirely
608 * contained within this sector. That is, data_start_addr + data_len
609 * must be less than sector_start_addr + sector_size.
610 */
611static int broadsheet_spiflash_rewrite_sector(struct broadsheetfb_par *par,
612					int sector_size, int data_start_addr,
613					int data_len, const char *data)
614{
615	int err;
616	char *sector_buffer;
617	int tail_start_addr;
618	int start_sector_addr;
619
620	sector_buffer = kzalloc(sizeof(char)*sector_size, GFP_KERNEL);
621	if (!sector_buffer)
622		return -ENOMEM;
623
624	/* the start address of the sector is the 0th byte of that sector */
625	start_sector_addr = (data_start_addr / sector_size) * sector_size;
626
627	/*
628	 * check if there is head data that we need to readback into our sector
629	 * buffer first
630	 */
631	if (data_start_addr != start_sector_addr) {
632		/*
633		 * we need to read every byte up till the start address of our
634		 * data and we put it into our sector buffer.
635		 */
636		err = broadsheet_spiflash_read_range(par, start_sector_addr,
637						data_start_addr, sector_buffer);
638		if (err)
639			return err;
640	}
641
642	/* now we copy our data into the right place in the sector buffer */
643	memcpy(sector_buffer + data_start_addr, data, data_len);
644
645	/*
646	 * now we check if there is a tail section of the sector that we need to
647	 * readback.
648	 */
649	tail_start_addr = (data_start_addr + data_len) % sector_size;
650
651	if (tail_start_addr) {
652		int tail_len;
653
654		tail_len = sector_size - tail_start_addr;
655
656		/* now we read this tail into our sector buffer */
657		err = broadsheet_spiflash_read_range(par, tail_start_addr,
658			tail_len, sector_buffer + tail_start_addr);
659		if (err)
660			return err;
661	}
662
663	/* if we got here we have the full sector that we want to rewrite. */
664
665	/* first erase the sector */
666	err = broadsheet_spiflash_erase_sector(par, start_sector_addr);
667	if (err)
668		return err;
669
670	/* now write it */
671	err = broadsheet_spiflash_write_sector(par, start_sector_addr,
672					sector_buffer, sector_size);
673	return err;
674}
675
676static int broadsheet_write_spiflash(struct broadsheetfb_par *par, u32 wfm_addr,
677				const u8 *wfm, int bytecount, int flash_type)
678{
679	int sector_size;
680	int err;
681	int cur_addr;
682	int writecount;
683	int maxlen;
684	int offset = 0;
685
686	switch (flash_type) {
687	case 0x10:
688		sector_size = 32*1024;
689		break;
690	case 0x11:
691	default:
692		sector_size = 64*1024;
693		break;
694	}
695
696	while (bytecount) {
697		cur_addr = wfm_addr + offset;
698		maxlen = roundup(cur_addr, sector_size) - cur_addr;
699		writecount = min(bytecount, maxlen);
700
701		err = broadsheet_spiflash_rewrite_sector(par, sector_size,
702				cur_addr, writecount, wfm + offset);
703		if (err)
704			return err;
705
706		offset += writecount;
707		bytecount -= writecount;
708	}
709
710	return 0;
711}
712
713static int broadsheet_store_waveform_to_spiflash(struct broadsheetfb_par *par,
714						const u8 *wfm, size_t wfm_size)
715{
716	int err = 0;
717	u16 initial_sfmcd = 0;
718	int flash_type = 0;
719
720	err = broadsheet_setup_for_wfm_write(par, &initial_sfmcd, &flash_type);
721	if (err)
722		goto failout;
723
724	err = broadsheet_write_spiflash(par, 0x886, wfm, wfm_size, flash_type);
725
726failout:
727	broadsheet_write_reg(par, 0x0204, initial_sfmcd);
728	return err;
729}
730
731static ssize_t broadsheet_loadstore_waveform(struct device *dev,
732						struct device_attribute *attr,
733						const char *buf, size_t len)
734{
735	int err;
736	struct fb_info *info = dev_get_drvdata(dev);
737	struct broadsheetfb_par *par = info->par;
738	const struct firmware *fw_entry;
739
740	if (len < 1)
741		return -EINVAL;
742
743	err = request_firmware(&fw_entry, "broadsheet.wbf", dev);
744	if (err < 0) {
745		dev_err(dev, "Failed to get broadsheet waveform\n");
746		goto err_failed;
747	}
748
749	/* try to enforce reasonable min max on waveform */
750	if ((fw_entry->size < 8*1024) || (fw_entry->size > 64*1024)) {
751		dev_err(dev, "Invalid waveform\n");
752		err = -EINVAL;
753		goto err_failed;
754	}
755
756	mutex_lock(&(par->io_lock));
757	err = broadsheet_store_waveform_to_spiflash(par, fw_entry->data,
758							fw_entry->size);
759
760	mutex_unlock(&(par->io_lock));
761	if (err < 0) {
762		dev_err(dev, "Failed to store broadsheet waveform\n");
763		goto err_failed;
764	}
765
766	dev_info(dev, "Stored broadsheet waveform, size %zd\n", fw_entry->size);
767
768	return len;
769
770err_failed:
771	return err;
772}
773static DEVICE_ATTR(loadstore_waveform, S_IWUSR, NULL,
774			broadsheet_loadstore_waveform);
775
776/* upper level functions that manipulate the display and other stuff */
777static void __devinit broadsheet_init_display(struct broadsheetfb_par *par)
778{
779	u16 args[5];
780	int xres = par->info->var.xres;
781	int yres = par->info->var.yres;
782
783	args[0] = panel_table[par->panel_index].w;
784	args[1] = panel_table[par->panel_index].h;
785	args[2] = panel_table[par->panel_index].sdcfg;
786	args[3] = panel_table[par->panel_index].gdcfg;
787	args[4] = panel_table[par->panel_index].lutfmt;
788	broadsheet_send_cmdargs(par, BS_CMD_INIT_DSPE_CFG, 5, args);
789
790	/* did the controller really set it? */
791	broadsheet_send_cmdargs(par, BS_CMD_INIT_DSPE_CFG, 5, args);
792
793	args[0] = panel_table[par->panel_index].fsynclen;
794	args[1] = panel_table[par->panel_index].fendfbegin;
795	args[2] = panel_table[par->panel_index].lsynclen;
796	args[3] = panel_table[par->panel_index].lendlbegin;
797	args[4] = panel_table[par->panel_index].pixclk;
798	broadsheet_send_cmdargs(par, BS_CMD_INIT_DSPE_TMG, 5, args);
799
800	broadsheet_write_reg32(par, 0x310, xres*yres*2);
801
802	/* setup waveform */
803	args[0] = 0x886;
804	args[1] = 0;
805	broadsheet_send_cmdargs(par, BS_CMD_RD_WFM_INFO, 2, args);
806
807	broadsheet_send_command(par, BS_CMD_UPD_GDRV_CLR);
808
809	broadsheet_send_command(par, BS_CMD_WAIT_DSPE_TRG);
810
811	broadsheet_write_reg(par, 0x330, 0x84);
812
813	broadsheet_send_command(par, BS_CMD_WAIT_DSPE_TRG);
814
815	args[0] = (0x3 << 4);
816	broadsheet_send_cmdargs(par, BS_CMD_LD_IMG, 1, args);
817
818	args[0] = 0x154;
819	broadsheet_send_cmdargs(par, BS_CMD_WR_REG, 1, args);
820
821	broadsheet_burst_write(par, (panel_table[par->panel_index].w *
822					panel_table[par->panel_index].h)/2,
823					(u16 *) par->info->screen_base);
824
825	broadsheet_send_command(par, BS_CMD_LD_IMG_END);
826
827	args[0] = 0x4300;
828	broadsheet_send_cmdargs(par, BS_CMD_UPD_FULL, 1, args);
829
830	broadsheet_send_command(par, BS_CMD_WAIT_DSPE_TRG);
831
832	broadsheet_send_command(par, BS_CMD_WAIT_DSPE_FREND);
833
834	par->board->wait_for_rdy(par);
835}
836
837static void __devinit broadsheet_identify(struct broadsheetfb_par *par)
838{
839	u16 rev, prc;
840	struct device *dev = par->info->device;
841
842	rev = broadsheet_read_reg(par, BS_REG_REV);
843	prc = broadsheet_read_reg(par, BS_REG_PRC);
844	dev_info(dev, "Broadsheet Rev 0x%x, Product Code 0x%x\n", rev, prc);
845
846	if (prc != 0x0047)
847		dev_warn(dev, "Unrecognized Broadsheet Product Code\n");
848	if (rev != 0x0100)
849		dev_warn(dev, "Unrecognized Broadsheet Revision\n");
850}
851
852static void __devinit broadsheet_init(struct broadsheetfb_par *par)
853{
854	broadsheet_send_command(par, BS_CMD_INIT_SYS_RUN);
855	/* the controller needs a second */
856	msleep(1000);
857	broadsheet_init_display(par);
858}
859
860static void broadsheetfb_dpy_update_pages(struct broadsheetfb_par *par,
861						u16 y1, u16 y2)
862{
863	u16 args[5];
864	unsigned char *buf = (unsigned char *)par->info->screen_base;
865
866	mutex_lock(&(par->io_lock));
867	/* y1 must be a multiple of 4 so drop the lower bits */
868	y1 &= 0xFFFC;
869	/* y2 must be a multiple of 4 , but - 1 so up the lower bits */
870	y2 |= 0x0003;
871
872	args[0] = 0x3 << 4;
873	args[1] = 0;
874	args[2] = y1;
875	args[3] = cpu_to_le16(par->info->var.xres);
876	args[4] = y2;
877	broadsheet_send_cmdargs(par, BS_CMD_LD_IMG_AREA, 5, args);
878
879	args[0] = 0x154;
880	broadsheet_send_cmdargs(par, BS_CMD_WR_REG, 1, args);
881
882	buf += y1 * par->info->var.xres;
883	broadsheet_burst_write(par, ((1 + y2 - y1) * par->info->var.xres)/2,
884				(u16 *) buf);
885
886	broadsheet_send_command(par, BS_CMD_LD_IMG_END);
887
888	args[0] = 0x4300;
889	broadsheet_send_cmdargs(par, BS_CMD_UPD_FULL, 1, args);
890
891	broadsheet_send_command(par, BS_CMD_WAIT_DSPE_TRG);
892
893	broadsheet_send_command(par, BS_CMD_WAIT_DSPE_FREND);
894
895	par->board->wait_for_rdy(par);
896	mutex_unlock(&(par->io_lock));
897
898}
899
900static void broadsheetfb_dpy_update(struct broadsheetfb_par *par)
901{
902	u16 args[5];
903
904	mutex_lock(&(par->io_lock));
905	args[0] = 0x3 << 4;
906	broadsheet_send_cmdargs(par, BS_CMD_LD_IMG, 1, args);
907
908	args[0] = 0x154;
909	broadsheet_send_cmdargs(par, BS_CMD_WR_REG, 1, args);
910	broadsheet_burst_write(par, (panel_table[par->panel_index].w *
911					panel_table[par->panel_index].h)/2,
912					(u16 *) par->info->screen_base);
913
914	broadsheet_send_command(par, BS_CMD_LD_IMG_END);
915
916	args[0] = 0x4300;
917	broadsheet_send_cmdargs(par, BS_CMD_UPD_FULL, 1, args);
918
919	broadsheet_send_command(par, BS_CMD_WAIT_DSPE_TRG);
920
921	broadsheet_send_command(par, BS_CMD_WAIT_DSPE_FREND);
922
923	par->board->wait_for_rdy(par);
924	mutex_unlock(&(par->io_lock));
925}
926
927/* this is called back from the deferred io workqueue */
928static void broadsheetfb_dpy_deferred_io(struct fb_info *info,
929				struct list_head *pagelist)
930{
931	u16 y1 = 0, h = 0;
932	int prev_index = -1;
933	struct page *cur;
934	struct fb_deferred_io *fbdefio = info->fbdefio;
935	int h_inc;
936	u16 yres = info->var.yres;
937	u16 xres = info->var.xres;
938
939	/* height increment is fixed per page */
940	h_inc = DIV_ROUND_UP(PAGE_SIZE , xres);
941
942	/* walk the written page list and swizzle the data */
943	list_for_each_entry(cur, &fbdefio->pagelist, lru) {
944		if (prev_index < 0) {
945			/* just starting so assign first page */
946			y1 = (cur->index << PAGE_SHIFT) / xres;
947			h = h_inc;
948		} else if ((prev_index + 1) == cur->index) {
949			/* this page is consecutive so increase our height */
950			h += h_inc;
951		} else {
952			/* page not consecutive, issue previous update first */
953			broadsheetfb_dpy_update_pages(info->par, y1, y1 + h);
954			/* start over with our non consecutive page */
955			y1 = (cur->index << PAGE_SHIFT) / xres;
956			h = h_inc;
957		}
958		prev_index = cur->index;
959	}
960
961	/* if we still have any pages to update we do so now */
962	if (h >= yres) {
963		/* its a full screen update, just do it */
964		broadsheetfb_dpy_update(info->par);
965	} else {
966		broadsheetfb_dpy_update_pages(info->par, y1,
967						min((u16) (y1 + h), yres));
968	}
969}
970
971static void broadsheetfb_fillrect(struct fb_info *info,
972				   const struct fb_fillrect *rect)
973{
974	struct broadsheetfb_par *par = info->par;
975
976	sys_fillrect(info, rect);
977
978	broadsheetfb_dpy_update(par);
979}
980
981static void broadsheetfb_copyarea(struct fb_info *info,
982				   const struct fb_copyarea *area)
983{
984	struct broadsheetfb_par *par = info->par;
985
986	sys_copyarea(info, area);
987
988	broadsheetfb_dpy_update(par);
989}
990
991static void broadsheetfb_imageblit(struct fb_info *info,
992				const struct fb_image *image)
993{
994	struct broadsheetfb_par *par = info->par;
995
996	sys_imageblit(info, image);
997
998	broadsheetfb_dpy_update(par);
999}
1000
1001/*
1002 * this is the slow path from userspace. they can seek and write to
1003 * the fb. it's inefficient to do anything less than a full screen draw
1004 */
1005static ssize_t broadsheetfb_write(struct fb_info *info, const char __user *buf,
1006				size_t count, loff_t *ppos)
1007{
1008	struct broadsheetfb_par *par = info->par;
1009	unsigned long p = *ppos;
1010	void *dst;
1011	int err = 0;
1012	unsigned long total_size;
1013
1014	if (info->state != FBINFO_STATE_RUNNING)
1015		return -EPERM;
1016
1017	total_size = info->fix.smem_len;
1018
1019	if (p > total_size)
1020		return -EFBIG;
1021
1022	if (count > total_size) {
1023		err = -EFBIG;
1024		count = total_size;
1025	}
1026
1027	if (count + p > total_size) {
1028		if (!err)
1029			err = -ENOSPC;
1030
1031		count = total_size - p;
1032	}
1033
1034	dst = (void *)(info->screen_base + p);
1035
1036	if (copy_from_user(dst, buf, count))
1037		err = -EFAULT;
1038
1039	if  (!err)
1040		*ppos += count;
1041
1042	broadsheetfb_dpy_update(par);
1043
1044	return (err) ? err : count;
1045}
1046
1047static struct fb_ops broadsheetfb_ops = {
1048	.owner		= THIS_MODULE,
1049	.fb_read        = fb_sys_read,
1050	.fb_write	= broadsheetfb_write,
1051	.fb_fillrect	= broadsheetfb_fillrect,
1052	.fb_copyarea	= broadsheetfb_copyarea,
1053	.fb_imageblit	= broadsheetfb_imageblit,
1054};
1055
1056static struct fb_deferred_io broadsheetfb_defio = {
1057	.delay		= HZ/4,
1058	.deferred_io	= broadsheetfb_dpy_deferred_io,
1059};
1060
1061static int __devinit broadsheetfb_probe(struct platform_device *dev)
1062{
1063	struct fb_info *info;
1064	struct broadsheet_board *board;
1065	int retval = -ENOMEM;
1066	int videomemorysize;
1067	unsigned char *videomemory;
1068	struct broadsheetfb_par *par;
1069	int i;
1070	int dpyw, dpyh;
1071	int panel_index;
1072
1073	/* pick up board specific routines */
1074	board = dev->dev.platform_data;
1075	if (!board)
1076		return -EINVAL;
1077
1078	/* try to count device specific driver, if can't, platform recalls */
1079	if (!try_module_get(board->owner))
1080		return -ENODEV;
1081
1082	info = framebuffer_alloc(sizeof(struct broadsheetfb_par), &dev->dev);
1083	if (!info)
1084		goto err;
1085
1086	switch (board->get_panel_type()) {
1087	case 37:
1088		panel_index = 1;
1089		break;
1090	case 97:
1091		panel_index = 2;
1092		break;
1093	case 6:
1094	default:
1095		panel_index = 0;
1096		break;
1097	}
1098
1099	dpyw = panel_table[panel_index].w;
1100	dpyh = panel_table[panel_index].h;
1101
1102	videomemorysize = roundup((dpyw*dpyh), PAGE_SIZE);
1103
1104	videomemory = vmalloc(videomemorysize);
1105	if (!videomemory)
1106		goto err_fb_rel;
1107
1108	memset(videomemory, 0, videomemorysize);
1109
1110	info->screen_base = (char *)videomemory;
1111	info->fbops = &broadsheetfb_ops;
1112
1113	broadsheetfb_var.xres = dpyw;
1114	broadsheetfb_var.yres = dpyh;
1115	broadsheetfb_var.xres_virtual = dpyw;
1116	broadsheetfb_var.yres_virtual = dpyh;
1117	info->var = broadsheetfb_var;
1118
1119	broadsheetfb_fix.line_length = dpyw;
1120	info->fix = broadsheetfb_fix;
1121	info->fix.smem_len = videomemorysize;
1122	par = info->par;
1123	par->panel_index = panel_index;
1124	par->info = info;
1125	par->board = board;
1126	par->write_reg = broadsheet_write_reg;
1127	par->read_reg = broadsheet_read_reg;
1128	init_waitqueue_head(&par->waitq);
1129
1130	mutex_init(&par->io_lock);
1131
1132	info->flags = FBINFO_FLAG_DEFAULT | FBINFO_VIRTFB;
1133
1134	info->fbdefio = &broadsheetfb_defio;
1135	fb_deferred_io_init(info);
1136
1137	retval = fb_alloc_cmap(&info->cmap, 16, 0);
1138	if (retval < 0) {
1139		dev_err(&dev->dev, "Failed to allocate colormap\n");
1140		goto err_vfree;
1141	}
1142
1143	/* set cmap */
1144	for (i = 0; i < 16; i++)
1145		info->cmap.red[i] = (((2*i)+1)*(0xFFFF))/32;
1146	memcpy(info->cmap.green, info->cmap.red, sizeof(u16)*16);
1147	memcpy(info->cmap.blue, info->cmap.red, sizeof(u16)*16);
1148
1149	retval = par->board->setup_irq(info);
1150	if (retval < 0)
1151		goto err_cmap;
1152
1153	/* this inits the dpy */
1154	retval = board->init(par);
1155	if (retval < 0)
1156		goto err_free_irq;
1157
1158	broadsheet_identify(par);
1159
1160	broadsheet_init(par);
1161
1162	retval = register_framebuffer(info);
1163	if (retval < 0)
1164		goto err_free_irq;
1165
1166	platform_set_drvdata(dev, info);
1167
1168	retval = device_create_file(&dev->dev, &dev_attr_loadstore_waveform);
1169	if (retval < 0)
1170		goto err_unreg_fb;
1171
1172	printk(KERN_INFO
1173	       "fb%d: Broadsheet frame buffer, using %dK of video memory\n",
1174	       info->node, videomemorysize >> 10);
1175
1176
1177	return 0;
1178
1179err_unreg_fb:
1180	unregister_framebuffer(info);
1181err_free_irq:
1182	board->cleanup(par);
1183err_cmap:
1184	fb_dealloc_cmap(&info->cmap);
1185err_vfree:
1186	vfree(videomemory);
1187err_fb_rel:
1188	framebuffer_release(info);
1189err:
1190	module_put(board->owner);
1191	return retval;
1192
1193}
1194
1195static int __devexit broadsheetfb_remove(struct platform_device *dev)
1196{
1197	struct fb_info *info = platform_get_drvdata(dev);
1198
1199	if (info) {
1200		struct broadsheetfb_par *par = info->par;
1201
1202		device_remove_file(info->dev, &dev_attr_loadstore_waveform);
1203		unregister_framebuffer(info);
1204		fb_deferred_io_cleanup(info);
1205		par->board->cleanup(par);
1206		fb_dealloc_cmap(&info->cmap);
1207		vfree((void *)info->screen_base);
1208		module_put(par->board->owner);
1209		framebuffer_release(info);
1210	}
1211	return 0;
1212}
1213
1214static struct platform_driver broadsheetfb_driver = {
1215	.probe	= broadsheetfb_probe,
1216	.remove = broadsheetfb_remove,
1217	.driver	= {
1218		.owner	= THIS_MODULE,
1219		.name	= "broadsheetfb",
1220	},
1221};
1222
1223static int __init broadsheetfb_init(void)
1224{
1225	return platform_driver_register(&broadsheetfb_driver);
1226}
1227
1228static void __exit broadsheetfb_exit(void)
1229{
1230	platform_driver_unregister(&broadsheetfb_driver);
1231}
1232
1233module_init(broadsheetfb_init);
1234module_exit(broadsheetfb_exit);
1235
1236MODULE_DESCRIPTION("fbdev driver for Broadsheet controller");
1237MODULE_AUTHOR("Jaya Kumar");
1238MODULE_LICENSE("GPL");
1239