Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * linux/drivers/video/arcfb.c -- FB driver for Arc monochrome LCD board
0003  *
0004  * Copyright (C) 2005, Jaya Kumar <jayalk@intworks.biz>
0005  *
0006  * This file is subject to the terms and conditions of the GNU General Public
0007  * License. See the file COPYING in the main directory of this archive for
0008  * more details.
0009  *
0010  * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven.
0011  *
0012  * This driver was written to be used with the Arc LCD board. Arc uses a
0013  * set of KS108 chips that control individual 64x64 LCD matrices. The board
0014  * can be paneled in a variety of setups such as 2x1=128x64, 4x4=256x256 and
0015  * so on. The interface between the board and the host is TTL based GPIO. The
0016  * GPIO requirements are 8 writable data lines and 4+n lines for control. On a
0017  * GPIO-less system, the board can be tested by connecting the respective sigs
0018  * up to a parallel port connector. The driver requires the IO addresses for
0019  * data and control GPIO at load time. It is unable to probe for the
0020  * existence of the LCD so it must be told at load time whether it should
0021  * be enabled or not.
0022  *
0023  * Todo:
0024  * - testing with 4x4
0025  * - testing with interrupt hw
0026  *
0027  * General notes:
0028  * - User must set tuhold. It's in microseconds. According to the 108 spec,
0029  *   the hold time is supposed to be at least 1 microsecond.
0030  * - User must set num_cols=x num_rows=y, eg: x=2 means 128
0031  * - User must set arcfb_enable=1 to enable it
0032  * - User must set dio_addr=0xIOADDR cio_addr=0xIOADDR
0033  *
0034  */
0035 
0036 #include <linux/module.h>
0037 #include <linux/kernel.h>
0038 #include <linux/errno.h>
0039 #include <linux/string.h>
0040 #include <linux/mm.h>
0041 #include <linux/vmalloc.h>
0042 #include <linux/delay.h>
0043 #include <linux/interrupt.h>
0044 #include <linux/fb.h>
0045 #include <linux/init.h>
0046 #include <linux/arcfb.h>
0047 #include <linux/platform_device.h>
0048 
0049 #include <linux/uaccess.h>
0050 
0051 #define floor8(a) (a&(~0x07))
0052 #define floorXres(a,xres) (a&(~(xres - 1)))
0053 #define iceil8(a) (((int)((a+7)/8))*8)
0054 #define ceil64(a) (a|0x3F)
0055 #define ceilXres(a,xres) (a|(xres - 1))
0056 
0057 /* ks108 chipset specific defines and code */
0058 
0059 #define KS_SET_DPY_START_LINE   0xC0
0060 #define KS_SET_PAGE_NUM     0xB8
0061 #define KS_SET_X        0x40
0062 #define KS_CEHI         0x01
0063 #define KS_CELO         0x00
0064 #define KS_SEL_CMD      0x08
0065 #define KS_SEL_DATA         0x00
0066 #define KS_DPY_ON       0x3F
0067 #define KS_DPY_OFF      0x3E
0068 #define KS_INTACK       0x40
0069 #define KS_CLRINT       0x02
0070 
0071 struct arcfb_par {
0072     unsigned long dio_addr;
0073     unsigned long cio_addr;
0074     unsigned long c2io_addr;
0075     atomic_t ref_count;
0076     unsigned char cslut[9];
0077     struct fb_info *info;
0078     unsigned int irq;
0079     spinlock_t lock;
0080 };
0081 
0082 static const struct fb_fix_screeninfo arcfb_fix = {
0083     .id =       "arcfb",
0084     .type =     FB_TYPE_PACKED_PIXELS,
0085     .visual =   FB_VISUAL_MONO01,
0086     .xpanstep = 0,
0087     .ypanstep = 1,
0088     .ywrapstep =    0,
0089     .accel =    FB_ACCEL_NONE,
0090 };
0091 
0092 static const struct fb_var_screeninfo arcfb_var = {
0093     .xres       = 128,
0094     .yres       = 64,
0095     .xres_virtual   = 128,
0096     .yres_virtual   = 64,
0097     .bits_per_pixel = 1,
0098     .nonstd     = 1,
0099 };
0100 
0101 static unsigned long num_cols;
0102 static unsigned long num_rows;
0103 static unsigned long dio_addr;
0104 static unsigned long cio_addr;
0105 static unsigned long c2io_addr;
0106 static unsigned long splashval;
0107 static unsigned long tuhold;
0108 static unsigned int nosplash;
0109 static unsigned int arcfb_enable;
0110 static unsigned int irq;
0111 
0112 static DECLARE_WAIT_QUEUE_HEAD(arcfb_waitq);
0113 
0114 static void ks108_writeb_ctl(struct arcfb_par *par,
0115                 unsigned int chipindex, unsigned char value)
0116 {
0117     unsigned char chipselval = par->cslut[chipindex];
0118 
0119     outb(chipselval|KS_CEHI|KS_SEL_CMD, par->cio_addr);
0120     outb(value, par->dio_addr);
0121     udelay(tuhold);
0122     outb(chipselval|KS_CELO|KS_SEL_CMD, par->cio_addr);
0123 }
0124 
0125 static void ks108_writeb_mainctl(struct arcfb_par *par, unsigned char value)
0126 {
0127 
0128     outb(value, par->cio_addr);
0129     udelay(tuhold);
0130 }
0131 
0132 static unsigned char ks108_readb_ctl2(struct arcfb_par *par)
0133 {
0134     return inb(par->c2io_addr);
0135 }
0136 
0137 static void ks108_writeb_data(struct arcfb_par *par,
0138                 unsigned int chipindex, unsigned char value)
0139 {
0140     unsigned char chipselval = par->cslut[chipindex];
0141 
0142     outb(chipselval|KS_CEHI|KS_SEL_DATA, par->cio_addr);
0143     outb(value, par->dio_addr);
0144     udelay(tuhold);
0145     outb(chipselval|KS_CELO|KS_SEL_DATA, par->cio_addr);
0146 }
0147 
0148 static void ks108_set_start_line(struct arcfb_par *par,
0149                 unsigned int chipindex, unsigned char y)
0150 {
0151     ks108_writeb_ctl(par, chipindex, KS_SET_DPY_START_LINE|y);
0152 }
0153 
0154 static void ks108_set_yaddr(struct arcfb_par *par,
0155                 unsigned int chipindex, unsigned char y)
0156 {
0157     ks108_writeb_ctl(par, chipindex, KS_SET_PAGE_NUM|y);
0158 }
0159 
0160 static void ks108_set_xaddr(struct arcfb_par *par,
0161                 unsigned int chipindex, unsigned char x)
0162 {
0163     ks108_writeb_ctl(par, chipindex, KS_SET_X|x);
0164 }
0165 
0166 static void ks108_clear_lcd(struct arcfb_par *par, unsigned int chipindex)
0167 {
0168     int i,j;
0169 
0170     for (i = 0; i <= 8; i++) {
0171         ks108_set_yaddr(par, chipindex, i);
0172         ks108_set_xaddr(par, chipindex, 0);
0173         for (j = 0; j < 64; j++) {
0174             ks108_writeb_data(par, chipindex,
0175                 (unsigned char) splashval);
0176         }
0177     }
0178 }
0179 
0180 /* main arcfb functions */
0181 
0182 static int arcfb_open(struct fb_info *info, int user)
0183 {
0184     struct arcfb_par *par = info->par;
0185 
0186     atomic_inc(&par->ref_count);
0187     return 0;
0188 }
0189 
0190 static int arcfb_release(struct fb_info *info, int user)
0191 {
0192     struct arcfb_par *par = info->par;
0193     int count = atomic_read(&par->ref_count);
0194 
0195     if (!count)
0196         return -EINVAL;
0197     atomic_dec(&par->ref_count);
0198     return 0;
0199 }
0200 
0201 static int arcfb_pan_display(struct fb_var_screeninfo *var,
0202                 struct fb_info *info)
0203 {
0204     int i;
0205     struct arcfb_par *par = info->par;
0206 
0207     if ((var->vmode & FB_VMODE_YWRAP) && (var->yoffset < 64)
0208         && (info->var.yres <= 64)) {
0209         for (i = 0; i < num_cols; i++) {
0210             ks108_set_start_line(par, i, var->yoffset);
0211         }
0212         info->var.yoffset = var->yoffset;
0213         return 0;
0214     }
0215 
0216     return -EINVAL;
0217 }
0218 
0219 static irqreturn_t arcfb_interrupt(int vec, void *dev_instance)
0220 {
0221     struct fb_info *info = dev_instance;
0222     unsigned char ctl2status;
0223     struct arcfb_par *par = info->par;
0224 
0225     ctl2status = ks108_readb_ctl2(par);
0226 
0227     if (!(ctl2status & KS_INTACK)) /* not arc generated interrupt */
0228         return IRQ_NONE;
0229 
0230     ks108_writeb_mainctl(par, KS_CLRINT);
0231 
0232     spin_lock(&par->lock);
0233         if (waitqueue_active(&arcfb_waitq)) {
0234                 wake_up(&arcfb_waitq);
0235         }
0236     spin_unlock(&par->lock);
0237 
0238     return IRQ_HANDLED;
0239 }
0240 
0241 /*
0242  * here we handle a specific page on the lcd. the complexity comes from
0243  * the fact that the fb is laidout in 8xX vertical columns. we extract
0244  * each write of 8 vertical pixels. then we shift out as we move along
0245  * X. That's what rightshift does. bitmask selects the desired input bit.
0246  */
0247 static void arcfb_lcd_update_page(struct arcfb_par *par, unsigned int upper,
0248         unsigned int left, unsigned int right, unsigned int distance)
0249 {
0250     unsigned char *src;
0251     unsigned int xindex, yindex, chipindex, linesize;
0252     int i;
0253     unsigned char val;
0254     unsigned char bitmask, rightshift;
0255 
0256     xindex = left >> 6;
0257     yindex = upper >> 6;
0258     chipindex = (xindex + (yindex*num_cols));
0259 
0260     ks108_set_yaddr(par, chipindex, upper/8);
0261 
0262     linesize = par->info->var.xres/8;
0263     src = (unsigned char __force *) par->info->screen_base + (left/8) +
0264         (upper * linesize);
0265     ks108_set_xaddr(par, chipindex, left);
0266 
0267     bitmask=1;
0268     rightshift=0;
0269     while (left <= right) {
0270         val = 0;
0271         for (i = 0; i < 8; i++) {
0272             if ( i > rightshift) {
0273                 val |= (*(src + (i*linesize)) & bitmask)
0274                         << (i - rightshift);
0275             } else {
0276                 val |= (*(src + (i*linesize)) & bitmask)
0277                          >> (rightshift - i);
0278             }
0279         }
0280         ks108_writeb_data(par, chipindex, val);
0281         left++;
0282         if (bitmask == 0x80) {
0283             bitmask = 1;
0284             src++;
0285             rightshift=0;
0286         } else {
0287             bitmask <<= 1;
0288             rightshift++;
0289         }
0290     }
0291 }
0292 
0293 /*
0294  * here we handle the entire vertical page of the update. we write across
0295  * lcd chips. update_page uses the upper/left values to decide which
0296  * chip to select for the right. upper is needed for setting the page
0297  * desired for the write.
0298  */
0299 static void arcfb_lcd_update_vert(struct arcfb_par *par, unsigned int top,
0300         unsigned int bottom, unsigned int left, unsigned int right)
0301 {
0302     unsigned int distance, upper, lower;
0303 
0304     distance = (bottom - top) + 1;
0305     upper = top;
0306     lower = top + 7;
0307 
0308     while (distance > 0) {
0309         distance -= 8;
0310         arcfb_lcd_update_page(par, upper, left, right, 8);
0311         upper = lower + 1;
0312         lower = upper + 7;
0313     }
0314 }
0315 
0316 /*
0317  * here we handle horizontal blocks for the update. update_vert will
0318  * handle spaning multiple pages. we break out each horizontal
0319  * block in to individual blocks no taller than 64 pixels.
0320  */
0321 static void arcfb_lcd_update_horiz(struct arcfb_par *par, unsigned int left,
0322             unsigned int right, unsigned int top, unsigned int h)
0323 {
0324     unsigned int distance, upper, lower;
0325 
0326     distance = h;
0327     upper = floor8(top);
0328     lower = min(upper + distance - 1, ceil64(upper));
0329 
0330     while (distance > 0) {
0331         distance -= ((lower - upper) + 1 );
0332         arcfb_lcd_update_vert(par, upper, lower, left, right);
0333         upper = lower + 1;
0334         lower = min(upper + distance - 1, ceil64(upper));
0335     }
0336 }
0337 
0338 /*
0339  * here we start the process of splitting out the fb update into
0340  * individual blocks of pixels. we end up splitting into 64x64 blocks
0341  * and finally down to 64x8 pages.
0342  */
0343 static void arcfb_lcd_update(struct arcfb_par *par, unsigned int dx,
0344             unsigned int dy, unsigned int w, unsigned int h)
0345 {
0346     unsigned int left, right, distance, y;
0347 
0348     /* align the request first */
0349     y = floor8(dy);
0350     h += dy - y;
0351     h = iceil8(h);
0352 
0353     distance = w;
0354     left = dx;
0355     right = min(left + w - 1, ceil64(left));
0356 
0357     while (distance > 0) {
0358         arcfb_lcd_update_horiz(par, left, right, y, h);
0359         distance -= ((right - left) + 1);
0360         left = right + 1;
0361         right = min(left + distance - 1, ceil64(left));
0362     }
0363 }
0364 
0365 static void arcfb_fillrect(struct fb_info *info,
0366                const struct fb_fillrect *rect)
0367 {
0368     struct arcfb_par *par = info->par;
0369 
0370     sys_fillrect(info, rect);
0371 
0372     /* update the physical lcd */
0373     arcfb_lcd_update(par, rect->dx, rect->dy, rect->width, rect->height);
0374 }
0375 
0376 static void arcfb_copyarea(struct fb_info *info,
0377                const struct fb_copyarea *area)
0378 {
0379     struct arcfb_par *par = info->par;
0380 
0381     sys_copyarea(info, area);
0382 
0383     /* update the physical lcd */
0384     arcfb_lcd_update(par, area->dx, area->dy, area->width, area->height);
0385 }
0386 
0387 static void arcfb_imageblit(struct fb_info *info, const struct fb_image *image)
0388 {
0389     struct arcfb_par *par = info->par;
0390 
0391     sys_imageblit(info, image);
0392 
0393     /* update the physical lcd */
0394     arcfb_lcd_update(par, image->dx, image->dy, image->width,
0395                 image->height);
0396 }
0397 
0398 static int arcfb_ioctl(struct fb_info *info,
0399               unsigned int cmd, unsigned long arg)
0400 {
0401     void __user *argp = (void __user *)arg;
0402     struct arcfb_par *par = info->par;
0403     unsigned long flags;
0404 
0405     switch (cmd) {
0406         case FBIO_WAITEVENT:
0407         {
0408             DEFINE_WAIT(wait);
0409             /* illegal to wait on arc if no irq will occur */
0410             if (!par->irq)
0411                 return -EINVAL;
0412 
0413             /* wait until the Arc has generated an interrupt
0414              * which will wake us up */
0415             spin_lock_irqsave(&par->lock, flags);
0416             prepare_to_wait(&arcfb_waitq, &wait,
0417                     TASK_INTERRUPTIBLE);
0418             spin_unlock_irqrestore(&par->lock, flags);
0419             schedule();
0420             finish_wait(&arcfb_waitq, &wait);
0421         }
0422         fallthrough;
0423 
0424         case FBIO_GETCONTROL2:
0425         {
0426             unsigned char ctl2;
0427 
0428             ctl2 = ks108_readb_ctl2(info->par);
0429             if (copy_to_user(argp, &ctl2, sizeof(ctl2)))
0430                 return -EFAULT;
0431             return 0;
0432         }
0433         default:
0434             return -EINVAL;
0435     }
0436 }
0437 
0438 /*
0439  * this is the access path from userspace. they can seek and write to
0440  * the fb. it's inefficient for them to do anything less than 64*8
0441  * writes since we update the lcd in each write() anyway.
0442  */
0443 static ssize_t arcfb_write(struct fb_info *info, const char __user *buf,
0444                size_t count, loff_t *ppos)
0445 {
0446     /* modded from epson 1355 */
0447 
0448     unsigned long p;
0449     int err;
0450     unsigned int fbmemlength,x,y,w,h, bitppos, startpos, endpos, bitcount;
0451     struct arcfb_par *par;
0452     unsigned int xres;
0453 
0454     p = *ppos;
0455     par = info->par;
0456     xres = info->var.xres;
0457     fbmemlength = (xres * info->var.yres)/8;
0458 
0459     if (p > fbmemlength)
0460         return -ENOSPC;
0461 
0462     err = 0;
0463     if ((count + p) > fbmemlength) {
0464         count = fbmemlength - p;
0465         err = -ENOSPC;
0466     }
0467 
0468     if (count) {
0469         char *base_addr;
0470 
0471         base_addr = (char __force *)info->screen_base;
0472         count -= copy_from_user(base_addr + p, buf, count);
0473         *ppos += count;
0474         err = -EFAULT;
0475     }
0476 
0477 
0478     bitppos = p*8;
0479     startpos = floorXres(bitppos, xres);
0480     endpos = ceilXres((bitppos + (count*8)), xres);
0481     bitcount = endpos - startpos;
0482 
0483     x = startpos % xres;
0484     y = startpos / xres;
0485     w = xres;
0486     h = bitcount / xres;
0487     arcfb_lcd_update(par, x, y, w, h);
0488 
0489     if (count)
0490         return count;
0491     return err;
0492 }
0493 
0494 static const struct fb_ops arcfb_ops = {
0495     .owner      = THIS_MODULE,
0496     .fb_open    = arcfb_open,
0497     .fb_read        = fb_sys_read,
0498     .fb_write   = arcfb_write,
0499     .fb_release = arcfb_release,
0500     .fb_pan_display = arcfb_pan_display,
0501     .fb_fillrect    = arcfb_fillrect,
0502     .fb_copyarea    = arcfb_copyarea,
0503     .fb_imageblit   = arcfb_imageblit,
0504     .fb_ioctl   = arcfb_ioctl,
0505 };
0506 
0507 static int arcfb_probe(struct platform_device *dev)
0508 {
0509     struct fb_info *info;
0510     int retval = -ENOMEM;
0511     int videomemorysize;
0512     unsigned char *videomemory;
0513     struct arcfb_par *par;
0514     int i;
0515 
0516     videomemorysize = (((64*64)*num_cols)*num_rows)/8;
0517 
0518     /* We need a flat backing store for the Arc's
0519        less-flat actual paged framebuffer */
0520     videomemory = vzalloc(videomemorysize);
0521     if (!videomemory)
0522         return retval;
0523 
0524     info = framebuffer_alloc(sizeof(struct arcfb_par), &dev->dev);
0525     if (!info)
0526         goto err;
0527 
0528     info->screen_base = (char __iomem *)videomemory;
0529     info->fbops = &arcfb_ops;
0530 
0531     info->var = arcfb_var;
0532     info->fix = arcfb_fix;
0533     par = info->par;
0534     par->info = info;
0535 
0536     if (!dio_addr || !cio_addr || !c2io_addr) {
0537         printk(KERN_WARNING "no IO addresses supplied\n");
0538         goto err1;
0539     }
0540     par->dio_addr = dio_addr;
0541     par->cio_addr = cio_addr;
0542     par->c2io_addr = c2io_addr;
0543     par->cslut[0] = 0x00;
0544     par->cslut[1] = 0x06;
0545     info->flags = FBINFO_FLAG_DEFAULT;
0546     spin_lock_init(&par->lock);
0547     if (irq) {
0548         par->irq = irq;
0549         if (request_irq(par->irq, &arcfb_interrupt, IRQF_SHARED,
0550                 "arcfb", info)) {
0551             printk(KERN_INFO
0552                 "arcfb: Failed req IRQ %d\n", par->irq);
0553             retval = -EBUSY;
0554             goto err1;
0555         }
0556     }
0557     retval = register_framebuffer(info);
0558     if (retval < 0)
0559         goto err1;
0560     platform_set_drvdata(dev, info);
0561     fb_info(info, "Arc frame buffer device, using %dK of video memory\n",
0562         videomemorysize >> 10);
0563 
0564     /* this inits the lcd but doesn't clear dirty pixels */
0565     for (i = 0; i < num_cols * num_rows; i++) {
0566         ks108_writeb_ctl(par, i, KS_DPY_OFF);
0567         ks108_set_start_line(par, i, 0);
0568         ks108_set_yaddr(par, i, 0);
0569         ks108_set_xaddr(par, i, 0);
0570         ks108_writeb_ctl(par, i, KS_DPY_ON);
0571     }
0572 
0573     /* if we were told to splash the screen, we just clear it */
0574     if (!nosplash) {
0575         for (i = 0; i < num_cols * num_rows; i++) {
0576             fb_info(info, "splashing lcd %d\n", i);
0577             ks108_set_start_line(par, i, 0);
0578             ks108_clear_lcd(par, i);
0579         }
0580     }
0581 
0582     return 0;
0583 err1:
0584     framebuffer_release(info);
0585 err:
0586     vfree(videomemory);
0587     return retval;
0588 }
0589 
0590 static int arcfb_remove(struct platform_device *dev)
0591 {
0592     struct fb_info *info = platform_get_drvdata(dev);
0593 
0594     if (info) {
0595         unregister_framebuffer(info);
0596         if (irq)
0597             free_irq(((struct arcfb_par *)(info->par))->irq, info);
0598         vfree((void __force *)info->screen_base);
0599         framebuffer_release(info);
0600     }
0601     return 0;
0602 }
0603 
0604 static struct platform_driver arcfb_driver = {
0605     .probe  = arcfb_probe,
0606     .remove = arcfb_remove,
0607     .driver = {
0608         .name   = "arcfb",
0609     },
0610 };
0611 
0612 static struct platform_device *arcfb_device;
0613 
0614 static int __init arcfb_init(void)
0615 {
0616     int ret;
0617 
0618     if (!arcfb_enable)
0619         return -ENXIO;
0620 
0621     ret = platform_driver_register(&arcfb_driver);
0622     if (!ret) {
0623         arcfb_device = platform_device_alloc("arcfb", 0);
0624         if (arcfb_device) {
0625             ret = platform_device_add(arcfb_device);
0626         } else {
0627             ret = -ENOMEM;
0628         }
0629         if (ret) {
0630             platform_device_put(arcfb_device);
0631             platform_driver_unregister(&arcfb_driver);
0632         }
0633     }
0634     return ret;
0635 
0636 }
0637 
0638 static void __exit arcfb_exit(void)
0639 {
0640     platform_device_unregister(arcfb_device);
0641     platform_driver_unregister(&arcfb_driver);
0642 }
0643 
0644 module_param(num_cols, ulong, 0);
0645 MODULE_PARM_DESC(num_cols, "Num horiz panels, eg: 2 = 128 bit wide");
0646 module_param(num_rows, ulong, 0);
0647 MODULE_PARM_DESC(num_rows, "Num vert panels, eg: 1 = 64 bit high");
0648 module_param(nosplash, uint, 0);
0649 MODULE_PARM_DESC(nosplash, "Disable doing the splash screen");
0650 module_param(arcfb_enable, uint, 0);
0651 MODULE_PARM_DESC(arcfb_enable, "Enable communication with Arc board");
0652 module_param_hw(dio_addr, ulong, ioport, 0);
0653 MODULE_PARM_DESC(dio_addr, "IO address for data, eg: 0x480");
0654 module_param_hw(cio_addr, ulong, ioport, 0);
0655 MODULE_PARM_DESC(cio_addr, "IO address for control, eg: 0x400");
0656 module_param_hw(c2io_addr, ulong, ioport, 0);
0657 MODULE_PARM_DESC(c2io_addr, "IO address for secondary control, eg: 0x408");
0658 module_param(splashval, ulong, 0);
0659 MODULE_PARM_DESC(splashval, "Splash pattern: 0xFF is black, 0x00 is green");
0660 module_param(tuhold, ulong, 0);
0661 MODULE_PARM_DESC(tuhold, "Time to hold between strobing data to Arc board");
0662 module_param_hw(irq, uint, irq, 0);
0663 MODULE_PARM_DESC(irq, "IRQ for the Arc board");
0664 
0665 module_init(arcfb_init);
0666 module_exit(arcfb_exit);
0667 
0668 MODULE_DESCRIPTION("fbdev driver for Arc monochrome LCD board");
0669 MODULE_AUTHOR("Jaya Kumar");
0670 MODULE_LICENSE("GPL");
0671