forked from KolibriOS/kolibrios
455 lines
9.4 KiB
C
455 lines
9.4 KiB
C
|
#include "pxa255_LCD.h"
|
||
|
#include "mem.h"
|
||
|
|
||
|
|
||
|
|
||
|
#define LCD_IMAGE "LCD.bmp"
|
||
|
#define UNMASKABLE_INTS 0x7C8E
|
||
|
|
||
|
|
||
|
static void pxa255lcdPrvUpdateInts(Pxa255lcd* lcd){
|
||
|
|
||
|
UInt16 ints = lcd->lcsr & lcd->intMask;
|
||
|
|
||
|
if((ints && !lcd->intWasPending) || (!ints && lcd->intWasPending)){
|
||
|
|
||
|
lcd->intWasPending = !!ints;
|
||
|
pxa255icInt(lcd->ic, PXA255_I_LCD, !!ints);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static Boolean pxa255lcdPrvMemAccessF(void* userData, UInt32 pa, UInt8 size, Boolean write, void* buf){
|
||
|
|
||
|
Pxa255lcd* lcd = userData;
|
||
|
UInt32 val = 0;
|
||
|
UInt16 v16;
|
||
|
|
||
|
if(size != 4) {
|
||
|
err_str(__FILE__ ": Unexpected ");
|
||
|
// err_str(write ? "write" : "read");
|
||
|
// err_str(" of ");
|
||
|
// err_dec(size);
|
||
|
// err_str(" bytes to 0x");
|
||
|
// err_hex(pa);
|
||
|
// err_str("\r\n");
|
||
|
return true; //we do not support non-word accesses
|
||
|
}
|
||
|
|
||
|
pa = (pa - PXA255_LCD_BASE) >> 2;
|
||
|
|
||
|
if(write){
|
||
|
val = *(UInt32*)buf;
|
||
|
|
||
|
switch(pa){
|
||
|
case 0:
|
||
|
if((lcd->lccr0 ^ val) & 0x0001){ //something changed about enablement - handle it
|
||
|
|
||
|
lcd->enbChanged = 1;
|
||
|
}
|
||
|
lcd->lccr0 = val;
|
||
|
//recalc intMask
|
||
|
v16 = UNMASKABLE_INTS;
|
||
|
if(val & 0x00200000UL){ //output fifo underrun
|
||
|
v16 |= 0x0040;
|
||
|
}
|
||
|
if(val & 0x00100000UL){ //branch int
|
||
|
v16 |= 0x0200;
|
||
|
}
|
||
|
if(val & 0x00000400UL){ //quick disable
|
||
|
v16 |= 0x0001;
|
||
|
}
|
||
|
if(val & 0x00000040UL){ //end of frame
|
||
|
v16 |= 0x0080;
|
||
|
}
|
||
|
if(val & 0x00000020UL){ //input fifo underrun
|
||
|
v16 |= 0x0030;
|
||
|
}
|
||
|
if(val & 0x00000010UL){ //start of frame
|
||
|
v16 |= 0x0002;
|
||
|
}
|
||
|
lcd->intMask = v16;
|
||
|
pxa255lcdPrvUpdateInts(lcd);
|
||
|
break;
|
||
|
|
||
|
case 1:
|
||
|
lcd->lccr1 = val;
|
||
|
break;
|
||
|
|
||
|
case 2:
|
||
|
lcd->lccr2 = val;
|
||
|
break;
|
||
|
|
||
|
case 3:
|
||
|
lcd->lccr3 = val;
|
||
|
break;
|
||
|
|
||
|
case 8:
|
||
|
lcd->fbr0 = val;
|
||
|
break;
|
||
|
|
||
|
case 9:
|
||
|
lcd->fbr1 = val;
|
||
|
break;
|
||
|
|
||
|
case 14:
|
||
|
lcd->lcsr &=~ val;
|
||
|
pxa255lcdPrvUpdateInts(lcd);
|
||
|
break;
|
||
|
|
||
|
case 15:
|
||
|
lcd->liicr = val;
|
||
|
break;
|
||
|
|
||
|
case 16:
|
||
|
lcd->trgbr = val;
|
||
|
break;
|
||
|
|
||
|
case 17:
|
||
|
lcd->tcr = val;
|
||
|
break;
|
||
|
|
||
|
case 128:
|
||
|
lcd->fdadr0 = val;
|
||
|
break;
|
||
|
|
||
|
case 132:
|
||
|
lcd->fdadr1 = val;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else{
|
||
|
switch(pa){
|
||
|
case 0:
|
||
|
val = lcd->lccr0;
|
||
|
break;
|
||
|
|
||
|
case 1:
|
||
|
val = lcd->lccr1;
|
||
|
break;
|
||
|
|
||
|
case 2:
|
||
|
val = lcd->lccr2;
|
||
|
break;
|
||
|
|
||
|
case 3:
|
||
|
val = lcd->lccr3;
|
||
|
break;
|
||
|
|
||
|
case 8:
|
||
|
val = lcd->fbr0;
|
||
|
break;
|
||
|
|
||
|
case 9:
|
||
|
val = lcd->fbr1;
|
||
|
break;
|
||
|
|
||
|
case 14:
|
||
|
val = lcd->lcsr;
|
||
|
break;
|
||
|
|
||
|
case 15:
|
||
|
val = lcd->liicr;
|
||
|
break;
|
||
|
|
||
|
case 16:
|
||
|
val = lcd->trgbr;
|
||
|
break;
|
||
|
|
||
|
case 17:
|
||
|
val = lcd->tcr;
|
||
|
break;
|
||
|
|
||
|
case 128:
|
||
|
val = lcd->fdadr0;
|
||
|
break;
|
||
|
|
||
|
case 129:
|
||
|
val = lcd->fsadr0;
|
||
|
break;
|
||
|
|
||
|
case 130:
|
||
|
val = lcd->fidr0;
|
||
|
break;
|
||
|
|
||
|
case 131:
|
||
|
val = lcd->ldcmd0;
|
||
|
break;
|
||
|
|
||
|
case 132:
|
||
|
val = lcd->fdadr1;
|
||
|
break;
|
||
|
|
||
|
case 133:
|
||
|
val = lcd->fsadr1;
|
||
|
break;
|
||
|
|
||
|
case 134:
|
||
|
val = lcd->fidr1;
|
||
|
break;
|
||
|
|
||
|
case 135:
|
||
|
val = lcd->ldcmd1;
|
||
|
break;
|
||
|
}
|
||
|
*(UInt32*)buf = val;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
static UInt32 pxa255PrvGetWord(Pxa255lcd* lcd, UInt32 addr){
|
||
|
|
||
|
UInt32 v;
|
||
|
|
||
|
if(!memAccess(lcd->mem, addr, 4, false, &v)) return 0;
|
||
|
|
||
|
return v;
|
||
|
}
|
||
|
|
||
|
static void pxa255LcdPrvDma(Pxa255lcd* lcd, void* dest, UInt32 addr, UInt32 len){
|
||
|
|
||
|
UInt32 t;
|
||
|
UInt8* d = dest;
|
||
|
|
||
|
//we assume aligntment here both on part of dest and of addr
|
||
|
|
||
|
while(len){
|
||
|
|
||
|
t = pxa255PrvGetWord(lcd, addr);
|
||
|
if(len--) *d++ = t;
|
||
|
if(len--) *d++ = t >> 8;
|
||
|
if(len--) *d++ = t >> 16;
|
||
|
if(len--) *d++ = t >> 24;
|
||
|
addr += 4;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#ifndef EMBEDDED
|
||
|
#include <stdio.h>
|
||
|
|
||
|
static _INLINE_ void pxa255LcdScreenDataPixel(Pxa255lcd* lcd, UInt8* buf){
|
||
|
|
||
|
UInt8 r, g, b;
|
||
|
const UInt32 W = 640;
|
||
|
const UInt32 H = 480;
|
||
|
|
||
|
b = buf[0] << 3;
|
||
|
r = buf[1] & 0xF8;
|
||
|
g = (buf[1] << 5) | ((buf[0] >> 3) & 0x1C);
|
||
|
|
||
|
{
|
||
|
static UInt32 pn = 0;
|
||
|
static FILE* bmp = NULL;
|
||
|
|
||
|
if(pn == 0){
|
||
|
bmp = fopen(LCD_IMAGE, "w+b");
|
||
|
if(bmp){
|
||
|
|
||
|
const UInt32 off = 56;
|
||
|
const UInt32 sz = 320 * 320 * 3 + off;
|
||
|
#define LE32(x) ((int)((x) & 0xFF)), ((int)(((x) >> 8) & 0xFF)), ((int)(((x) >> 16) & 0xFF)), ((int)((x) >> 24))
|
||
|
#define LE16(x) ((int)((x) & 0xFF)), ((int)(((x) >> 8) & 0xFF))
|
||
|
|
||
|
fprintf(bmp, "BM%c%c%c%c%c%c%c%c%c%c%c%c", LE32(sz), LE16(0), LE16(0), LE32(off)); //bitmap file header
|
||
|
fprintf(bmp, "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c", LE32(40), LE32(W), LE32(-H), LE16(1), LE16(24), LE32(0), LE32(W * H * 3), LE32(2835), LE32(2835), LE32(0), LE32(0)); //BITMAPCOREHEADER
|
||
|
fprintf(bmp, "%c%c",0 ,0); //spacer to align bmp data to 4 bytes
|
||
|
|
||
|
#undef LE32
|
||
|
}
|
||
|
}
|
||
|
if(bmp){
|
||
|
|
||
|
fprintf(bmp, "%c%c%c", b, g, r);
|
||
|
}
|
||
|
pn++;
|
||
|
if(pn == W * H){
|
||
|
pn = 0;
|
||
|
if(bmp){
|
||
|
|
||
|
fclose(bmp);
|
||
|
bmp = NULL;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#ifndef PXA255_LCD_SUPPORTS_PALLETES
|
||
|
static void pxa255LcdSetFakePal(UInt8* buf, UInt8 bpp, UInt8 val){
|
||
|
|
||
|
while(bpp++ < 8) val = (val << 1) | (val & 1); //sign extend up (weird but works)
|
||
|
|
||
|
buf[1] = (val & 0xF8) | (val >> 3);
|
||
|
buf[0] = ((val & 0xFC) << 5) | val >> 3;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
static void pxa255LcdScreenDataDma(Pxa255lcd* lcd, UInt32 addr/*PA*/, UInt32 len){
|
||
|
|
||
|
UInt8 data[4];
|
||
|
UInt32 i, j;
|
||
|
void* ptr;
|
||
|
#ifndef PXA255_LCD_SUPPORTS_PALLETES
|
||
|
UInt8 val[2];
|
||
|
#endif
|
||
|
|
||
|
len /= 4;
|
||
|
while(len--){
|
||
|
pxa255LcdPrvDma(lcd, data, addr, 4);
|
||
|
addr += 4;
|
||
|
|
||
|
switch((lcd->lccr3 >> 24) & 7){
|
||
|
|
||
|
case 0: //1BPP
|
||
|
|
||
|
#ifdef PXA255_LCD_SUPPORTS_PALLETES
|
||
|
ptr = lcd->palette + ((data[i] >> j) & 1) * 2;
|
||
|
#else
|
||
|
ptr = val;
|
||
|
pxa255LcdSetFakePal(val, 1, (data[i] >> j) & 1);
|
||
|
#endif
|
||
|
for(i = 0; i < 4; i += 1) for(j = 0; j < 8; j += 1) pxa255LcdScreenDataPixel(lcd, ptr);
|
||
|
break;
|
||
|
|
||
|
case 1: //2BPP
|
||
|
|
||
|
#ifdef PXA255_LCD_SUPPORTS_PALLETES
|
||
|
ptr = lcd->palette + ((data[i] >> j) & 3) * 2;
|
||
|
#else
|
||
|
ptr = val;
|
||
|
pxa255LcdSetFakePal(val, 2, (data[i] >> j) & 3);
|
||
|
#endif
|
||
|
for(i = 0; i < 4; i += 1) for(j = 0; j < 8; j += 2) pxa255LcdScreenDataPixel(lcd, ptr);
|
||
|
break;
|
||
|
|
||
|
case 2: //4BPP
|
||
|
|
||
|
#ifdef PXA255_LCD_SUPPORTS_PALLETES
|
||
|
ptr = lcd->palette + ((data[i] >> j) & 15) * 2;
|
||
|
#else
|
||
|
ptr = val;
|
||
|
pxa255LcdSetFakePal(val, 4, (data[i] >> j) & 15);
|
||
|
#endif
|
||
|
for(i = 0; i < 4; i += 1) for(j = 0; j < 8; j += 4) pxa255LcdScreenDataPixel(lcd, ptr);
|
||
|
break;
|
||
|
|
||
|
case 3: //8BPP
|
||
|
|
||
|
#ifdef PXA255_LCD_SUPPORTS_PALLETES
|
||
|
ptr = lcd->palette + (data[i] * 2);
|
||
|
#else
|
||
|
ptr = val;
|
||
|
pxa255LcdSetFakePal(val, 8, data[i]);
|
||
|
#endif
|
||
|
for(i = 0; i < 4; i += 1) pxa255LcdScreenDataPixel(lcd, ptr);
|
||
|
break;
|
||
|
|
||
|
case 4: //16BPP
|
||
|
|
||
|
for(i = 0; i < 4; i +=2 ) pxa255LcdScreenDataPixel(lcd, data + i);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
|
||
|
;//BAD
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#else
|
||
|
static void pxa255LcdScreenDataDma(Pxa255lcd* lcd, UInt32 addr/*PA*/, UInt32 len){
|
||
|
|
||
|
//nothing
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
void pxa255lcdFrame(Pxa255lcd* lcd){
|
||
|
//every other call starts a frame, the others end one [this generates spacing between interrupts so as to not confuse guest OS]
|
||
|
|
||
|
if(lcd->enbChanged){
|
||
|
|
||
|
if(lcd->lccr0 & 0x0001){ //just got enabled
|
||
|
|
||
|
//TODO: perhaps check settings?
|
||
|
}
|
||
|
else{ // we just got quick disabled - kill current frame and do no more
|
||
|
|
||
|
lcd->lcsr |= 0x0080; //quick disable happened
|
||
|
lcd->state = LCD_STATE_IDLE;
|
||
|
}
|
||
|
lcd->enbChanged = false;
|
||
|
}
|
||
|
|
||
|
if(lcd->lccr0 & 0x0001){ //enabled - do a frame
|
||
|
|
||
|
UInt32 descrAddr, len;
|
||
|
|
||
|
switch(lcd->state){
|
||
|
|
||
|
case LCD_STATE_IDLE:
|
||
|
|
||
|
if(lcd->fbr0 & 1){ //branch
|
||
|
|
||
|
lcd->fbr0 &=~ 1UL;
|
||
|
if(lcd->fbr0 & 2) lcd->lcsr |= 0x0200;
|
||
|
descrAddr = lcd->fbr0 &~ 0xFUL;
|
||
|
} else descrAddr = lcd->fdadr0;
|
||
|
lcd->fdadr0 = pxa255PrvGetWord(lcd, descrAddr + 0);
|
||
|
lcd->fsadr0 = pxa255PrvGetWord(lcd, descrAddr + 4);
|
||
|
lcd->fidr0 = pxa255PrvGetWord(lcd, descrAddr + 8);
|
||
|
lcd->ldcmd0 = pxa255PrvGetWord(lcd, descrAddr + 12);
|
||
|
|
||
|
lcd->state = LCD_STATE_DMA_0_START;
|
||
|
break;
|
||
|
|
||
|
case LCD_STATE_DMA_0_START:
|
||
|
|
||
|
if(lcd->ldcmd0 & 0x00400000UL) lcd->lcsr |= 0x0002; //set SOF is DMA 0 started
|
||
|
len = lcd->ldcmd0 & 0x000FFFFFUL;
|
||
|
|
||
|
if(lcd->ldcmd0 & 0x04000000UL){ //pallette data
|
||
|
|
||
|
#ifdef PXA255_LCD_SUPPORTS_PALLETES
|
||
|
if(len > sizeof(lcd->palette)){
|
||
|
|
||
|
len = sizeof(lcd->palette);
|
||
|
|
||
|
pxa255LcdPrvDma(lcd, lcd->palette, lcd->fsadr0, len);
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
else{
|
||
|
|
||
|
lcd->frameNum++;
|
||
|
if(!(lcd->frameNum & 63)) pxa255LcdScreenDataDma(lcd, lcd->fsadr0, len);
|
||
|
}
|
||
|
|
||
|
lcd->state = LCD_STATE_DMA_0_END;
|
||
|
break;
|
||
|
|
||
|
case LCD_STATE_DMA_0_END:
|
||
|
|
||
|
if(lcd->ldcmd0 & 0x00200000UL) lcd->lcsr |= 0x0100; //set EOF is DMA 0 finished
|
||
|
lcd->state = LCD_STATE_IDLE;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
pxa255lcdPrvUpdateInts(lcd);
|
||
|
}
|
||
|
|
||
|
|
||
|
Boolean pxa255lcdInit(Pxa255lcd* lcd, ArmMem* physMem, Pxa255ic* ic){
|
||
|
|
||
|
|
||
|
__mem_zero(lcd, sizeof(Pxa255lcd));
|
||
|
|
||
|
lcd->ic = ic;
|
||
|
lcd->mem = physMem;
|
||
|
lcd->intMask = UNMASKABLE_INTS;
|
||
|
|
||
|
return memRegionAdd(physMem, PXA255_LCD_BASE, PXA255_LCD_SIZE, pxa255lcdPrvMemAccessF, lcd);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|