📄 overlay_xscale.c
字号:
/*****************************************************************************
*
* This program is free software ; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* $Id: overlay_xscale.c 615 2006-01-26 16:57:51Z picard $
*
* The Core Pocket Media Player
* Copyright (c) 2004-2005 Gabor Kovacs
*
****************************************************************************/
#include "../common.h"
#define X50V // included in official version
#if defined(ARM)
#define WIN32_LEAN_AND_MEAN
#ifndef STRICT
#define STRICT
#endif
#include <windows.h>
#define MAXDESC 1024
#define MAXORIGBLOCK 8
#define MAXCOUNT 3
#define MAXDESCBLOCK 4
typedef struct xscaledesc
{
uint32_t Next;
uint32_t Base;
uint32_t Id;
uint32_t Cmd;
} xscaledesc;
typedef struct xscaledriver
{
node Node;
int Width;
int Height;
int BufferSize;
int MaxBlock;
bool_t AllocAtStart;
bool_t SetupFlip;
bool_t SetupStretch;
bool_t InAlloc;
bool_t AtStart;
struct xscale* Used;
int DescPhyCount[MAXCOUNT];
phymemblock DescPhy[MAXCOUNT][MAXDESCBLOCK];
xscaledesc* Desc[MAXCOUNT];
xscaledesc* DescLast[MAXCOUNT];
int* Map;
int BufferPhyCount[MAXCOUNT];
phymemblock* BufferPhy; // [MAXCOUNT][MaxBlock]
void* Buffer[MAXCOUNT];
int Count;
#ifdef X50V
uint32_t* GPIO;
uint32_t* Marathon;
bool_t X50v;
#endif
uint32_t* Regs;
uint32_t OrigDescPhy[MAXORIGBLOCK];
phymemblock OrigBufferPhy[MAXORIGBLOCK];
int OrigDescCount;
void* OrigBuffer;
int OrigBufferSize;
xscaledesc* OrigDescEnd;
bool_t OrigDescEndSet;
bool_t NotOrig;
} xscaledriver;
typedef struct xscale
{
overlay Overlay;
xscaledriver* Driver;
bool_t Flip;
int Next;
} xscale;
#define MAGIC 0xBABE0000
#define GPIO_BASE 0x40E00000
#define GPIO_SIZE 0x1000
#define LCD_BASE 0x44000000
#define LCD_SIZE 0x1000
#define LCCR0 (0x000/4)
#define LCCR1 (0x004/4)
#define LCCR2 (0x008/4)
#define LCCR3 (0x00C/4)
#define LCCR4 (0x010/4)
#define LCCR5 (0x014/4)
#define LCSR0 (0x038/4)
#define LCSR1 (0x034/4)
#define FBR0 (0x020/4)
#define FDADR0 (0x200/4)
#define FSADR0 (0x204/4)
#define FIDR0 (0x208/4)
#define GAFR1_U (0x060/4)
#define GAFR2_L (0x064/4)
#define LCD_CONFIG (0x03fe0060/4)
static void FreeOrig(xscaledriver* p)
{
int n;
// be sure that the old orig is not referenced by the buffers
for (n=0;n<p->Count;++n)
p->DescLast[n]->Next = p->DescPhy[n]->Addr;
// restore and release end descriptor
if (p->OrigDescEnd)
{
if (p->OrigDescEndSet)
{
p->OrigDescEnd->Next = p->OrigDescPhy[0];
p->OrigDescEndSet = 0;
}
PhyMemEnd(p->OrigDescEnd);
p->OrigDescEnd = NULL;
}
// release framebuffer
if (p->OrigBuffer)
{
PhyMemEnd(p->OrigBuffer);
p->OrigBuffer = NULL;
}
p->OrigDescCount = 0;
p->OrigBufferSize = 0;
p->NotOrig = 0;
}
static void GetOrig(xscaledriver* p)
{
uint32_t DescPhy[MAXORIGBLOCK]; // original descriptor head
xscaledesc Desc[MAXORIGBLOCK];
uint32_t Phy;
#ifdef X50V
if (p->X50v)
{
// create a fake desc chain with SRAM usage (like Loox720)
/*
int Left = 640*480*2 - 256*1024;
phymemblock Block2;
phymemblock Block;
int One = 1;
xscaledesc* d = (xscaledesc*) PhyMemAlloc(sizeof(xscaledesc)*2,&Block,&One);
if (!d)
return;
One = 1;
if (!PhyMemAlloc(Left,&Block2,&One))
return;
d[0].Base = Block2.Addr;
d[0].Cmd = Block2.Length;
d[0].Id = 0;
d[0].Next = Block.Addr + sizeof(xscaledesc);
d[1].Base = 0x5C000000;
d[1].Cmd = 256*1024 | (1<<21);
d[1].Id = 0;
d[1].Next = Block.Addr;
Phy = Block.Addr;
*/
Phy = 0;
}
else
#endif
{
Phy = p->Regs[FDADR0] & ~15;
p->Width = (p->Regs[LCCR1] & 1023)+1;
p->Height = (p->Regs[LCCR2] & 1023)+1;
}
if (Phy)
{
int n,m;
FreeOrig(p);
for (n=0;n<MAXORIGBLOCK;)
{
xscaledesc* d = (xscaledesc*) PhyMemBegin(Phy,sizeof(xscaledesc),0);
if (!d)
break;
DescPhy[n] = Phy;
Desc[n] = *d;
DEBUG_MSG4(-1,T("XScale %08x (%08x %08x %08x)"),Phy,Desc[n].Base,Desc[n].Cmd,Desc[n].Next);
++n;
Phy = d->Next & ~15;
PhyMemEnd(d);
for (m=0;m<n;++m)
if (DescPhy[m] == Phy)
{
int i,j;
if (n-m>1) // need to find end
{
for (i=m;i<n;++i)
if (Desc[i].Cmd & (1<<21))
{
++i;
if (i==n) i=m;
break;
}
if (i==n)
return; // failed
}
else
i=m; // there is only one desc
j=i;
do
{
p->OrigDescPhy[p->OrigDescCount] = DescPhy[j];
p->OrigBufferPhy[p->OrigDescCount].Addr = Desc[j].Base;
p->OrigBufferPhy[p->OrigDescCount].Length = Desc[j].Cmd & 0x1FFFFF;
p->OrigBufferSize += p->OrigBufferPhy[p->OrigDescCount].Length;
p->OrigDescCount++;
if (++j==n) j=m;
}
while (i!=j);
// map end descriptor so we don't have to use disable/enable for flipping (with multiple desc displays)
p->OrigDescEnd = (xscaledesc*) PhyMemBegin(p->OrigDescPhy[p->OrigDescCount-1],sizeof(xscaledesc),0);
if (p->OrigDescEnd && p->OrigDescEnd->Next != p->OrigDescPhy[0])
{
PhyMemEnd(p->OrigDescEnd);
p->OrigDescEnd = NULL;
}
// reuse original framebuffer
if (p->OrigBufferSize >= p->Width*2*p->Height)
p->OrigBuffer = PhyMemBeginEx(p->OrigBufferPhy,p->OrigDescCount,1);
return;
}
}
}
}
static bool_t FreeBuffer(xscaledriver* p)
{
int n;
if (!p->BufferPhy || p->InAlloc || p->Used)
return 0;
for (n=0;n<p->Count;++n)
{
PhyMemFree(p->Desc[n],p->DescPhy[n],p->DescPhyCount[n]);
if (n>0 || !p->OrigDescCount)
PhyMemFree(p->Buffer[n],p->BufferPhy+p->MaxBlock*n,p->BufferPhyCount[n]);
}
p->Count = 0;
p->MaxBlock = 0;
free(p->Map);
p->Map = NULL;
free(p->BufferPhy);
p->BufferPhy = NULL;
DEBUG_MSG(-1,T("XSCALE Freed"));
return 1;
}
static bool_t AllocBuffer(xscaledriver* p)
{
if (!p->BufferPhy && p->OrigBuffer)
{
int n;
p->BufferSize = (p->Width*2 * p->Height) & ~3;
p->MaxBlock = (p->BufferSize / 4096)+1;
p->BufferPhy = (phymemblock*) malloc(sizeof(phymemblock)*p->MaxBlock*MAXCOUNT);
if (!p->BufferPhy)
return 0;
p->Map = (int*) malloc(sizeof(int)*p->Height);
if (!p->Map)
{
free(p->BufferPhy);
p->BufferPhy = NULL;
return 0;
}
p->InAlloc = 1;
for (n=0;n<(p->SetupFlip?MAXCOUNT:1);++n)
{
// allocate desc table
p->DescPhyCount[n] = MAXDESCBLOCK;
p->Desc[n] = p->DescLast[n] = PhyMemAlloc(MAXDESC*sizeof(xscaledesc),p->DescPhy[n],&p->DescPhyCount[n]);
if (!p->Desc[n])
break;
if (n==0 && p->OrigBufferSize >= p->BufferSize)
{
// use original surface
p->Buffer[n] = p->OrigBuffer;
p->BufferPhyCount[n] = p->OrigDescCount;
memcpy(p->BufferPhy+p->MaxBlock*n,p->OrigBufferPhy,sizeof(phymemblock)*p->OrigDescCount);
}
else
{
// allocate new surface
p->BufferPhyCount[n] = p->MaxBlock;
p->Buffer[n] = PhyMemAlloc(p->BufferSize,p->BufferPhy+p->MaxBlock*n,&p->BufferPhyCount[n]);
}
if (!p->Buffer[n])
{
PhyMemFree(p->Desc[n],p->DescPhy[n],p->DescPhyCount[n]);
break;
}
}
if (n==2)
{
// can't flip chain with 2 surfaces (minimum is 3)
PhyMemFree(p->Desc[1],p->DescPhy[1],p->DescPhyCount[1]);
PhyMemFree(p->Buffer[1],p->BufferPhy+p->MaxBlock*1,p->BufferPhyCount[1]);
--n;
}
p->Count = n;
p->InAlloc = 0;
DEBUG_MSG5(-1,T("XSCALE %d %d %d %d %d"),p->Count,p->BufferPhyCount[0],p->BufferPhyCount[1],p->BufferPhyCount[2],AvailMemory());
}
return 1;
}
static void GetMode(xscale* p)
{
p->Overlay.Output.Format.Video.Width = p->Driver->Width;
p->Overlay.Output.Format.Video.Height = p->Driver->Height;
p->Overlay.Output.Format.Video.Direction = 0;
p->Overlay.Output.Format.Video.Aspect = ASPECT_ONE;
p->Overlay.Output.Format.Video.Pitch = p->Overlay.Output.Format.Video.Width*2;
DefaultRGB(&p->Overlay.Output.Format.Video.Pixel,16,5,6,5,0,0,0);
AdjustOrientation(&p->Overlay.Output.Format.Video,1);
if (p->Overlay.Output.Format.Video.Direction & DIR_SWAPXY)
{
int Model = QueryPlatform(PLATFORM_MODEL);
if (Model == MODEL_IPAQ_H3800 || Model == MODEL_IPAQ_H3900 ||
(Model == MODEL_NOVOGO && QueryPlatform(PLATFORM_VER)<500 && p->Driver->Width==240 && p->Driver->Height==320))
p->Overlay.Output.Format.Video.Direction ^= DIR_MIRRORLEFTRIGHT|DIR_MIRRORUPDOWN;
}
if (!((uint32_t)p->Driver->OrigBuffer & 15))
p->Overlay.Output.Format.Video.Pixel.Flags |= PF_16ALIGNED;
}
static int Init(xscale* p)
{
if (!p->Driver->OrigBuffer)
{
GetOrig(p->Driver);
if (!p->Driver->OrigBuffer)
return ERR_NOT_SUPPORTED;
}
GetMode(p);
p->Next = 0;
p->Flip = 0;
p->Overlay.SetFX = BLITFX_AVOIDTEARING;
if (p->Driver->Used)
return ERR_DEVICE_ERROR;
p->Driver->Used = p;
if (!AllocBuffer(p->Driver))
return ERR_OUT_OF_MEMORY;
if (p->Driver->Count >= 3)
p->Overlay.ClearFX = BLITFX_ONLYDIFF;
return ERR_NONE;
}
static void QuickDisable(xscaledriver* p)
{
int n = p->Regs[LCCR0];
n &= ~(1<<10); //DIS
n &= ~1; //ENB
p->Regs[LCCR0] = n;
Sleep(1);
}
static void Disable(xscaledriver* p)
{
int i;
int n = p->Regs[LCCR0];
if (n & 1)
{
n |= 1<<10; //DIS
p->Regs[LCCR0] = n;
for (i=0;i<30;++i)
{
if (!(p->Regs[LCCR0] & 1))
break;
Sleep(1);
}
if (i==30)
QuickDisable(p);
}
}
static void Enable(xscaledriver* p)
{
int n = p->Regs[LCCR0];
n &= ~(1<<10); //DIS
n |= 1; //EN;
p->Regs[LCCR0] = n;
Sleep(1);
}
static int GetCurrent2(xscaledriver* p)
{
int n;
int Id = p->Regs[FIDR0] & ~15;
uint32_t Phy = p->Regs[FDADR0] & ~15;
if ((Id & 0xFFFF0000) == MAGIC)
return (Id >> 4) & 0xFF;
for (n=0;n<p->OrigDescCount;++n)
if (Phy == p->OrigDescPhy[n] || Phy == p->OrigDescPhy[n]+sizeof(xscaledesc))
return -1;
return -2; // unknown
}
static int GetCurrent(xscaledriver* p)
{
int Current;
if (!(p->Regs[LCCR0] & 1))
return -2; // turned off lcd
Current = GetCurrent2(p);
if (Current >= -1)
return Current;
Sleep(50); // original desc chain has changed. maybe it's just temporary
Current = GetCurrent2(p);
if (Current >= -1)
return Current;
GetOrig(p); // reread original desc chain
return GetCurrent2(p);
}
#ifdef X50V
static void X50vDisable(xscaledriver* p)
{
if (p->Marathon[LCD_CONFIG] & (1<<16))
{
uint32_t v;
while ((v = p->Marathon[LCD_CONFIG]) & (1<<16))
p->Marathon[LCD_CONFIG] = v & ~0x1000A;
Disable(p);
v = p->GPIO[GAFR1_U];
if (v & 0xFFF00000)
p->GPIO[GAFR1_U] = v & 0xFFFFF;
v = p->GPIO[GAFR2_L];
if (v & 0xFFFFFFF)
p->GPIO[GAFR2_L] = v & 0xF0000000;
}
}
static bool_t X50vEnable(xscaledriver* p,uint32_t Desc)
{
bool_t Changed = 0;
if (!(p->Marathon[LCD_CONFIG] & (1<<16)))
{
uint32_t v;
Changed = 1;
Disable(p);
p->Regs[LCCR0] = 0x1B008F8;
p->Regs[LCCR1] = 0x1056FDDF;
p->Regs[LCCR2] = 0x104067F;
p->Regs[LCCR3] = 0x4f00001;
p->Regs[LCCR4] = 0;
p->Regs[LCCR5] = 0x3F3F3F3F;
p->Regs[FDADR0] = 0;
p->Regs[LCSR0] = 0;
v = p->GPIO[GAFR1_U];
if ((v & 0xFFF00000) != 0xAAA00000)
p->GPIO[GAFR1_U] = (v & 0xFFFFF) | 0xAAA00000;
v = p->GPIO[GAFR2_L];
if ((v & 0xFFFFFFF) != 0xAAAAAAA)
p->GPIO[GAFR2_L] = (v & 0xF0000000) | 0xAAAAAAA;
p->Regs[FDADR0] = Desc;
Enable(p);
QuickDisable(p);
p->Regs[FDADR0] = Desc;
Enable(p);
while (!((v = p->Marathon[LCD_CONFIG]) & (1<<16)))
{
p->Marathon[LCD_CONFIG] = v | 0x1000A;
Sleep(1);
}
}
return Changed;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -