0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
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
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
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))
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
0243
0244
0245
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
0295
0296
0297
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
0318
0319
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
0340
0341
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
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
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
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
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
0410 if (!par->irq)
0411 return -EINVAL;
0412
0413
0414
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
0440
0441
0442
0443 static ssize_t arcfb_write(struct fb_info *info, const char __user *buf,
0444 size_t count, loff_t *ppos)
0445 {
0446
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
0519
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
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
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