/* * linux/drivers/video/arcfb.c -- FB driver for Arc monochrome LCD board * * Copyright (C) 2005, Jaya Kumar <jayalk@intworks.biz> * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive for * more details. * * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven. * * This driver was written to be used with the Arc LCD board. Arc uses a * set of KS108 chips that control individual 64x64 LCD matrices. The board * can be paneled in a variety of setups such as 2x1=128x64, 4x4=256x256 and * so on. The interface between the board and the host is TTL based GPIO. The * GPIO requirements are 8 writable data lines and 4+n lines for control. On a * GPIO-less system, the board can be tested by connecting the respective sigs * up to a parallel port connector. The driver requires the IO addresses for * data and control GPIO at load time. It is unable to probe for the * existence of the LCD so it must be told at load time whether it should * be enabled or not. * * Todo: * - testing with 4x4 * - testing with interrupt hw * * General notes: * - User must set tuhold. It's in microseconds. According to the 108 spec, * the hold time is supposed to be at least 1 microsecond. * - User must set num_cols=x num_rows=y, eg: x=2 means 128 * - User must set arcfb_enable=1 to enable it * - User must set dio_addr=0xIOADDR cio_addr=0xIOADDR *
*/
if (!(ctl2status & KS_INTACK)) /* not arc generated interrupt */ return IRQ_NONE;
ks108_writeb_mainctl(par, KS_CLRINT);
spin_lock(&par->lock); if (waitqueue_active(&arcfb_waitq)) {
wake_up(&arcfb_waitq);
}
spin_unlock(&par->lock);
return IRQ_HANDLED;
}
/* * here we handle a specific page on the lcd. the complexity comes from * the fact that the fb is laidout in 8xX vertical columns. we extract * each write of 8 vertical pixels. then we shift out as we move along * X. That's what rightshift does. bitmask selects the desired input bit.
*/ staticvoid arcfb_lcd_update_page(struct arcfb_par *par, unsignedint upper, unsignedint left, unsignedint right, unsignedint distance)
{ unsignedchar *src; unsignedint xindex, yindex, chipindex, linesize; int i; unsignedchar val; unsignedchar bitmask, rightshift;
bitmask=1;
rightshift=0; while (left <= right) {
val = 0; for (i = 0; i < 8; i++) { if ( i > rightshift) {
val |= (*(src + (i*linesize)) & bitmask)
<< (i - rightshift);
} else {
val |= (*(src + (i*linesize)) & bitmask)
>> (rightshift - i);
}
}
ks108_writeb_data(par, chipindex, val);
left++; if (bitmask == 0x80) {
bitmask = 1;
src++;
rightshift=0;
} else {
bitmask <<= 1;
rightshift++;
}
}
}
/* * here we handle the entire vertical page of the update. we write across * lcd chips. update_page uses the upper/left values to decide which * chip to select for the right. upper is needed for setting the page * desired for the write.
*/ staticvoid arcfb_lcd_update_vert(struct arcfb_par *par, unsignedint top, unsignedint bottom, unsignedint left, unsignedint right)
{ unsignedint distance, upper, lower;
/* * here we handle horizontal blocks for the update. update_vert will * handle spaning multiple pages. we break out each horizontal * block in to individual blocks no taller than 64 pixels.
*/ staticvoid arcfb_lcd_update_horiz(struct arcfb_par *par, unsignedint left, unsignedint right, unsignedint top, unsignedint h)
{ unsignedint distance, upper, lower;
/* * here we start the process of splitting out the fb update into * individual blocks of pixels. we end up splitting into 64x64 blocks * and finally down to 64x8 pages.
*/ staticvoid arcfb_lcd_update(struct arcfb_par *par, unsignedint dx, unsignedint dy, unsignedint w, unsignedint h)
{ unsignedint left, right, distance, y;
/* align the request first */
y = floor8(dy);
h += dy - y;
h = iceil8(h);
distance = w;
left = dx;
right = min(left + w - 1, ceil64(left));
while (distance > 0) {
arcfb_lcd_update_horiz(par, left, right, y, h);
distance -= ((right - left) + 1);
left = right + 1;
right = min(left + distance - 1, ceil64(left));
}
}
switch (cmd) { case FBIO_WAITEVENT:
{
DEFINE_WAIT(wait); /* illegal to wait on arc if no irq will occur */ if (!par->irq) return -EINVAL;
/* wait until the Arc has generated an interrupt
* which will wake us up */
spin_lock_irqsave(&par->lock, flags);
prepare_to_wait(&arcfb_waitq, &wait,
TASK_INTERRUPTIBLE);
spin_unlock_irqrestore(&par->lock, flags);
schedule();
finish_wait(&arcfb_waitq, &wait);
}
fallthrough;
/* We need a flat backing store for the Arc's
less-flat actual paged framebuffer */
videomemory = vzalloc(videomemorysize); if (!videomemory) return retval;
info = framebuffer_alloc(sizeof(struct arcfb_par), &dev->dev); if (!info) goto err_fb_alloc;
/* this inits the lcd but doesn't clear dirty pixels */ for (i = 0; i < num_cols * num_rows; i++) {
ks108_writeb_ctl(par, i, KS_DPY_OFF);
ks108_set_start_line(par, i, 0);
ks108_set_yaddr(par, i, 0);
ks108_set_xaddr(par, i, 0);
ks108_writeb_ctl(par, i, KS_DPY_ON);
}
/* if we were told to splash the screen, we just clear it */ if (!nosplash) { for (i = 0; i < num_cols * num_rows; i++) {
fb_info(info, "splashing lcd %d\n", i);
ks108_set_start_line(par, i, 0);
ks108_clear_lcd(par, i);
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.