aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/fb/cmap_xfbdev.txt53
-rw-r--r--Documentation/fb/metronomefb.txt38
-rw-r--r--drivers/video/Kconfig14
-rw-r--r--drivers/video/Makefile1
-rw-r--r--drivers/video/fb_defio.c22
-rw-r--r--drivers/video/metronomefb.c999
6 files changed, 1125 insertions, 2 deletions
diff --git a/Documentation/fb/cmap_xfbdev.txt b/Documentation/fb/cmap_xfbdev.txt
new file mode 100644
index 000000000000..55e1f0a3d2b4
--- /dev/null
+++ b/Documentation/fb/cmap_xfbdev.txt
@@ -0,0 +1,53 @@
1Understanding fbdev's cmap
2--------------------------
3
4These notes explain how X's dix layer uses fbdev's cmap structures.
5
6*. example of relevant structures in fbdev as used for a 3-bit grayscale cmap
7struct fb_var_screeninfo {
8 .bits_per_pixel = 8,
9 .grayscale = 1,
10 .red = { 4, 3, 0 },
11 .green = { 0, 0, 0 },
12 .blue = { 0, 0, 0 },
13}
14struct fb_fix_screeninfo {
15 .visual = FB_VISUAL_STATIC_PSEUDOCOLOR,
16}
17for (i = 0; i < 8; i++)
18 info->cmap.red[i] = (((2*i)+1)*(0xFFFF))/16;
19memcpy(info->cmap.green, info->cmap.red, sizeof(u16)*8);
20memcpy(info->cmap.blue, info->cmap.red, sizeof(u16)*8);
21
22*. X11 apps do something like the following when trying to use grayscale.
23for (i=0; i < 8; i++) {
24 char colorspec[64];
25 memset(colorspec,0,64);
26 sprintf(colorspec, "rgb:%x/%x/%x", i*36,i*36,i*36);
27 if (!XParseColor(outputDisplay, testColormap, colorspec, &wantedColor))
28 printf("Can't get color %s\n",colorspec);
29 XAllocColor(outputDisplay, testColormap, &wantedColor);
30 grays[i] = wantedColor;
31}
32There's also named equivalents like gray1..x provided you have an rgb.txt.
33
34Somewhere in X's callchain, this results in a call to X code that handles the
35colormap. For example, Xfbdev hits the following:
36
37xc-011010/programs/Xserver/dix/colormap.c:
38
39FindBestPixel(pentFirst, size, prgb, channel)
40
41dr = (long) pent->co.local.red - prgb->red;
42dg = (long) pent->co.local.green - prgb->green;
43db = (long) pent->co.local.blue - prgb->blue;
44sq = dr * dr;
45UnsignedToBigNum (sq, &sum);
46BigNumAdd (&sum, &temp, &sum);
47
48co.local.red are entries that were brought in through FBIOGETCMAP which come
49directly from the info->cmap.red that was listed above. The prgb is the rgb
50that the app wants to match to. The above code is doing what looks like a least
51squares matching function. That's why the cmap entries can't be set to the left
52hand side boundaries of a color range.
53
diff --git a/Documentation/fb/metronomefb.txt b/Documentation/fb/metronomefb.txt
new file mode 100644
index 000000000000..b9a2e7b7e838
--- /dev/null
+++ b/Documentation/fb/metronomefb.txt
@@ -0,0 +1,38 @@
1 Metronomefb
2 -----------
3Maintained by Jaya Kumar <jayakumar.lkml.gmail.com>
4Last revised: Nov 20, 2007
5
6Metronomefb is a driver for the Metronome display controller. The controller
7is from E-Ink Corporation. It is intended to be used to drive the E-Ink
8Vizplex display media. E-Ink hosts some details of this controller and the
9display media here http://www.e-ink.com/products/matrix/metronome.html .
10
11Metronome is interfaced to the host CPU through the AMLCD interface. The
12host CPU generates the control information and the image in a framebuffer
13which is then delivered to the AMLCD interface by a host specific method.
14Currently, that's implemented for the PXA's LCDC controller. The display and
15error status are each pulled through individual GPIOs.
16
17Metronomefb was written for the PXA255/gumstix/lyre combination and
18therefore currently has board set specific code in it. If other boards based on
19other architectures are available, then the host specific code can be separated
20and abstracted out.
21
22Metronomefb requires waveform information which is delivered via the AMLCD
23interface to the metronome controller. The waveform information is expected to
24be delivered from userspace via the firmware class interface. The waveform file
25can be compressed as long as your udev or hotplug script is aware of the need
26to uncompress it before delivering it. metronomefb will ask for waveform.wbf
27which would typically go into /lib/firmware/waveform.wbf depending on your
28udev/hotplug setup. I have only tested with a single waveform file which was
29originally labeled 23P01201_60_WT0107_MTC. I do not know what it stands for.
30Caution should be exercised when manipulating the waveform as there may be
31a possibility that it could have some permanent effects on the display media.
32I neither have access to nor know exactly what the waveform does in terms of
33the physical media.
34
35Metronomefb uses the deferred IO interface so that it can provide a memory
36mappable frame buffer. It has been tested with tinyx (Xfbdev). It is known
37to work at this time with xeyes, xclock, xloadimage, xpdf.
38
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index e0b0580705e4..1bd5fb30237d 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -1893,6 +1893,20 @@ config FB_XILINX
1893 framebuffer. ML300 carries a 640*480 LCD display on the board, 1893 framebuffer. ML300 carries a 640*480 LCD display on the board,
1894 ML403 uses a standard DB15 VGA connector. 1894 ML403 uses a standard DB15 VGA connector.
1895 1895
1896config FB_METRONOME
1897 tristate "Metronome display controller support"
1898 depends on FB && ARCH_PXA && MMU
1899 select FB_SYS_FILLRECT
1900 select FB_SYS_COPYAREA
1901 select FB_SYS_IMAGEBLIT
1902 select FB_SYS_FOPS
1903 select FB_DEFERRED_IO
1904 help
1905 This enables support for the Metronome display controller. Tested
1906 with an E-Ink 800x600 display and Gumstix Connex through an AMLCD
1907 interface. Please read <file:Documentation/fb/metronomefb.txt>
1908 for more information.
1909
1896config FB_VIRTUAL 1910config FB_VIRTUAL
1897 tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)" 1911 tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)"
1898 depends on FB 1912 depends on FB
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 03371c789039..11c0e5e05f21 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -103,6 +103,7 @@ obj-$(CONFIG_FB_PMAG_AA) += pmag-aa-fb.o
103obj-$(CONFIG_FB_PMAG_BA) += pmag-ba-fb.o 103obj-$(CONFIG_FB_PMAG_BA) += pmag-ba-fb.o
104obj-$(CONFIG_FB_PMAGB_B) += pmagb-b-fb.o 104obj-$(CONFIG_FB_PMAGB_B) += pmagb-b-fb.o
105obj-$(CONFIG_FB_MAXINE) += maxinefb.o 105obj-$(CONFIG_FB_MAXINE) += maxinefb.o
106obj-$(CONFIG_FB_METRONOME) += metronomefb.o
106obj-$(CONFIG_FB_S1D13XXX) += s1d13xxxfb.o 107obj-$(CONFIG_FB_S1D13XXX) += s1d13xxxfb.o
107obj-$(CONFIG_FB_IMX) += imxfb.o 108obj-$(CONFIG_FB_IMX) += imxfb.o
108obj-$(CONFIG_FB_S3C2410) += s3c2410fb.o 109obj-$(CONFIG_FB_S3C2410) += s3c2410fb.o
diff --git a/drivers/video/fb_defio.c b/drivers/video/fb_defio.c
index 0f8cfb988c90..24843fdd5395 100644
--- a/drivers/video/fb_defio.c
+++ b/drivers/video/fb_defio.c
@@ -4,7 +4,7 @@
4 * Copyright (C) 2006 Jaya Kumar 4 * Copyright (C) 2006 Jaya Kumar
5 * 5 *
6 * This file is subject to the terms and conditions of the GNU General Public 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 7 * License. See the file COPYING in the main directory of this archive
8 * for more details. 8 * for more details.
9 */ 9 */
10 10
@@ -31,7 +31,7 @@ static int fb_deferred_io_fault(struct vm_area_struct *vma,
31 unsigned long offset; 31 unsigned long offset;
32 struct page *page; 32 struct page *page;
33 struct fb_info *info = vma->vm_private_data; 33 struct fb_info *info = vma->vm_private_data;
34 /* info->screen_base is in System RAM */ 34 /* info->screen_base is virtual memory */
35 void *screen_base = (void __force *) info->screen_base; 35 void *screen_base = (void __force *) info->screen_base;
36 36
37 offset = vmf->pgoff << PAGE_SHIFT; 37 offset = vmf->pgoff << PAGE_SHIFT;
@@ -43,6 +43,15 @@ static int fb_deferred_io_fault(struct vm_area_struct *vma,
43 return VM_FAULT_SIGBUS; 43 return VM_FAULT_SIGBUS;
44 44
45 get_page(page); 45 get_page(page);
46
47 if (vma->vm_file)
48 page->mapping = vma->vm_file->f_mapping;
49 else
50 printk(KERN_ERR "no mapping available\n");
51
52 BUG_ON(!page->mapping);
53 page->index = vmf->pgoff;
54
46 vmf->page = page; 55 vmf->page = page;
47 return 0; 56 return 0;
48} 57}
@@ -138,11 +147,20 @@ EXPORT_SYMBOL_GPL(fb_deferred_io_init);
138 147
139void fb_deferred_io_cleanup(struct fb_info *info) 148void fb_deferred_io_cleanup(struct fb_info *info)
140{ 149{
150 void *screen_base = (void __force *) info->screen_base;
141 struct fb_deferred_io *fbdefio = info->fbdefio; 151 struct fb_deferred_io *fbdefio = info->fbdefio;
152 struct page *page;
153 int i;
142 154
143 BUG_ON(!fbdefio); 155 BUG_ON(!fbdefio);
144 cancel_delayed_work(&info->deferred_work); 156 cancel_delayed_work(&info->deferred_work);
145 flush_scheduled_work(); 157 flush_scheduled_work();
158
159 /* clear out the mapping that we setup */
160 for (i = 0 ; i < info->fix.smem_len; i += PAGE_SIZE) {
161 page = vmalloc_to_page(screen_base + i);
162 page->mapping = NULL;
163 }
146} 164}
147EXPORT_SYMBOL_GPL(fb_deferred_io_cleanup); 165EXPORT_SYMBOL_GPL(fb_deferred_io_cleanup);
148 166
diff --git a/drivers/video/metronomefb.c b/drivers/video/metronomefb.c
new file mode 100644
index 000000000000..e9a89fd82757
--- /dev/null
+++ b/drivers/video/metronomefb.c
@@ -0,0 +1,999 @@
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. http://support.eink.com/community
14 *
15 * This driver is written to be used with the Metronome display controller.
16 * It was tested with an E-Ink 800x600 Vizplex EPD on a Gumstix Connex board
17 * using the Lyre interface board.
18 *
19 * General notes:
20 * - User must set metronomefb_enable=1 to enable it.
21 * - See Documentation/fb/metronomefb.txt for how metronome works.
22 */
23#include <linux/module.h>
24#include <linux/kernel.h>
25#include <linux/errno.h>
26#include <linux/string.h>
27#include <linux/mm.h>
28#include <linux/slab.h>
29#include <linux/vmalloc.h>
30#include <linux/delay.h>
31#include <linux/interrupt.h>
32#include <linux/fb.h>
33#include <linux/init.h>
34#include <linux/platform_device.h>
35#include <linux/list.h>
36#include <linux/firmware.h>
37#include <linux/dma-mapping.h>
38#include <linux/uaccess.h>
39#include <linux/irq.h>
40
41#include <asm/arch/pxa-regs.h>
42#include <asm/unaligned.h>
43
44#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
56struct metromem_desc {
57 u32 mFDADR0;
58 u32 mFSADR0;
59 u32 mFIDR0;
60 u32 mLDCMD0;
61};
62
63struct metromem_cmd {
64 u16 opcode;
65 u16 args[((64-2)/2)];
66 u16 csum;
67};
68
69struct metronomefb_par {
70 unsigned char *metromem;
71 struct metromem_desc *metromem_desc;
72 struct metromem_cmd *metromem_cmd;
73 unsigned char *metromem_wfm;
74 unsigned char *metromem_img;
75 u16 *metromem_img_csum;
76 u16 *csum_table;
77 int metromemsize;
78 dma_addr_t metromem_dma;
79 dma_addr_t metromem_desc_dma;
80 struct fb_info *info;
81 wait_queue_head_t waitq;
82 u8 frame_count;
83};
84
85/* frame differs from image. frame includes non-visible pixels */
86struct epd_frame {
87 int fw; /* frame width */
88 int fh; /* frame height */
89};
90
91static struct epd_frame epd_frame_table[] = {
92 {
93 .fw = 832,
94 .fh = 622
95 },
96};
97
98static struct fb_fix_screeninfo metronomefb_fix __devinitdata = {
99 .id = "metronomefb",
100 .type = FB_TYPE_PACKED_PIXELS,
101 .visual = FB_VISUAL_STATIC_PSEUDOCOLOR,
102 .xpanstep = 0,
103 .ypanstep = 0,
104 .ywrapstep = 0,
105 .line_length = DPY_W,
106 .accel = FB_ACCEL_NONE,
107};
108
109static struct fb_var_screeninfo metronomefb_var __devinitdata = {
110 .xres = DPY_W,
111 .yres = DPY_H,
112 .xres_virtual = DPY_W,
113 .yres_virtual = DPY_H,
114 .bits_per_pixel = 8,
115 .grayscale = 1,
116 .nonstd = 1,
117 .red = { 4, 3, 0 },
118 .green = { 0, 0, 0 },
119 .blue = { 0, 0, 0 },
120 .transp = { 0, 0, 0 },
121};
122
123static unsigned int metronomefb_enable;
124
125struct waveform_hdr {
126 u8 stuff[32];
127
128 u8 wmta[3];
129 u8 fvsn;
130
131 u8 luts;
132 u8 mc;
133 u8 trc;
134 u8 stuff3;
135
136 u8 endb;
137 u8 swtb;
138 u8 stuff2a[2];
139
140 u8 stuff2b[3];
141 u8 wfm_cs;
142} __attribute__ ((packed));
143
144/* main metronomefb functions */
145static u8 calc_cksum(int start, int end, u8 *mem)
146{
147 u8 tmp = 0;
148 int i;
149
150 for (i = start; i < end; i++)
151 tmp += mem[i];
152
153 return tmp;
154}
155
156static u16 calc_img_cksum(u16 *start, int length)
157{
158 u16 tmp = 0;
159
160 while (length--)
161 tmp += *start++;
162
163 return tmp;
164}
165
166/* here we decode the incoming waveform file and populate metromem */
167#define EXP_WFORM_SIZE 47001
168static int load_waveform(u8 *mem, size_t size, u8 *metromem, int m, int t,
169 u8 *frame_count)
170{
171 int tta;
172 int wmta;
173 int trn = 0;
174 int i;
175 unsigned char v;
176 u8 cksum;
177 int cksum_idx;
178 int wfm_idx, owfm_idx;
179 int mem_idx = 0;
180 struct waveform_hdr *wfm_hdr;
181
182 if (size != EXP_WFORM_SIZE) {
183 printk(KERN_ERR "Error: unexpected size %d != %d\n", size,
184 EXP_WFORM_SIZE);
185 return -EINVAL;
186 }
187
188 wfm_hdr = (struct waveform_hdr *) mem;
189
190 if (wfm_hdr->fvsn != 1) {
191 printk(KERN_ERR "Error: bad fvsn %x\n", wfm_hdr->fvsn);
192 return -EINVAL;
193 }
194 if (wfm_hdr->luts != 0) {
195 printk(KERN_ERR "Error: bad luts %x\n", wfm_hdr->luts);
196 return -EINVAL;
197 }
198 cksum = calc_cksum(32, 47, mem);
199 if (cksum != wfm_hdr->wfm_cs) {
200 printk(KERN_ERR "Error: bad cksum %x != %x\n", cksum,
201 wfm_hdr->wfm_cs);
202 return -EINVAL;
203 }
204 wfm_hdr->mc += 1;
205 wfm_hdr->trc += 1;
206 for (i = 0; i < 5; i++) {
207 if (*(wfm_hdr->stuff2a + i) != 0) {
208 printk(KERN_ERR "Error: unexpected value in padding\n");
209 return -EINVAL;
210 }
211 }
212
213 /* calculating trn. trn is something used to index into
214 the waveform. presumably selecting the right one for the
215 desired temperature. it works out the offset of the first
216 v that exceeds the specified temperature */
217 if ((sizeof(*wfm_hdr) + wfm_hdr->trc) > size)
218 return -EINVAL;
219
220 for (i = sizeof(*wfm_hdr); i <= sizeof(*wfm_hdr) + wfm_hdr->trc; i++) {
221 if (mem[i] > t) {
222 trn = i - sizeof(*wfm_hdr) - 1;
223 break;
224 }
225 }
226
227 /* check temperature range table checksum */
228 cksum_idx = sizeof(*wfm_hdr) + wfm_hdr->trc + 1;
229 if (cksum_idx > size)
230 return -EINVAL;
231 cksum = calc_cksum(sizeof(*wfm_hdr), cksum_idx, mem);
232 if (cksum != mem[cksum_idx]) {
233 printk(KERN_ERR "Error: bad temperature range table cksum"
234 " %x != %x\n", cksum, mem[cksum_idx]);
235 return -EINVAL;
236 }
237
238 /* check waveform mode table address checksum */
239 wmta = le32_to_cpu(get_unaligned((__le32 *) wfm_hdr->wmta));
240 wmta &= 0x00FFFFFF;
241 cksum_idx = wmta + m*4 + 3;
242 if (cksum_idx > size)
243 return -EINVAL;
244 cksum = calc_cksum(cksum_idx - 3, cksum_idx, mem);
245 if (cksum != mem[cksum_idx]) {
246 printk(KERN_ERR "Error: bad mode table address cksum"
247 " %x != %x\n", cksum, mem[cksum_idx]);
248 return -EINVAL;
249 }
250
251 /* check waveform temperature table address checksum */
252 tta = le32_to_cpu(get_unaligned((int *) (mem + wmta + m*4)));
253 tta &= 0x00FFFFFF;
254 cksum_idx = tta + trn*4 + 3;
255 if (cksum_idx > size)
256 return -EINVAL;
257 cksum = calc_cksum(cksum_idx - 3, cksum_idx, mem);
258 if (cksum != mem[cksum_idx]) {
259 printk(KERN_ERR "Error: bad temperature table address cksum"
260 " %x != %x\n", cksum, mem[cksum_idx]);
261 return -EINVAL;
262 }
263
264 /* here we do the real work of putting the waveform into the
265 metromem buffer. this does runlength decoding of the waveform */
266 wfm_idx = le32_to_cpu(get_unaligned((__le32 *) (mem + tta + trn*4)));
267 wfm_idx &= 0x00FFFFFF;
268 owfm_idx = wfm_idx;
269 if (wfm_idx > size)
270 return -EINVAL;
271 while (wfm_idx < size) {
272 unsigned char rl;
273 v = mem[wfm_idx++];
274 if (v == wfm_hdr->swtb) {
275 while (((v = mem[wfm_idx++]) != wfm_hdr->swtb) &&
276 wfm_idx < size)
277 metromem[mem_idx++] = v;
278
279 continue;
280 }
281
282 if (v == wfm_hdr->endb)
283 break;
284
285 rl = mem[wfm_idx++];
286 for (i = 0; i <= rl; i++)
287 metromem[mem_idx++] = v;
288 }
289
290 cksum_idx = wfm_idx;
291 if (cksum_idx > size)
292 return -EINVAL;
293 cksum = calc_cksum(owfm_idx, cksum_idx, mem);
294 if (cksum != mem[cksum_idx]) {
295 printk(KERN_ERR "Error: bad waveform data cksum"
296 " %x != %x\n", cksum, mem[cksum_idx]);
297 return -EINVAL;
298 }
299 *frame_count = (mem_idx/64);
300
301 return 0;
302}
303
304/* register offsets for gpio control */
305#define LED_GPIO_PIN 51
306#define STDBY_GPIO_PIN 48
307#define RST_GPIO_PIN 49
308#define RDY_GPIO_PIN 32
309#define ERR_GPIO_PIN 17
310#define PCBPWR_GPIO_PIN 16
311
312#define AF_SEL_GPIO_N 0x3
313#define GAFR0_U_OFFSET(pin) ((pin - 16) * 2)
314#define GAFR1_L_OFFSET(pin) ((pin - 32) * 2)
315#define GAFR1_U_OFFSET(pin) ((pin - 48) * 2)
316#define GPDR1_OFFSET(pin) (pin - 32)
317#define GPCR1_OFFSET(pin) (pin - 32)
318#define GPSR1_OFFSET(pin) (pin - 32)
319#define GPCR0_OFFSET(pin) (pin)
320#define GPSR0_OFFSET(pin) (pin)
321
322static void metronome_set_gpio_output(int pin, int val)
323{
324 u8 index;
325
326 index = pin >> 4;
327
328 switch (index) {
329 case 1:
330 if (val)
331 GPSR0 |= (1 << GPSR0_OFFSET(pin));
332 else
333 GPCR0 |= (1 << GPCR0_OFFSET(pin));
334 break;
335 case 2:
336 break;
337 case 3:
338 if (val)
339 GPSR1 |= (1 << GPSR1_OFFSET(pin));
340 else
341 GPCR1 |= (1 << GPCR1_OFFSET(pin));
342 break;
343 default:
344 printk(KERN_ERR "unimplemented\n");
345 }
346}
347
348static void __devinit metronome_init_gpio_pin(int pin, int dir)
349{
350 u8 index;
351 /* dir 0 is output, 1 is input
352 - do 2 things here:
353 - set gpio alternate function to standard gpio
354 - set gpio direction to input or output */
355
356 index = pin >> 4;
357 switch (index) {
358 case 1:
359 GAFR0_U &= ~(AF_SEL_GPIO_N << GAFR0_U_OFFSET(pin));
360
361 if (dir)
362 GPDR0 &= ~(1 << pin);
363 else
364 GPDR0 |= (1 << pin);
365 break;
366 case 2:
367 GAFR1_L &= ~(AF_SEL_GPIO_N << GAFR1_L_OFFSET(pin));
368
369 if (dir)
370 GPDR1 &= ~(1 << GPDR1_OFFSET(pin));
371 else
372 GPDR1 |= (1 << GPDR1_OFFSET(pin));
373 break;
374 case 3:
375 GAFR1_U &= ~(AF_SEL_GPIO_N << GAFR1_U_OFFSET(pin));
376
377 if (dir)
378 GPDR1 &= ~(1 << GPDR1_OFFSET(pin));
379 else
380 GPDR1 |= (1 << GPDR1_OFFSET(pin));
381 break;
382 default:
383 printk(KERN_ERR "unimplemented\n");
384 }
385}
386
387static void __devinit metronome_init_gpio_regs(void)
388{
389 metronome_init_gpio_pin(LED_GPIO_PIN, 0);
390 metronome_set_gpio_output(LED_GPIO_PIN, 0);
391
392 metronome_init_gpio_pin(STDBY_GPIO_PIN, 0);
393 metronome_set_gpio_output(STDBY_GPIO_PIN, 0);
394
395 metronome_init_gpio_pin(RST_GPIO_PIN, 0);
396 metronome_set_gpio_output(RST_GPIO_PIN, 0);
397
398 metronome_init_gpio_pin(RDY_GPIO_PIN, 1);
399
400 metronome_init_gpio_pin(ERR_GPIO_PIN, 1);
401
402 metronome_init_gpio_pin(PCBPWR_GPIO_PIN, 0);
403 metronome_set_gpio_output(PCBPWR_GPIO_PIN, 0);
404}
405
406static void metronome_disable_lcd_controller(struct metronomefb_par *par)
407{
408 LCSR = 0xffffffff; /* Clear LCD Status Register */
409 LCCR0 |= LCCR0_DIS; /* Disable LCD Controller */
410
411 /* we reset and just wait for things to settle */
412 msleep(200);
413}
414
415static void metronome_enable_lcd_controller(struct metronomefb_par *par)
416{
417 LCSR = 0xffffffff;
418 FDADR0 = par->metromem_desc_dma;
419 LCCR0 |= LCCR0_ENB;
420}
421
422static void __devinit metronome_init_lcdc_regs(struct metronomefb_par *par)
423{
424 /* here we do:
425 - disable the lcd controller
426 - setup lcd control registers
427 - setup dma descriptor
428 - reenable lcd controller
429 */
430
431 /* disable the lcd controller */
432 metronome_disable_lcd_controller(par);
433
434 /* setup lcd control registers */
435 LCCR0 = LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM | LCCR0_PAS
436 | LCCR0_QDM | LCCR0_BM | LCCR0_OUM;
437
438 LCCR1 = (epd_frame_table[0].fw/2 - 1) /* pixels per line */
439 | (27 << 10) /* hsync pulse width - 1 */
440 | (33 << 16) /* eol pixel count */
441 | (33 << 24); /* bol pixel count */
442
443 LCCR2 = (epd_frame_table[0].fh - 1) /* lines per panel */
444 | (24 << 10) /* vsync pulse width - 1 */
445 | (2 << 16) /* eof pixel count */
446 | (0 << 24); /* bof pixel count */
447
448 LCCR3 = 2 /* pixel clock divisor */
449 | (24 << 8) /* AC Bias pin freq */
450 | LCCR3_16BPP /* BPP */
451 | LCCR3_PCP; /* PCP falling edge */
452
453 /* setup dma descriptor */
454 par->metromem_desc->mFDADR0 = par->metromem_desc_dma;
455 par->metromem_desc->mFSADR0 = par->metromem_dma;
456 par->metromem_desc->mFIDR0 = 0;
457 par->metromem_desc->mLDCMD0 = epd_frame_table[0].fw
458 * epd_frame_table[0].fh;
459 /* reenable lcd controller */
460 metronome_enable_lcd_controller(par);
461}
462
463static int metronome_display_cmd(struct metronomefb_par *par)
464{
465 int i;
466 u16 cs;
467 u16 opcode;
468 static u8 borderval;
469 u8 *ptr;
470
471 /* setup display command
472 we can't immediately set the opcode since the controller
473 will try parse the command before we've set it all up
474 so we just set cs here and set the opcode at the end */
475
476 ptr = par->metromem;
477
478 if (par->metromem_cmd->opcode == 0xCC40)
479 opcode = cs = 0xCC41;
480 else
481 opcode = cs = 0xCC40;
482
483 /* set the args ( 2 bytes ) for display */
484 i = 0;
485 par->metromem_cmd->args[i] = 1 << 3 /* border update */
486 | ((borderval++ % 4) & 0x0F) << 4
487 | (par->frame_count - 1) << 8;
488 cs += par->metromem_cmd->args[i++];
489
490 /* the rest are 0 */
491 memset((u8 *) (par->metromem_cmd->args + i), 0, (32-i)*2);
492
493 par->metromem_cmd->csum = cs;
494 par->metromem_cmd->opcode = opcode; /* display cmd */
495
496 i = wait_event_interruptible_timeout(par->waitq, (GPLR1 & 0x01), HZ);
497 return i;
498}
499
500static int __devinit metronome_powerup_cmd(struct metronomefb_par *par)
501{
502 int i;
503 u16 cs;
504
505 /* setup power up command */
506 par->metromem_cmd->opcode = 0x1234; /* pwr up pseudo cmd */
507 cs = par->metromem_cmd->opcode;
508
509 /* set pwr1,2,3 to 1024 */
510 for (i = 0; i < 3; i++) {
511 par->metromem_cmd->args[i] = 1024;
512 cs += par->metromem_cmd->args[i];
513 }
514
515 /* the rest are 0 */
516 memset((u8 *) (par->metromem_cmd->args + i), 0, (32-i)*2);
517
518 par->metromem_cmd->csum = cs;
519
520 msleep(1);
521 metronome_set_gpio_output(RST_GPIO_PIN, 1);
522
523 msleep(1);
524 metronome_set_gpio_output(STDBY_GPIO_PIN, 1);
525
526 i = wait_event_timeout(par->waitq, (GPLR1 & 0x01), HZ);
527 return i;
528}
529
530static int __devinit metronome_config_cmd(struct metronomefb_par *par)
531{
532 int i;
533 u16 cs;
534
535 /* setup config command
536 we can't immediately set the opcode since the controller
537 will try parse the command before we've set it all up
538 so we just set cs here and set the opcode at the end */
539
540 cs = 0xCC10;
541
542 /* set the 12 args ( 8 bytes ) for config. see spec for meanings */
543 i = 0;
544 par->metromem_cmd->args[i] = 15 /* sdlew */
545 | 2 << 8 /* sdosz */
546 | 0 << 11 /* sdor */
547 | 0 << 12 /* sdces */
548 | 0 << 15; /* sdcer */
549 cs += par->metromem_cmd->args[i++];
550
551 par->metromem_cmd->args[i] = 42 /* gdspl */
552 | 1 << 8 /* gdr1 */
553 | 1 << 9 /* sdshr */
554 | 0 << 15; /* gdspp */
555 cs += par->metromem_cmd->args[i++];
556
557 par->metromem_cmd->args[i] = 18 /* gdspw */
558 | 0 << 15; /* dispc */
559 cs += par->metromem_cmd->args[i++];
560
561 par->metromem_cmd->args[i] = 599 /* vdlc */
562 | 0 << 11 /* dsi */
563 | 0 << 12; /* dsic */
564 cs += par->metromem_cmd->args[i++];
565
566 /* the rest are 0 */
567 memset((u8 *) (par->metromem_cmd->args + i), 0, (32-i)*2);
568
569 par->metromem_cmd->csum = cs;
570 par->metromem_cmd->opcode = 0xCC10; /* config cmd */
571
572 i = wait_event_timeout(par->waitq, (GPLR1 & 0x01), HZ);
573 return i;
574}
575
576static int __devinit metronome_init_cmd(struct metronomefb_par *par)
577{
578 int i;
579 u16 cs;
580
581 /* setup init command
582 we can't immediately set the opcode since the controller
583 will try parse the command before we've set it all up
584 so we just set cs here and set the opcode at the end */
585
586 cs = 0xCC20;
587
588 /* set the args ( 2 bytes ) for init */
589 i = 0;
590 par->metromem_cmd->args[i] = 0;
591 cs += par->metromem_cmd->args[i++];
592
593 /* the rest are 0 */
594 memset((u8 *) (par->metromem_cmd->args + i), 0, (32-i)*2);
595
596 par->metromem_cmd->csum = cs;
597 par->metromem_cmd->opcode = 0xCC20; /* init cmd */
598
599 i = wait_event_timeout(par->waitq, (GPLR1 & 0x01), HZ);
600 return i;
601}
602
603static int __devinit metronome_init_regs(struct metronomefb_par *par)
604{
605 int res;
606
607 metronome_init_gpio_regs();
608 metronome_init_lcdc_regs(par);
609
610 res = metronome_powerup_cmd(par);
611 if (res)
612 return res;
613
614 res = metronome_config_cmd(par);
615 if (res)
616 return res;
617
618 res = metronome_init_cmd(par);
619 if (res)
620 return res;
621
622 return res;
623}
624
625static void metronomefb_dpy_update(struct metronomefb_par *par)
626{
627 u16 cksum;
628 unsigned char *buf = (unsigned char __force *)par->info->screen_base;
629
630 /* copy from vm to metromem */
631 memcpy(par->metromem_img, buf, DPY_W*DPY_H);
632
633 cksum = calc_img_cksum((u16 *) par->metromem_img,
634 (epd_frame_table[0].fw * DPY_H)/2);
635 *((u16 *) (par->metromem_img) +
636 (epd_frame_table[0].fw * DPY_H)/2) = cksum;
637 metronome_display_cmd(par);
638}
639
640static u16 metronomefb_dpy_update_page(struct metronomefb_par *par, int index)
641{
642 int i;
643 u16 csum = 0;
644 u16 *buf = (u16 __force *) (par->info->screen_base + index);
645 u16 *img = (u16 *) (par->metromem_img + index);
646
647 /* swizzle from vm to metromem and recalc cksum at the same time*/
648 for (i = 0; i < PAGE_SIZE/2; i++) {
649 *(img + i) = (buf[i] << 5) & 0xE0E0;
650 csum += *(img + i);
651 }
652 return csum;
653}
654
655/* this is called back from the deferred io workqueue */
656static void metronomefb_dpy_deferred_io(struct fb_info *info,
657 struct list_head *pagelist)
658{
659 u16 cksum;
660 struct page *cur;
661 struct fb_deferred_io *fbdefio = info->fbdefio;
662 struct metronomefb_par *par = info->par;
663
664 /* walk the written page list and swizzle the data */
665 list_for_each_entry(cur, &fbdefio->pagelist, lru) {
666 cksum = metronomefb_dpy_update_page(par,
667 (cur->index << PAGE_SHIFT));
668 par->metromem_img_csum -= par->csum_table[cur->index];
669 par->csum_table[cur->index] = cksum;
670 par->metromem_img_csum += cksum;
671 }
672
673 metronome_display_cmd(par);
674}
675
676static void metronomefb_fillrect(struct fb_info *info,
677 const struct fb_fillrect *rect)
678{
679 struct metronomefb_par *par = info->par;
680
681 cfb_fillrect(info, rect);
682 metronomefb_dpy_update(par);
683}
684
685static void metronomefb_copyarea(struct fb_info *info,
686 const struct fb_copyarea *area)
687{
688 struct metronomefb_par *par = info->par;
689
690 cfb_copyarea(info, area);
691 metronomefb_dpy_update(par);
692}
693
694static void metronomefb_imageblit(struct fb_info *info,
695 const struct fb_image *image)
696{
697 struct metronomefb_par *par = info->par;
698
699 cfb_imageblit(info, image);
700 metronomefb_dpy_update(par);
701}
702
703/*
704 * this is the slow path from userspace. they can seek and write to
705 * the fb. it is based on fb_sys_write
706 */
707static ssize_t metronomefb_write(struct fb_info *info, const char __user *buf,
708 size_t count, loff_t *ppos)
709{
710 struct metronomefb_par *par = info->par;
711 unsigned long p = *ppos;
712 void *dst;
713 int err = 0;
714 unsigned long total_size;
715
716 if (info->state != FBINFO_STATE_RUNNING)
717 return -EPERM;
718
719 total_size = info->fix.smem_len;
720
721 if (p > total_size)
722 return -EFBIG;
723
724 if (count > total_size) {
725 err = -EFBIG;
726 count = total_size;
727 }
728
729 if (count + p > total_size) {
730 if (!err)
731 err = -ENOSPC;
732
733 count = total_size - p;
734 }
735
736 dst = (void __force *) (info->screen_base + p);
737
738 if (copy_from_user(dst, buf, count))
739 err = -EFAULT;
740
741 if (!err)
742 *ppos += count;
743
744 metronomefb_dpy_update(par);
745
746 return (err) ? err : count;
747}
748
749static struct fb_ops metronomefb_ops = {
750 .owner = THIS_MODULE,
751 .fb_write = metronomefb_write,
752 .fb_fillrect = metronomefb_fillrect,
753 .fb_copyarea = metronomefb_copyarea,
754 .fb_imageblit = metronomefb_imageblit,
755};
756
757static struct fb_deferred_io metronomefb_defio = {
758 .delay = HZ,
759 .deferred_io = metronomefb_dpy_deferred_io,
760};
761
762static irqreturn_t metronome_handle_irq(int irq, void *dev_id)
763{
764 struct fb_info *info = dev_id;
765 struct metronomefb_par *par = info->par;
766
767 wake_up_interruptible(&par->waitq);
768 return IRQ_HANDLED;
769}
770
771static int __devinit metronomefb_probe(struct platform_device *dev)
772{
773 struct fb_info *info;
774 int retval = -ENOMEM;
775 int videomemorysize;
776 unsigned char *videomemory;
777 struct metronomefb_par *par;
778 const struct firmware *fw_entry;
779 int cmd_size, wfm_size, img_size, padding_size, totalsize;
780 int i;
781
782 /* we have two blocks of memory.
783 info->screen_base which is vm, and is the fb used by apps.
784 par->metromem which is physically contiguous memory and
785 contains the display controller commands, waveform,
786 processed image data and padding. this is the data pulled
787 by the pxa255's LCD controller and pushed to Metronome */
788
789 videomemorysize = (DPY_W*DPY_H);
790 videomemory = vmalloc(videomemorysize);
791 if (!videomemory)
792 return retval;
793
794 memset(videomemory, 0, videomemorysize);
795
796 info = framebuffer_alloc(sizeof(struct metronomefb_par), &dev->dev);
797 if (!info)
798 goto err_vfree;
799
800 info->screen_base = (char __iomem *) videomemory;
801 info->fbops = &metronomefb_ops;
802
803 info->var = metronomefb_var;
804 info->fix = metronomefb_fix;
805 info->fix.smem_len = videomemorysize;
806 par = info->par;
807 par->info = info;
808 init_waitqueue_head(&par->waitq);
809
810 /* this table caches per page csum values. */
811 par->csum_table = vmalloc(videomemorysize/PAGE_SIZE);
812 if (!par->csum_table)
813 goto err_csum_table;
814
815 /* the metromem buffer is divided as follows:
816 command | CRC | padding
817 16kb waveform data | CRC | padding
818 image data | CRC
819 and an extra 256 bytes for dma descriptors
820 eg: IW=832 IH=622 WS=128
821 */
822
823 cmd_size = 1 * epd_frame_table[0].fw;
824 wfm_size = ((16*1024 + 2 + epd_frame_table[0].fw - 1)
825 / epd_frame_table[0].fw) * epd_frame_table[0].fw;
826 img_size = epd_frame_table[0].fh * epd_frame_table[0].fw;
827 padding_size = 4 * epd_frame_table[0].fw;
828 totalsize = cmd_size + wfm_size + img_size + padding_size;
829 par->metromemsize = PAGE_ALIGN(totalsize + 256);
830 DPRINTK("desired memory size = %d\n", par->metromemsize);
831 dev->dev.coherent_dma_mask = 0xffffffffull;
832 par->metromem = dma_alloc_writecombine(&dev->dev, par->metromemsize,
833 &par->metromem_dma, GFP_KERNEL);
834 if (!par->metromem) {
835 printk(KERN_ERR
836 "metronomefb: unable to allocate dma buffer\n");
837 goto err_vfree;
838 }
839
840 info->fix.smem_start = par->metromem_dma;
841 par->metromem_cmd = (struct metromem_cmd *) par->metromem;
842 par->metromem_wfm = par->metromem + cmd_size;
843 par->metromem_img = par->metromem + cmd_size + wfm_size;
844 par->metromem_img_csum = (u16 *) (par->metromem_img +
845 (epd_frame_table[0].fw * DPY_H));
846 DPRINTK("img offset=0x%x\n", cmd_size + wfm_size);
847 par->metromem_desc = (struct metromem_desc *) (par->metromem + cmd_size
848 + wfm_size + img_size + padding_size);
849 par->metromem_desc_dma = par->metromem_dma + cmd_size + wfm_size
850 + img_size + padding_size;
851
852 /* load the waveform in. assume mode 3, temp 31 for now */
853 /* a) request the waveform file from userspace
854 b) process waveform and decode into metromem */
855
856 retval = request_firmware(&fw_entry, "waveform.wbf", &dev->dev);
857 if (retval < 0) {
858 printk(KERN_ERR "metronomefb: couldn't get waveform\n");
859 goto err_dma_free;
860 }
861
862 retval = load_waveform((u8 *) fw_entry->data, fw_entry->size,
863 par->metromem_wfm, 3, 31, &par->frame_count);
864 if (retval < 0) {
865 printk(KERN_ERR "metronomefb: couldn't process waveform\n");
866 goto err_ld_wfm;
867 }
868 release_firmware(fw_entry);
869
870 retval = request_irq(IRQ_GPIO(RDY_GPIO_PIN), metronome_handle_irq,
871 IRQF_DISABLED, "Metronome", info);
872 if (retval) {
873 dev_err(&dev->dev, "request_irq failed: %d\n", retval);
874 goto err_ld_wfm;
875 }
876 set_irq_type(IRQ_GPIO(RDY_GPIO_PIN), IRQT_FALLING);
877
878 retval = metronome_init_regs(par);
879 if (retval < 0)
880 goto err_free_irq;
881
882 info->flags = FBINFO_FLAG_DEFAULT;
883
884 info->fbdefio = &metronomefb_defio;
885 fb_deferred_io_init(info);
886
887 retval = fb_alloc_cmap(&info->cmap, 8, 0);
888 if (retval < 0) {
889 printk(KERN_ERR "Failed to allocate colormap\n");
890 goto err_fb_rel;
891 }
892
893 /* set cmap */
894 for (i = 0; i < 8; i++)
895 info->cmap.red[i] = (((2*i)+1)*(0xFFFF))/16;
896 memcpy(info->cmap.green, info->cmap.red, sizeof(u16)*8);
897 memcpy(info->cmap.blue, info->cmap.red, sizeof(u16)*8);
898
899 retval = register_framebuffer(info);
900 if (retval < 0)
901 goto err_cmap;
902
903 platform_set_drvdata(dev, info);
904
905 printk(KERN_INFO
906 "fb%d: Metronome frame buffer device, using %dK of video"
907 " memory\n", info->node, videomemorysize >> 10);
908
909 return 0;
910
911err_cmap:
912 fb_dealloc_cmap(&info->cmap);
913err_fb_rel:
914 framebuffer_release(info);
915err_free_irq:
916 free_irq(IRQ_GPIO(RDY_GPIO_PIN), info);
917err_ld_wfm:
918 release_firmware(fw_entry);
919err_dma_free:
920 dma_free_writecombine(&dev->dev, par->metromemsize, par->metromem,
921 par->metromem_dma);
922err_csum_table:
923 vfree(par->csum_table);
924err_vfree:
925 vfree(videomemory);
926 return retval;
927}
928
929static int __devexit metronomefb_remove(struct platform_device *dev)
930{
931 struct fb_info *info = platform_get_drvdata(dev);
932
933 if (info) {
934 struct metronomefb_par *par = info->par;
935 fb_deferred_io_cleanup(info);
936 dma_free_writecombine(&dev->dev, par->metromemsize,
937 par->metromem, par->metromem_dma);
938 fb_dealloc_cmap(&info->cmap);
939 vfree(par->csum_table);
940 unregister_framebuffer(info);
941 vfree((void __force *)info->screen_base);
942 free_irq(IRQ_GPIO(RDY_GPIO_PIN), info);
943 framebuffer_release(info);
944 }
945 return 0;
946}
947
948static struct platform_driver metronomefb_driver = {
949 .probe = metronomefb_probe,
950 .remove = metronomefb_remove,
951 .driver = {
952 .name = "metronomefb",
953 },
954};
955
956static struct platform_device *metronomefb_device;
957
958static int __init metronomefb_init(void)
959{
960 int ret;
961
962 if (!metronomefb_enable) {
963 printk(KERN_ERR
964 "Use metronomefb_enable to enable the device\n");
965 return -ENXIO;
966 }
967
968 ret = platform_driver_register(&metronomefb_driver);
969 if (!ret) {
970 metronomefb_device = platform_device_alloc("metronomefb", 0);
971 if (metronomefb_device)
972 ret = platform_device_add(metronomefb_device);
973 else
974 ret = -ENOMEM;
975
976 if (ret) {
977 platform_device_put(metronomefb_device);
978 platform_driver_unregister(&metronomefb_driver);
979 }
980 }
981 return ret;
982
983}
984
985static void __exit metronomefb_exit(void)
986{
987 platform_device_unregister(metronomefb_device);
988 platform_driver_unregister(&metronomefb_driver);
989}
990
991module_param(metronomefb_enable, uint, 0);
992MODULE_PARM_DESC(metronomefb_enable, "Enable communication with Metronome");
993
994module_init(metronomefb_init);
995module_exit(metronomefb_exit);
996
997MODULE_DESCRIPTION("fbdev driver for Metronome controller");
998MODULE_AUTHOR("Jaya Kumar");
999MODULE_LICENSE("GPL");