diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/9/omap/screen.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/9/omap/screen.c')
-rwxr-xr-x | sys/src/9/omap/screen.c | 791 |
1 files changed, 791 insertions, 0 deletions
diff --git a/sys/src/9/omap/screen.c b/sys/src/9/omap/screen.c new file mode 100755 index 000000000..e47fd2821 --- /dev/null +++ b/sys/src/9/omap/screen.c @@ -0,0 +1,791 @@ +/* + * ti omap35 display subsystem (dss) + * + * can handle 2ⁿ bits per pixel for 0 < n ≤ 4, and 12 and 24 bits. + * can handle 1024×768 at 60 Hz with pixel clock of 63.5 MHz + * 1280×800 at 59.91 Hz with pixel clock of 71 MHz + * 1400×1050 lcd at 50 MHz with pixel clock of 75 MHz + * has 256 24-bit entries in RGB palette + */ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "ureg.h" +#include "../port/error.h" + +#define Image IMAGE +#include <draw.h> +#include <memdraw.h> +#include <cursor.h> +#include "screen.h" +// #include "gamma.h" + +enum { + Tabstop = 4, /* should be 8 */ + Scroll = 8, /* lines to scroll at one time */ + /* + * screen settings for Wid and Ht, should a bit more dynamic? + * http://www.epanorama.net/faq/vga2rgb/calc.html + * used to calculate settings. + */ + +// Hbp = (248-1) << 20, +// Hfp = (48-1) << 8, +// Hsw = 112-1, + +// Vbp = 38 << 20, +// Vfp = 1 << 8, +// Vsw = 3, + + Tft = 0x60, + + Loadmode = 2 << 1, + Fifosize = 0x400, + + /* dispc sysconfig */ + Midlemode = 2 << 12, + Sidlemode = 2 << 3, + EnableWakeup = 1 << 2, + Autoidle = 1 << 0, + + /* dispc pool_freq */ + Ipc = 1 << 14, + Ihs = 1 << 13, + Ivs = 1 << 12, + Acb = 0x28, + + /* gfx attribs */ + Burstsize = 2 << 6, + Format = 6 << 1, + Gfxenable = 1 << 0, + + /* dispc control */ + Gpout1 = 1 << 16, + Gpout0 = 1 << 15, + Tftdata = 3 << 8, + Digital = 1 << 6, + Lcd = 1 << 5, + Stntft = 1 << 3, + Digitalen = 1 << 1, +// Lcden = 1 << 0, /* unused */ +}; + +typedef struct Dispcregs Dispc; +typedef struct Dssregs Dss; +typedef struct Ioregs Ioregs; + +struct Ioregs { /* common registers, 68 (0x44) bytes */ + ulong rev; + uchar _pad0[0x10-0x4]; + ulong sysconf; + ulong sysstat; + ulong irqstat1; + + /* Dispc only regs */ + ulong irqen1; + ulong wkupen; + ulong _pad1; + ulong irqsts2; + ulong irqen2; + ulong _pad2[4]; + + ulong ctrl; +}; + +struct Dssregs { /* display subsys at 0x48050000 */ + Ioregs; + ulong sdicrtl; + ulong pllcrtl; + uchar _pad3[0x5c-0x4c]; + ulong sdistat; +}; + +struct Dispcregs { /* display ctlr at 0x48050400 */ + Ioregs; + ulong config; + ulong _pad3; + ulong defaultcolor[2]; + ulong transcolor[2]; + ulong linestat; + ulong linenum; + ulong timing_h; + ulong timing_v; + ulong pol_req; + ulong divisor; + ulong alpha; + ulong digsize; + ulong lcdsize; + + ulong base[2]; /* should allocate both to avoid dithering */ + ulong pos; + ulong size; + ulong _pad4[4]; + ulong attrib; + ulong fifothr; + ulong fifosize; + ulong rowinc; + ulong pixelinc; + ulong winskip; + ulong palette; /* gfx_table_ba */ + uchar _pad5[0x5d4 - 0x4bc]; + + ulong datacycle[3]; + uchar _pad5[0x620 - 0x5e0]; + + ulong cprcoefr; + ulong cprcoefg; + ulong cprcoefb; + ulong preload; +}; + +int drawdebug; +Point ZP = {0, 0}; +Cursor arrow = { + { -1, -1 }, + { 0xFF, 0xFF, 0x80, 0x01, 0x80, 0x02, 0x80, 0x0C, + 0x80, 0x10, 0x80, 0x10, 0x80, 0x08, 0x80, 0x04, + 0x80, 0x02, 0x80, 0x01, 0x80, 0x02, 0x8C, 0x04, + 0x92, 0x08, 0x91, 0x10, 0xA0, 0xA0, 0xC0, 0x40, + }, + { 0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFC, 0x7F, 0xF0, + 0x7F, 0xE0, 0x7F, 0xE0, 0x7F, 0xF0, 0x7F, 0xF8, + 0x7F, 0xFC, 0x7F, 0xFE, 0x7F, 0xFC, 0x73, 0xF8, + 0x61, 0xF0, 0x60, 0xE0, 0x40, 0x40, 0x00, 0x00, + }, +}; + +OScreen oscreen; +Settings settings[] = { +[Res800x600] { 800, 600, 60, RGB16, 40000, 88, 40, 128, 23, 1, 5, }, +[Res1024x768] { 1024, 768, 60, RGB16, 65000, 160, 24, 136, 29, 3, 7, }, +[Res1280x1024] { 1280, 1024, 60, RGB16, 108000, 248, 48, 112, 38, 1, 4, }, +[Res1400x1050] { 1400, 1050, 50, RGB16, 108000, 248, 48, 112, 38, 1, 4, }, // TODO +}; +Omap3fb *framebuf; +Memimage *gscreen; + +static Memdata xgdata; + +static Memimage xgscreen = +{ + { 0, 0, Wid, Ht }, /* r */ + { 0, 0, Wid, Ht }, /* clipr */ + Depth, /* depth */ + 3, /* nchan */ + RGB16, /* chan */ + nil, /* cmap */ + &xgdata, /* data */ + 0, /* zero */ + Wid*(Depth/BI2BY)/BY2WD, /* width in words of a single scan line */ + 0, /* layer */ + 0, /* flags */ +}; + +static Memimage *conscol; +static Memimage *back; + +static Memsubfont *memdefont; + +static Lock screenlock; + +static Point curpos; +static int h, w; +static int landscape = 0; /* screen orientation, default is 0: portrait */ +static ushort *vscreen; /* virtual screen */ +static Rectangle window; + +static Dispc *dispc = (Dispc *)PHYSDISPC; +static Dss *dss = (Dss *)PHYSDSS; + +static void omapscreenputs(char *s, int n); +static ulong rep(ulong, int); +static void screenputc(char *buf); +static void screenwin(void); + +/* + * Software cursor. + */ +int swvisible; /* is the cursor visible? */ +int swenabled; /* is the cursor supposed to be on the screen? */ +Memimage* swback; /* screen under cursor */ +Memimage* swimg; /* cursor image */ +Memimage* swmask; /* cursor mask */ +Memimage* swimg1; +Memimage* swmask1; + +Point swoffset; +Rectangle swrect; /* screen rectangle in swback */ +Point swpt; /* desired cursor location */ +Point swvispt; /* actual cursor location */ +int swvers; /* incremented each time cursor image changes */ +int swvisvers; /* the version on the screen */ + +static void +lcdoff(void) +{ + dispc->ctrl &= ~1; /* disable the lcd */ + coherence(); + + dispc->irqstat1 |= 1; /* set framedone */ + coherence(); + + /* the lcd never comes ready, so don't bother with this */ +#ifdef notdef + /* spin until the frame is complete, but not forever */ + for(cnt = 50; !(dispc->irqstat1 & 1) && cnt-- > 0; ) + delay(10); +#endif + delay(20); /* worst case for 1 frame, 50Hz */ +} + +static void +dssstart(void) +{ + /* should reset the dss system */ + dss->sysconf |= 1; + coherence(); +} + +/* see spruf98i §15.6.7.4.2 */ +static void +configdispc(void) +{ + Settings *sp; + + sp = oscreen.settings; + dss->ctrl &= 0x78; /* choose dss clock */ + dispc->sysconf = Midlemode | Sidlemode | EnableWakeup | Autoidle; + dispc->config = Loadmode; + coherence(); + + /* pll */ + dispc->defaultcolor[0] = 0; /* set background color to black? */ + dispc->defaultcolor[1] = 0; + dispc->transcolor[0] = 0; /* set transparency to full */ + dispc->transcolor[1] = 0; + + dispc->timing_h = (sp->hbp-1) << 20 | (sp->hfp-1) << 8 | + (sp->hsw-1); + dispc->timing_v = sp->vbp << 20 | sp->vfp << 8 | + (sp->vsw-1); + + dispc->pol_req = Ipc | Ihs | Ivs | Acb; + dispc->divisor = 1 << 16 | HOWMANY(432000, sp->pixelclock); + + dispc->lcdsize = (sp->ht - 1) << 16 | (sp->wid - 1); + coherence(); + + dispc->base[0] = PADDR(framebuf->pixel); + dispc->base[1] = PADDR(framebuf->pixel); + + dispc->pos = 0; /* place screen in the left corner */ + /* use the whole screen */ + dispc->size = (sp->ht - 1) << 16 | (sp->wid - 1); + + /* what mode does plan 9 use for fb? */ + dispc->attrib = Burstsize | Format | Gfxenable; + + dispc->preload = Tft; + dispc->fifosize = Fifosize; + /* 1008 is max for our Burstsize */ + dispc->fifothr = (Fifosize - 1) << 16 | (1008 - 1); + + /* 1 byte is one pixel (not true, we use 2 bytes per pixel) */ + dispc->rowinc = 1; + dispc->pixelinc = 1; + dispc->winskip = 0; /* don't skip anything */ + coherence(); + + // dispc->palette = PADDR(framebuf->palette); +} + +static void +lcdon(int enable) +{ + dispc->ctrl = Gpout1 | Gpout0 | Tftdata | Digital | Lcd | Stntft | + Digitalen | enable; + coherence(); + delay(10); +} + +static void +lcdstop(void) +{ + configscreengpio(); + screenclockson(); + + lcdoff(); +} + +static void +lcdinit(void) +{ + lcdstop(); + + dssstart(); + configdispc(); +} + +/* Paint the image data with blue pixels */ +void +screentest(void) +{ + int i; + + for (i = nelem(framebuf->pixel) - 1; i >= 0; i--) + framebuf->pixel[i] = 0x1f; /* blue */ +// memset(framebuf->pixel, ~0, sizeof framebuf->pixel); /* white */ +} + +void +screenpower(int on) +{ + blankscreen(on == 0); +} + +/* + * called with drawlock locked for us, most of the time. + * kernel prints at inopportune times might mean we don't + * hold the lock, but memimagedraw is now reentrant so + * that should be okay: worst case we get cursor droppings. + */ +void +swcursorhide(void) +{ + if(swvisible == 0) + return; + if(swback == nil) + return; + swvisible = 0; + memimagedraw(gscreen, swrect, swback, ZP, memopaque, ZP, S); + flushmemscreen(swrect); +} + +void +swcursoravoid(Rectangle r) +{ + if(swvisible && rectXrect(r, swrect)) + swcursorhide(); +} + +void +swcursordraw(void) +{ + if(swvisible) + return; + if(swenabled == 0) + return; + if(swback == nil || swimg1 == nil || swmask1 == nil) + return; +// assert(!canqlock(&drawlock)); // assertion fails on omap + swvispt = swpt; + swvisvers = swvers; + swrect = rectaddpt(Rect(0,0,16,16), swvispt); + memimagedraw(swback, swback->r, gscreen, swpt, memopaque, ZP, S); + memimagedraw(gscreen, swrect, swimg1, ZP, swmask1, ZP, SoverD); + flushmemscreen(swrect); + swvisible = 1; +} + +int +cursoron(int dolock) +{ + if (dolock) + lock(&oscreen); + cursoroff(0); + swcursordraw(); + if (dolock) + unlock(&oscreen); + return 0; +} + +void +cursoroff(int dolock) +{ + if (dolock) + lock(&oscreen); + swcursorhide(); + if (dolock) + unlock(&oscreen); +} + +void +swload(Cursor *curs) +{ + uchar *ip, *mp; + int i, j, set, clr; + + if(!swimg || !swmask || !swimg1 || !swmask1) + return; + /* + * Build cursor image and mask. + * Image is just the usual cursor image + * but mask is a transparent alpha mask. + * + * The 16x16x8 memimages do not have + * padding at the end of their scan lines. + */ + ip = byteaddr(swimg, ZP); + mp = byteaddr(swmask, ZP); + for(i=0; i<32; i++){ + set = curs->set[i]; + clr = curs->clr[i]; + for(j=0x80; j; j>>=1){ + *ip++ = set&j ? 0x00 : 0xFF; + *mp++ = (clr|set)&j ? 0xFF : 0x00; + } + } + swoffset = curs->offset; + swvers++; + memimagedraw(swimg1, swimg1->r, swimg, ZP, memopaque, ZP, S); + memimagedraw(swmask1, swmask1->r, swmask, ZP, memopaque, ZP, S); +} + +/* called from devmouse */ +void +setcursor(Cursor* curs) +{ + cursoroff(1); + oscreen.Cursor = *curs; + swload(curs); + cursoron(1); +} + +int +swmove(Point p) +{ + swpt = addpt(p, swoffset); + return 0; +} + +void +swcursorclock(void) +{ + int x; + + if(!swenabled) + return; + swmove(mousexy()); + if(swvisible && eqpt(swpt, swvispt) && swvers==swvisvers) + return; + + x = splhi(); + if(swenabled) + if(!swvisible || !eqpt(swpt, swvispt) || swvers!=swvisvers) + if(canqlock(&drawlock)){ + swcursorhide(); + swcursordraw(); + qunlock(&drawlock); + } + splx(x); +} + +void +swcursorinit(void) +{ + static int init; + + if(!init){ + init = 1; + addclock0link(swcursorclock, 10); + } + if(swback){ + freememimage(swback); + freememimage(swmask); + freememimage(swmask1); + freememimage(swimg); + freememimage(swimg1); + } + + swback = allocmemimage(Rect(0,0,32,32), gscreen->chan); + swmask = allocmemimage(Rect(0,0,16,16), GREY8); + swmask1 = allocmemimage(Rect(0,0,16,16), GREY1); + swimg = allocmemimage(Rect(0,0,16,16), GREY8); + swimg1 = allocmemimage(Rect(0,0,16,16), GREY1); + if(swback==nil || swmask==nil || swmask1==nil || swimg==nil || swimg1 == nil){ + print("software cursor: allocmemimage fails\n"); + return; + } + + memfillcolor(swmask, DOpaque); + memfillcolor(swmask1, DOpaque); + memfillcolor(swimg, DBlack); + memfillcolor(swimg1, DBlack); +} + +/* called from main and possibly later from devdss to change resolution */ +void +screeninit(void) +{ + static int first = 1; + + if (first) { + iprint("screeninit..."); + oscreen.settings = &settings[Res1280x1024]; + + lcdstop(); + if (framebuf) + free(framebuf); + /* mode is 16*32 = 512 */ + framebuf = xspanalloc(sizeof *framebuf, 16*32, 0); + } + + lcdinit(); + lcdon(1); + if (first) { + memimageinit(); + memdefont = getmemdefont(); + screentest(); + } + + xgdata.ref = 1; + xgdata.bdata = (uchar *)framebuf->pixel; + + gscreen = &xgscreen; + gscreen->r = Rect(0, 0, Wid, Ht); + gscreen->clipr = gscreen->r; + /* width, in words, of a single scan line */ + gscreen->width = Wid * (Depth / BI2BY) / BY2WD; + flushmemscreen(gscreen->r); + + blanktime = 3; /* minutes */ + + if (first) { + iprint("on: blue for 3 seconds..."); + delay(3*1000); + iprint("\n"); + + screenwin(); /* draw border & top orange bar */ + screenputs = omapscreenputs; + iprint("screen: frame buffer at %#p for %dx%d\n", + framebuf, oscreen.settings->wid, oscreen.settings->ht); + + swenabled = 1; + swcursorinit(); /* needs gscreen set */ + setcursor(&arrow); + + first = 0; + } +} + +/* flushmemscreen should change buffer? */ +void +flushmemscreen(Rectangle r) +{ + ulong start, end; + + if (r.min.x < 0) + r.min.x = 0; + if (r.max.x > Wid) + r.max.x = Wid; + if (r.min.y < 0) + r.min.y = 0; + if (r.max.y > Ht) + r.max.y = Ht; + if (rectclip(&r, gscreen->r) == 0) + return; + start = (ulong)&framebuf->pixel[r.min.y*Wid + r.min.x]; + end = (ulong)&framebuf->pixel[(r.max.y - 1)*Wid + r.max.x -1]; + cachedwbse((ulong *)start, end - start); +} + +/* + * export screen to devdraw + */ +uchar* +attachscreen(Rectangle *r, ulong *chan, int *d, int *width, int *softscreen) +{ + *r = gscreen->r; + *d = gscreen->depth; + *chan = gscreen->chan; + *width = gscreen->width; + *softscreen = (landscape == 0); + return (uchar *)gscreen->data->bdata; +} + +void +getcolor(ulong p, ulong *pr, ulong *pg, ulong *pb) +{ + USED(p, pr, pg, pb); +} + +int +setcolor(ulong p, ulong r, ulong g, ulong b) +{ + USED(p, r, g, b); + return 0; +} + +void +blankscreen(int blank) +{ + if (blank) + lcdon(0); + else { + lcdinit(); + lcdon(1); + } +} + +static void +omapscreenputs(char *s, int n) +{ + int i; + Rune r; + char buf[4]; + + if (!islo()) { + /* don't deadlock trying to print in interrupt */ + if (!canlock(&screenlock)) + return; /* discard s */ + } else + lock(&screenlock); + + while (n > 0) { + i = chartorune(&r, s); + if (i == 0) { + s++; + --n; + continue; + } + memmove(buf, s, i); + buf[i] = 0; + n -= i; + s += i; + screenputc(buf); + } + unlock(&screenlock); +} + +static void +screenwin(void) +{ + char *greet; + Memimage *orange; + Point p, q; + Rectangle r; + + memsetchan(gscreen, RGB16); + + back = memwhite; + conscol = memblack; + + orange = allocmemimage(Rect(0, 0, 1, 1), RGB16); + orange->flags |= Frepl; + orange->clipr = gscreen->r; + orange->data->bdata[0] = 0x40; /* magic: colour? */ + orange->data->bdata[1] = 0xfd; /* magic: colour? */ + + w = memdefont->info[' '].width; + h = memdefont->height; + + r = insetrect(gscreen->r, 4); + + memimagedraw(gscreen, r, memblack, ZP, memopaque, ZP, S); + window = insetrect(r, 4); + memimagedraw(gscreen, window, memwhite, ZP, memopaque, ZP, S); + + memimagedraw(gscreen, Rect(window.min.x, window.min.y, + window.max.x, window.min.y + h + 5 + 6), orange, ZP, nil, ZP, S); + freememimage(orange); + window = insetrect(window, 5); + + greet = " Plan 9 Console "; + p = addpt(window.min, Pt(10, 0)); + q = memsubfontwidth(memdefont, greet); + memimagestring(gscreen, p, conscol, ZP, memdefont, greet); + flushmemscreen(r); + window.min.y += h + 6; + curpos = window.min; + window.max.y = window.min.y + ((window.max.y - window.min.y) / h) * h; +} + +static void +scroll(void) +{ + int o; + Point p; + Rectangle r; + + /* move window contents up Scroll text lines */ + o = Scroll * h; + r = Rpt(window.min, Pt(window.max.x, window.max.y - o)); + p = Pt(window.min.x, window.min.y + o); + memimagedraw(gscreen, r, gscreen, p, nil, p, S); + flushmemscreen(r); + + /* clear the bottom Scroll text lines */ + r = Rpt(Pt(window.min.x, window.max.y - o), window.max); + memimagedraw(gscreen, r, back, ZP, nil, ZP, S); + flushmemscreen(r); + + curpos.y -= o; +} + +static void +screenputc(char *buf) +{ + int w; + uint pos; + Point p; + Rectangle r; + static int *xp; + static int xbuf[256]; + + if (xp < xbuf || xp >= &xbuf[sizeof(xbuf)]) + xp = xbuf; + + switch (buf[0]) { + case '\n': + if (curpos.y + h >= window.max.y) + scroll(); + curpos.y += h; + screenputc("\r"); + break; + case '\r': + xp = xbuf; + curpos.x = window.min.x; + break; + case '\t': + p = memsubfontwidth(memdefont, " "); + w = p.x; + if (curpos.x >= window.max.x - Tabstop * w) + screenputc("\n"); + + pos = (curpos.x - window.min.x) / w; + pos = Tabstop - pos % Tabstop; + *xp++ = curpos.x; + r = Rect(curpos.x, curpos.y, curpos.x + pos * w, curpos.y + h); + memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S); + flushmemscreen(r); + curpos.x += pos * w; + break; + case '\b': + if (xp <= xbuf) + break; + xp--; + r = Rect(*xp, curpos.y, curpos.x, curpos.y + h); + memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S); + flushmemscreen(r); + curpos.x = *xp; + break; + case '\0': + break; + default: + p = memsubfontwidth(memdefont, buf); + w = p.x; + + if (curpos.x >= window.max.x - w) + screenputc("\n"); + + *xp++ = curpos.x; + r = Rect(curpos.x, curpos.y, curpos.x + w, curpos.y + h); + memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S); + memimagestring(gscreen, curpos, conscol, ZP, memdefont, buf); + flushmemscreen(r); + curpos.x += w; + } +} |