summaryrefslogtreecommitdiff
path: root/os/ipaq1110/lcd.c
diff options
context:
space:
mode:
Diffstat (limited to 'os/ipaq1110/lcd.c')
-rw-r--r--os/ipaq1110/lcd.c185
1 files changed, 185 insertions, 0 deletions
diff --git a/os/ipaq1110/lcd.c b/os/ipaq1110/lcd.c
new file mode 100644
index 00000000..11b9ef7d
--- /dev/null
+++ b/os/ipaq1110/lcd.c
@@ -0,0 +1,185 @@
+#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);
+ }
+}