ref: 254b07675e1a5348f2a8723f55e6b5b1b18a4721
dir: /os/ipaq1110/lcd.c/
#include "u.h"
#include "mem.h"
#include "../port/lib.h"
#include "dat.h"
#include "draw.h"
#include "fns.h"
#include "io.h"
#include <memdraw.h>
#include "screen.h"
#define DPRINT if(1)iprint
enum {
/* lccr0 */
EnableCtlr = 1<<0, /* controller enable */
IsColour = 0<<1,
IsMono = 1<<1,
SinglePanel = 0<<2,
DualPanel = 1<<2,
DisableDone = 1<<3,
DisableBAU = 1<<4,
DisableErr = 1<<5,
PassivePanel = 0<<7,
ActivePanel = 1<<7,
BigEndian = 1<<8,
DoublePixel = 1<<9,
/* 19:12 is palette dma delay */
/* lcsr */
CtlrReady = 1<<0,
/* lccr3 */
VsyncLow = 1<<20,
HsyncLow = 1<<21,
PixelClockLow = 1<<22,
OELow = 1<<23,
};
typedef struct {
Vdisplay;
LCDparam;
ushort* palette;
uchar* upper;
uchar* lower;
} LCDdisplay;
static LCDdisplay *vd; // current active display
void
lcd_setcolor(ulong p, ulong r, ulong g, ulong b)
{
if(vd->pbs == 0 && p > 15 ||
vd->pbs == 1 && p > 255 ||
vd->pbs == 2)
return;
vd->palette[p] = (vd->pbs<<12) |
((r>>(32-4))<<8) |
((g>>(32-4))<<4) |
(b>>(32-4));
}
static void
disablelcd(void)
{
LcdReg *lcd = LCDREG;
int i;
/* if LCD enabled, turn off and wait for current frame to end */
if(lcd->lccr0 & EnableCtlr) {
lcd->lccr0 &= ~EnableCtlr;
for(i=0; i < 50 && !(lcd->lcsr & CtlrReady); i++)
delay(5);
}
}
static void
setlcdmode(LCDdisplay *vd)
{
LCDmode *p;
int ppf, pclk, clockdiv;
ulong v, c;
LcdReg *lcd = LCDREG;
GpioReg *gpio = GPIOREG;
p = (LCDmode*)&vd->Vmode;
ppf = ((((p->x+p->sol_wait+p->eol_wait) *
(p->mono ? 1 : 3)) >> (3-p->mono)) +
p->hsync_wid) *
(p->y/(p->dual+1)+p->vsync_hgt+
p->sof_wait+p->eof_wait);
pclk = ppf*p->hz;
clockdiv = ((m->cpuhz/pclk) >> 1)-2;
DPRINT(" oclockdiv=%d\n", clockdiv);
clockdiv=0x10;
disablelcd();
lcd->lccr0 = 0; /* reset it */
DPRINT(" pclk=%d clockdiv=%d\n", pclk, clockdiv);
lcd->lccr3 = (clockdiv << 0) |
(p->acbias_lines << 8) |
(p->lines_per_int << 16) |
VsyncLow | HsyncLow; /* vsync active low, hsync active low */
lcd->lccr2 = (((p->y/(p->dual+1))-1) << 0) |
(p->vsync_hgt << 10) |
(p->eof_wait << 16) |
(p->sof_wait << 24);
lcd->lccr1 = ((p->x-16) << 0) |
(p->hsync_wid << 10) |
(p->eol_wait << 16) |
(p->sol_wait << 24);
// enable LCD controller, CODEC, and lower 4/8 data bits (for tft/dual)
v = p->obits < 12? 0: p->obits < 16? 0x3c: 0x3fc;
c = p->obits == 12? 0x3c0: 0;
gpio->gafr |= v;
gpio->gpdr |= v | c;
gpio->gpcr = c;
lcd->dbar1 = PADDR(vd->palette);
if(vd->dual)
lcd->dbar2 = PADDR(vd->lower);
// Enable LCD
lcd->lccr0 = EnableCtlr | (p->mono?IsMono:IsColour)
| (p->palette_delay << 12)
| (p->dual ? DualPanel : SinglePanel)
| (p->active? ActivePanel: PassivePanel)
| DisableDone | DisableBAU | DisableErr;
// recalculate actual HZ
pclk = (m->cpuhz/(clockdiv+2)) >> 1;
p->hz = pclk/ppf;
archlcdenable(1);
iprint("lccr0=%8.8lux lccr1=%8.8lux lccr2=%8.8lux lccr3=%8.8lux\n", lcd->lccr0, lcd->lccr1, lcd->lccr2, lcd->lccr3);
}
static LCDdisplay main_display; /* TO DO: limits us to a single display */
Vdisplay*
lcd_init(LCDmode *p)
{
int palsize;
int fbsize;
vd = &main_display;
vd->Vmode = *p;
vd->LCDparam = *p;
DPRINT("%dx%dx%d: hz=%d\n", vd->x, vd->y, vd->depth, vd->hz); /* */
palsize = vd->pbs==1? 256 : 16;
fbsize = palsize*2+(((vd->x*vd->y) * vd->depth) >> 3);
if((vd->palette = xspanalloc(fbsize+CACHELINESZ+512, CACHELINESZ, 0)) == nil) /* at least 16-byte alignment */
panic("no vidmem, no party...");
vd->palette[0] = (vd->pbs<<12);
vd->palette = minicached(vd->palette);
vd->upper = (uchar*)(vd->palette + palsize);
vd->bwid = (vd->x << vd->pbs) >> 1;
vd->lower = vd->upper+((vd->bwid*vd->y) >> 1);
vd->fb = vd->upper;
DPRINT(" fbsize=%d p=%p u=%p l=%p\n", fbsize, vd->palette, vd->upper, vd->lower); /* */
setlcdmode(vd);
return vd;
}
void
lcd_flush(void)
{
if(conf.useminicache)
minidcflush();
else
dcflushall(); /* need more precise addresses */
}
void
blankscreen(int blank)
{
if (blank) {
disablelcd();
archlcdenable(0);
} else {
archlcdenable(1);
setlcdmode(&main_display);
}
}