aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/arcfb.c
diff options
context:
space:
mode:
authorJaya Kumar <jayalk@intworks.biz>2005-06-21 20:17:04 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-06-21 22:07:41 -0400
commit1154ea7dcd8eed758fb5ec47393a79d5a1f0bc43 (patch)
tree5c5c67e549c60b030555f97fb66c1501f86897d2 /drivers/video/arcfb.c
parent4ff45f515144d232c83bf55c53f54deecb750296 (diff)
[PATCH] Framebuffer driver for Arc LCD board
Add support for the Arc monochrome LCD board. The board uses KS108 controllers to drive individual 64x64 LCD matrices. The board can be paneled in a variety of setups such as 2x1=128x64, 4x4=256x256 and so on. The board/host interface is through GPIO. Signed-off-by: Jaya Kumar <jayalk@intworks.biz> Cc: "Antonino A. Daplas" <adaplas@pol.net> Cc: <linux-fbdev-devel@lists.sourceforge.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/video/arcfb.c')
-rw-r--r--drivers/video/arcfb.c684
1 files changed, 684 insertions, 0 deletions
diff --git a/drivers/video/arcfb.c b/drivers/video/arcfb.c
new file mode 100644
index 000000000000..d28457e0c063
--- /dev/null
+++ b/drivers/video/arcfb.c
@@ -0,0 +1,684 @@
1/*
2 * linux/drivers/video/arcfb.c -- FB driver for Arc monochrome LCD board
3 *
4 * Copyright (C) 2005, Jaya Kumar <jayalk@intworks.biz>
5 * http://www.intworks.biz/arclcd
6 *
7 * This file is subject to the terms and conditions of the GNU General Public
8 * License. See the file COPYING in the main directory of this archive for
9 * more details.
10 *
11 * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven.
12 *
13 * This driver was written to be used with the Arc LCD board. Arc uses a
14 * set of KS108 chips that control individual 64x64 LCD matrices. The board
15 * can be paneled in a variety of setups such as 2x1=128x64, 4x4=256x256 and
16 * so on. The interface between the board and the host is TTL based GPIO. The
17 * GPIO requirements are 8 writable data lines and 4+n lines for control. On a
18 * GPIO-less system, the board can be tested by connecting the respective sigs
19 * up to a parallel port connector. The driver requires the IO addresses for
20 * data and control GPIO at load time. It is unable to probe for the
21 * existence of the LCD so it must be told at load time whether it should
22 * be enabled or not.
23 *
24 * Todo:
25 * - testing with 4x4
26 * - testing with interrupt hw
27 *
28 * General notes:
29 * - User must set tuhold. It's in microseconds. According to the 108 spec,
30 * the hold time is supposed to be at least 1 microsecond.
31 * - User must set num_cols=x num_rows=y, eg: x=2 means 128
32 * - User must set arcfb_enable=1 to enable it
33 * - User must set dio_addr=0xIOADDR cio_addr=0xIOADDR
34 *
35 */
36
37#include <linux/module.h>
38#include <linux/kernel.h>
39#include <linux/errno.h>
40#include <linux/string.h>
41#include <linux/mm.h>
42#include <linux/tty.h>
43#include <linux/slab.h>
44#include <linux/vmalloc.h>
45#include <linux/delay.h>
46#include <linux/interrupt.h>
47#include <linux/fb.h>
48#include <linux/init.h>
49#include <linux/arcfb.h>
50
51#include <asm/uaccess.h>
52
53#define floor8(a) (a&(~0x07))
54#define floorXres(a,xres) (a&(~(xres - 1)))
55#define iceil8(a) (((int)((a+7)/8))*8)
56#define ceil64(a) (a|0x3F)
57#define ceilXres(a,xres) (a|(xres - 1))
58
59/* ks108 chipset specific defines and code */
60
61#define KS_SET_DPY_START_LINE 0xC0
62#define KS_SET_PAGE_NUM 0xB8
63#define KS_SET_X 0x40
64#define KS_CEHI 0x01
65#define KS_CELO 0x00
66#define KS_SEL_CMD 0x08
67#define KS_SEL_DATA 0x00
68#define KS_DPY_ON 0x3F
69#define KS_DPY_OFF 0x3E
70#define KS_INTACK 0x40
71#define KS_CLRINT 0x02
72
73struct arcfb_par {
74 unsigned long dio_addr;
75 unsigned long cio_addr;
76 unsigned long c2io_addr;
77 atomic_t ref_count;
78 unsigned char cslut[9];
79 struct fb_info *info;
80 unsigned int irq;
81 spinlock_t lock;
82};
83
84static struct fb_fix_screeninfo arcfb_fix __initdata = {
85 .id = "arcfb",
86 .type = FB_TYPE_PACKED_PIXELS,
87 .visual = FB_VISUAL_MONO01,
88 .xpanstep = 0,
89 .ypanstep = 1,
90 .ywrapstep = 0,
91 .accel = FB_ACCEL_NONE,
92};
93
94static struct fb_var_screeninfo arcfb_var __initdata = {
95 .xres = 128,
96 .yres = 64,
97 .xres_virtual = 128,
98 .yres_virtual = 64,
99 .bits_per_pixel = 1,
100 .nonstd = 1,
101};
102
103static unsigned long num_cols;
104static unsigned long num_rows;
105static unsigned long dio_addr;
106static unsigned long cio_addr;
107static unsigned long c2io_addr;
108static unsigned long splashval;
109static unsigned long tuhold;
110static unsigned int nosplash;
111static unsigned int arcfb_enable;
112static unsigned int irq;
113
114static DECLARE_WAIT_QUEUE_HEAD(arcfb_waitq);
115
116static void ks108_writeb_ctl(struct arcfb_par *par,
117 unsigned int chipindex, unsigned char value)
118{
119 unsigned char chipselval = par->cslut[chipindex];
120
121 outb(chipselval|KS_CEHI|KS_SEL_CMD, par->cio_addr);
122 outb(value, par->dio_addr);
123 udelay(tuhold);
124 outb(chipselval|KS_CELO|KS_SEL_CMD, par->cio_addr);
125}
126
127static void ks108_writeb_mainctl(struct arcfb_par *par, unsigned char value)
128{
129
130 outb(value, par->cio_addr);
131 udelay(tuhold);
132}
133
134static unsigned char ks108_readb_ctl2(struct arcfb_par *par)
135{
136 return inb(par->c2io_addr);
137}
138
139static void ks108_writeb_data(struct arcfb_par *par,
140 unsigned int chipindex, unsigned char value)
141{
142 unsigned char chipselval = par->cslut[chipindex];
143
144 outb(chipselval|KS_CEHI|KS_SEL_DATA, par->cio_addr);
145 outb(value, par->dio_addr);
146 udelay(tuhold);
147 outb(chipselval|KS_CELO|KS_SEL_DATA, par->cio_addr);
148}
149
150static void ks108_set_start_line(struct arcfb_par *par,
151 unsigned int chipindex, unsigned char y)
152{
153 ks108_writeb_ctl(par, chipindex, KS_SET_DPY_START_LINE|y);
154}
155
156static void ks108_set_yaddr(struct arcfb_par *par,
157 unsigned int chipindex, unsigned char y)
158{
159 ks108_writeb_ctl(par, chipindex, KS_SET_PAGE_NUM|y);
160}
161
162static void ks108_set_xaddr(struct arcfb_par *par,
163 unsigned int chipindex, unsigned char x)
164{
165 ks108_writeb_ctl(par, chipindex, KS_SET_X|x);
166}
167
168static void ks108_clear_lcd(struct arcfb_par *par, unsigned int chipindex)
169{
170 int i,j;
171
172 for (i = 0; i <= 8; i++) {
173 ks108_set_yaddr(par, chipindex, i);
174 ks108_set_xaddr(par, chipindex, 0);
175 for (j = 0; j < 64; j++) {
176 ks108_writeb_data(par, chipindex,
177 (unsigned char) splashval);
178 }
179 }
180}
181
182/* main arcfb functions */
183
184static int arcfb_open(struct fb_info *info, int user)
185{
186 struct arcfb_par *par = info->par;
187
188 atomic_inc(&par->ref_count);
189 return 0;
190}
191
192static int arcfb_release(struct fb_info *info, int user)
193{
194 struct arcfb_par *par = info->par;
195 int count = atomic_read(&par->ref_count);
196
197 if (!count)
198 return -EINVAL;
199 atomic_dec(&par->ref_count);
200 return 0;
201}
202
203static int arcfb_pan_display(struct fb_var_screeninfo *var,
204 struct fb_info *info)
205{
206 int i;
207 struct arcfb_par *par = info->par;
208
209 if ((var->vmode & FB_VMODE_YWRAP) && (var->yoffset < 64)
210 && (info->var.yres <= 64)) {
211 for (i = 0; i < num_cols; i++) {
212 ks108_set_start_line(par, i, var->yoffset);
213 }
214 info->var.yoffset = var->yoffset;
215 return 0;
216 }
217
218 return -EINVAL;
219}
220
221static irqreturn_t arcfb_interrupt(int vec, void *dev_instance,
222 struct pt_regs *regs)
223{
224 struct fb_info *info = dev_instance;
225 unsigned char ctl2status;
226 struct arcfb_par *par = info->par;
227
228 ctl2status = ks108_readb_ctl2(par);
229
230 if (!(ctl2status & KS_INTACK)) /* not arc generated interrupt */
231 return IRQ_NONE;
232
233 ks108_writeb_mainctl(par, KS_CLRINT);
234
235 spin_lock(&par->lock);
236 if (waitqueue_active(&arcfb_waitq)) {
237 wake_up(&arcfb_waitq);
238 }
239 spin_unlock(&par->lock);
240
241 return IRQ_HANDLED;
242}
243
244/*
245 * here we handle a specific page on the lcd. the complexity comes from
246 * the fact that the fb is laidout in 8xX vertical columns. we extract
247 * each write of 8 vertical pixels. then we shift out as we move along
248 * X. That's what rightshift does. bitmask selects the desired input bit.
249 */
250static void arcfb_lcd_update_page(struct arcfb_par *par, unsigned int upper,
251 unsigned int left, unsigned int right, unsigned int distance)
252{
253 unsigned char *src;
254 unsigned int xindex, yindex, chipindex, linesize;
255 int i, count;
256 unsigned char val;
257 unsigned char bitmask, rightshift;
258
259 xindex = left >> 6;
260 yindex = upper >> 6;
261 chipindex = (xindex + (yindex*num_cols));
262
263 ks108_set_yaddr(par, chipindex, upper/8);
264
265 linesize = par->info->var.xres/8;
266 src = par->info->screen_base + (left/8) + (upper * linesize);
267 ks108_set_xaddr(par, chipindex, left);
268
269 bitmask=1;
270 rightshift=0;
271 while (left <= right) {
272 val = 0;
273 for (i = 0; i < 8; i++) {
274 if ( i > rightshift) {
275 val |= (*(src + (i*linesize)) & bitmask)
276 << (i - rightshift);
277 } else {
278 val |= (*(src + (i*linesize)) & bitmask)
279 >> (rightshift - i);
280 }
281 }
282 ks108_writeb_data(par, chipindex, val);
283 left++;
284 count++;
285 if (bitmask == 0x80) {
286 bitmask = 1;
287 src++;
288 rightshift=0;
289 } else {
290 bitmask <<= 1;
291 rightshift++;
292 }
293 }
294}
295
296/*
297 * here we handle the entire vertical page of the update. we write across
298 * lcd chips. update_page uses the upper/left values to decide which
299 * chip to select for the right. upper is needed for setting the page
300 * desired for the write.
301 */
302static void arcfb_lcd_update_vert(struct arcfb_par *par, unsigned int top,
303 unsigned int bottom, unsigned int left, unsigned int right)
304{
305 unsigned int distance, upper, lower;
306
307 distance = (bottom - top) + 1;
308 upper = top;
309 lower = top + 7;
310
311 while (distance > 0) {
312 distance -= 8;
313 arcfb_lcd_update_page(par, upper, left, right, 8);
314 upper = lower + 1;
315 lower = upper + 7;
316 }
317}
318
319/*
320 * here we handle horizontal blocks for the update. update_vert will
321 * handle spaning multiple pages. we break out each horizontal
322 * block in to individual blocks no taller than 64 pixels.
323 */
324static void arcfb_lcd_update_horiz(struct arcfb_par *par, unsigned int left,
325 unsigned int right, unsigned int top, unsigned int h)
326{
327 unsigned int distance, upper, lower;
328
329 distance = h;
330 upper = floor8(top);
331 lower = min(upper + distance - 1, ceil64(upper));
332
333 while (distance > 0) {
334 distance -= ((lower - upper) + 1 );
335 arcfb_lcd_update_vert(par, upper, lower, left, right);
336 upper = lower + 1;
337 lower = min(upper + distance - 1, ceil64(upper));
338 }
339}
340
341/*
342 * here we start the process of spliting out the fb update into
343 * individual blocks of pixels. we end up spliting into 64x64 blocks
344 * and finally down to 64x8 pages.
345 */
346static void arcfb_lcd_update(struct arcfb_par *par, unsigned int dx,
347 unsigned int dy, unsigned int w, unsigned int h)
348{
349 unsigned int left, right, distance, y;
350
351 /* align the request first */
352 y = floor8(dy);
353 h += dy - y;
354 h = iceil8(h);
355
356 distance = w;
357 left = dx;
358 right = min(left + w - 1, ceil64(left));
359
360 while (distance > 0) {
361 arcfb_lcd_update_horiz(par, left, right, y, h);
362 distance -= ((right - left) + 1);
363 left = right + 1;
364 right = min(left + distance - 1, ceil64(left));
365 }
366}
367
368void arcfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
369{
370 struct arcfb_par *par = info->par;
371
372 cfb_fillrect(info, rect);
373
374 /* update the physical lcd */
375 arcfb_lcd_update(par, rect->dx, rect->dy, rect->width, rect->height);
376}
377
378void arcfb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
379{
380 struct arcfb_par *par = info->par;
381
382 cfb_copyarea(info, area);
383
384 /* update the physical lcd */
385 arcfb_lcd_update(par, area->dx, area->dy, area->width, area->height);
386}
387
388void arcfb_imageblit(struct fb_info *info, const struct fb_image *image)
389{
390 struct arcfb_par *par = info->par;
391
392 cfb_imageblit(info, image);
393
394 /* update the physical lcd */
395 arcfb_lcd_update(par, image->dx, image->dy, image->width,
396 image->height);
397}
398
399static int arcfb_ioctl(struct inode *inode, struct file *file,
400 unsigned int cmd, unsigned long arg,
401 struct fb_info *info)
402{
403 void __user *argp = (void __user *)arg;
404 struct arcfb_par *par = info->par;
405 unsigned long flags;
406
407 switch (cmd) {
408 case FBIO_WAITEVENT:
409 {
410 DEFINE_WAIT(wait);
411 /* illegal to wait on arc if no irq will occur */
412 if (!par->irq)
413 return -EINVAL;
414
415 /* wait until the Arc has generated an interrupt
416 * which will wake us up */
417 spin_lock_irqsave(&par->lock, flags);
418 prepare_to_wait(&arcfb_waitq, &wait,
419 TASK_INTERRUPTIBLE);
420 spin_unlock_irqrestore(&par->lock, flags);
421 schedule();
422 finish_wait(&arcfb_waitq, &wait);
423 }
424 case FBIO_GETCONTROL2:
425 {
426 unsigned char ctl2;
427
428 ctl2 = ks108_readb_ctl2(info->par);
429 if (copy_to_user(argp, &ctl2, sizeof(ctl2)))
430 return -EFAULT;
431 return 0;
432 }
433 default:
434 return -EINVAL;
435 }
436}
437
438/*
439 * this is the access path from userspace. they can seek and write to
440 * the fb. it's inefficient for them to do anything less than 64*8
441 * writes since we update the lcd in each write() anyway.
442 */
443static ssize_t arcfb_write(struct file *file, const char *buf, size_t count,
444 loff_t *ppos)
445{
446 /* modded from epson 1355 */
447
448 struct inode *inode;
449 int fbidx;
450 struct fb_info *info;
451 unsigned long p;
452 int err=-EINVAL;
453 unsigned int fbmemlength,x,y,w,h, bitppos, startpos, endpos, bitcount;
454 struct arcfb_par *par;
455 unsigned int xres;
456
457 p = *ppos;
458 inode = file->f_dentry->d_inode;
459 fbidx = iminor(inode);
460 info = registered_fb[fbidx];
461 par = info->par;
462
463 if (!info || !info->screen_base)
464 return -ENODEV;
465
466 xres = info->var.xres;
467 fbmemlength = (xres * info->var.yres)/8;
468
469 if (p > fbmemlength)
470 return -ENOSPC;
471
472 err = 0;
473 if ((count + p) > fbmemlength) {
474 count = fbmemlength - p;
475 err = -ENOSPC;
476 }
477
478 if (count) {
479 char *base_addr;
480
481 base_addr = info->screen_base;
482 count -= copy_from_user(base_addr + p, buf, count);
483 *ppos += count;
484 err = -EFAULT;
485 }
486
487
488 bitppos = p*8;
489 startpos = floorXres(bitppos, xres);
490 endpos = ceilXres((bitppos + (count*8)), xres);
491 bitcount = endpos - startpos;
492
493 x = startpos % xres;
494 y = startpos / xres;
495 w = xres;
496 h = bitcount / xres;
497 arcfb_lcd_update(par, x, y, w, h);
498
499 if (count)
500 return count;
501 return err;
502}
503
504static void arcfb_platform_release(struct device *device)
505{
506}
507
508static struct fb_ops arcfb_ops = {
509 .owner = THIS_MODULE,
510 .fb_open = arcfb_open,
511 .fb_write = arcfb_write,
512 .fb_release = arcfb_release,
513 .fb_pan_display = arcfb_pan_display,
514 .fb_fillrect = arcfb_fillrect,
515 .fb_copyarea = arcfb_copyarea,
516 .fb_imageblit = arcfb_imageblit,
517 .fb_cursor = soft_cursor,
518 .fb_ioctl = arcfb_ioctl,
519};
520
521static int __init arcfb_probe(struct device *device)
522{
523 struct platform_device *dev = to_platform_device(device);
524 struct fb_info *info;
525 int retval = -ENOMEM;
526 int videomemorysize;
527 unsigned char *videomemory;
528 struct arcfb_par *par;
529 int i;
530
531 videomemorysize = (((64*64)*num_cols)*num_rows)/8;
532
533 /* We need a flat backing store for the Arc's
534 less-flat actual paged framebuffer */
535 if (!(videomemory = vmalloc(videomemorysize)))
536 return retval;
537
538 memset(videomemory, 0, videomemorysize);
539
540 info = framebuffer_alloc(sizeof(struct arcfb_par), &dev->dev);
541 if (!info)
542 goto err;
543
544 info->screen_base = (char __iomem *)videomemory;
545 info->fbops = &arcfb_ops;
546
547 info->var = arcfb_var;
548 info->fix = arcfb_fix;
549 par = info->par;
550 par->info = info;
551
552 if (!dio_addr || !cio_addr || !c2io_addr) {
553 printk(KERN_WARNING "no IO addresses supplied\n");
554 goto err1;
555 }
556 par->dio_addr = dio_addr;
557 par->cio_addr = cio_addr;
558 par->c2io_addr = c2io_addr;
559 par->cslut[0] = 0x00;
560 par->cslut[1] = 0x06;
561 info->flags = FBINFO_FLAG_DEFAULT;
562 spin_lock_init(&par->lock);
563 retval = register_framebuffer(info);
564 if (retval < 0)
565 goto err1;
566 dev_set_drvdata(&dev->dev, info);
567 if (irq) {
568 par->irq = irq;
569 if (request_irq(par->irq, &arcfb_interrupt, SA_SHIRQ,
570 "arcfb", info)) {
571 printk(KERN_INFO
572 "arcfb: Failed req IRQ %d\n", par->irq);
573 goto err1;
574 }
575 }
576 printk(KERN_INFO
577 "fb%d: Arc frame buffer device, using %dK of video memory\n",
578 info->node, videomemorysize >> 10);
579
580 /* this inits the lcd but doesn't clear dirty pixels */
581 for (i = 0; i < num_cols * num_rows; i++) {
582 ks108_writeb_ctl(par, i, KS_DPY_OFF);
583 ks108_set_start_line(par, i, 0);
584 ks108_set_yaddr(par, i, 0);
585 ks108_set_xaddr(par, i, 0);
586 ks108_writeb_ctl(par, i, KS_DPY_ON);
587 }
588
589 /* if we were told to splash the screen, we just clear it */
590 if (!nosplash) {
591 for (i = 0; i < num_cols * num_rows; i++) {
592 printk(KERN_INFO "fb%d: splashing lcd %d\n",
593 info->node, i);
594 ks108_set_start_line(par, i, 0);
595 ks108_clear_lcd(par, i);
596 }
597 }
598
599 return 0;
600err1:
601 framebuffer_release(info);
602err:
603 vfree(videomemory);
604 return retval;
605}
606
607static int arcfb_remove(struct device *device)
608{
609 struct fb_info *info = dev_get_drvdata(device);
610
611 if (info) {
612 unregister_framebuffer(info);
613 vfree(info->screen_base);
614 framebuffer_release(info);
615 }
616 return 0;
617}
618
619static struct device_driver arcfb_driver = {
620 .name = "arcfb",
621 .bus = &platform_bus_type,
622 .probe = arcfb_probe,
623 .remove = arcfb_remove,
624};
625
626static struct platform_device arcfb_device = {
627 .name = "arcfb",
628 .id = 0,
629 .dev = {
630 .release = arcfb_platform_release,
631 }
632};
633
634static int __init arcfb_init(void)
635{
636 int ret;
637
638 if (!arcfb_enable)
639 return -ENXIO;
640
641 ret = driver_register(&arcfb_driver);
642 if (!ret) {
643 ret = platform_device_register(&arcfb_device);
644 if (ret)
645 driver_unregister(&arcfb_driver);
646 }
647 return ret;
648
649}
650
651static void __exit arcfb_exit(void)
652{
653 platform_device_unregister(&arcfb_device);
654 driver_unregister(&arcfb_driver);
655}
656
657module_param(num_cols, ulong, 0);
658MODULE_PARM_DESC(num_cols, "Num horiz panels, eg: 2 = 128 bit wide");
659module_param(num_rows, ulong, 0);
660MODULE_PARM_DESC(num_rows, "Num vert panels, eg: 1 = 64 bit high");
661module_param(nosplash, uint, 0);
662MODULE_PARM_DESC(nosplash, "Disable doing the splash screen");
663module_param(arcfb_enable, uint, 0);
664MODULE_PARM_DESC(arcfb_enable, "Enable communication with Arc board");
665module_param(dio_addr, ulong, 0);
666MODULE_PARM_DESC(dio_addr, "IO address for data, eg: 0x480");
667module_param(cio_addr, ulong, 0);
668MODULE_PARM_DESC(cio_addr, "IO address for control, eg: 0x400");
669module_param(c2io_addr, ulong, 0);
670MODULE_PARM_DESC(c2io_addr, "IO address for secondary control, eg: 0x408");
671module_param(splashval, ulong, 0);
672MODULE_PARM_DESC(splashval, "Splash pattern: 0xFF is black, 0x00 is green");
673module_param(tuhold, ulong, 0);
674MODULE_PARM_DESC(tuhold, "Time to hold between strobing data to Arc board");
675module_param(irq, uint, 0);
676MODULE_PARM_DESC(irq, "IRQ for the Arc board");
677
678module_init(arcfb_init);
679module_exit(arcfb_exit);
680
681MODULE_DESCRIPTION("fbdev driver for Arc monochrome LCD board");
682MODULE_AUTHOR("Jaya Kumar");
683MODULE_LICENSE("GPL");
684