From 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sat, 16 Apr 2005 15:20:36 -0700 Subject: Linux-2.6.12-rc2 Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip! --- drivers/video/kyro/Makefile | 8 + drivers/video/kyro/STG4000InitDevice.c | 326 ++++++++++++ drivers/video/kyro/STG4000Interface.h | 60 +++ drivers/video/kyro/STG4000OverlayDevice.c | 600 ++++++++++++++++++++++ drivers/video/kyro/STG4000Ramdac.c | 163 ++++++ drivers/video/kyro/STG4000Reg.h | 283 +++++++++++ drivers/video/kyro/STG4000VTG.c | 170 +++++++ drivers/video/kyro/fbdev.c | 820 ++++++++++++++++++++++++++++++ 8 files changed, 2430 insertions(+) create mode 100644 drivers/video/kyro/Makefile create mode 100644 drivers/video/kyro/STG4000InitDevice.c create mode 100644 drivers/video/kyro/STG4000Interface.h create mode 100644 drivers/video/kyro/STG4000OverlayDevice.c create mode 100644 drivers/video/kyro/STG4000Ramdac.c create mode 100644 drivers/video/kyro/STG4000Reg.h create mode 100644 drivers/video/kyro/STG4000VTG.c create mode 100644 drivers/video/kyro/fbdev.c (limited to 'drivers/video/kyro') diff --git a/drivers/video/kyro/Makefile b/drivers/video/kyro/Makefile new file mode 100644 index 00000000000..2fd66f551ba --- /dev/null +++ b/drivers/video/kyro/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for the Kyro framebuffer driver +# + +obj-$(CONFIG_FB_KYRO) += kyrofb.o + +kyrofb-objs := STG4000Ramdac.o STG4000VTG.o STG4000OverlayDevice.o \ + STG4000InitDevice.o fbdev.o diff --git a/drivers/video/kyro/STG4000InitDevice.c b/drivers/video/kyro/STG4000InitDevice.c new file mode 100644 index 00000000000..7e33cd307d4 --- /dev/null +++ b/drivers/video/kyro/STG4000InitDevice.c @@ -0,0 +1,326 @@ +/* + * linux/drivers/video/kyro/STG4000InitDevice.c + * + * Copyright (C) 2000 Imagination Technologies Ltd + * Copyright (C) 2002 STMicroelectronics + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#include +#include +#include +#include + +#include "STG4000Reg.h" + +/* SDRAM fixed settings */ +#define SDRAM_CFG_0 0x49A1 +#define SDRAM_CFG_1 0xA732 +#define SDRAM_CFG_2 0x31 +#define SDRAM_ARB_CFG 0xA0 +#define SDRAM_REFRESH 0x20 + +/* Reset values */ +#define PMX2_SOFTRESET_DAC_RST 0x0001 +#define PMX2_SOFTRESET_C1_RST 0x0004 +#define PMX2_SOFTRESET_C2_RST 0x0008 +#define PMX2_SOFTRESET_3D_RST 0x0010 +#define PMX2_SOFTRESET_VIDIN_RST 0x0020 +#define PMX2_SOFTRESET_TLB_RST 0x0040 +#define PMX2_SOFTRESET_SD_RST 0x0080 +#define PMX2_SOFTRESET_VGA_RST 0x0100 +#define PMX2_SOFTRESET_ROM_RST 0x0200 /* reserved bit, do not reset */ +#define PMX2_SOFTRESET_TA_RST 0x0400 +#define PMX2_SOFTRESET_REG_RST 0x4000 +#define PMX2_SOFTRESET_ALL 0x7fff + +/* Core clock freq */ +#define CORE_PLL_FREQ 1000000 + +/* Reference Clock freq */ +#define REF_FREQ 14318 + +/* PCI Registers */ +static u16 CorePllControl = 0x70; + +#define PCI_CONFIG_SUBSYS_ID 0x2e + +/* Misc */ +#define CORE_PLL_MODE_REG_0_7 3 +#define CORE_PLL_MODE_REG_8_15 2 +#define CORE_PLL_MODE_CONFIG_REG 1 +#define DAC_PLL_CONFIG_REG 0 + +#define STG_MAX_VCO 500000 +#define STG_MIN_VCO 100000 + +/* PLL Clock */ +#define STG4K3_PLL_SCALER 8 /* scale numbers by 2^8 for fixed point calc */ +#define STG4K3_PLL_MIN_R 2 /* Minimum multiplier */ +#define STG4K3_PLL_MAX_R 33 /* Max */ +#define STG4K3_PLL_MIN_F 2 /* Minimum divisor */ +#define STG4K3_PLL_MAX_F 513 /* Max */ +#define STG4K3_PLL_MIN_OD 0 /* Min output divider (shift) */ +#define STG4K3_PLL_MAX_OD 2 /* Max */ +#define STG4K3_PLL_MIN_VCO_SC (100000000 >> STG4K3_PLL_SCALER) /* Min VCO rate */ +#define STG4K3_PLL_MAX_VCO_SC (500000000 >> STG4K3_PLL_SCALER) /* Max VCO rate */ +#define STG4K3_PLL_MINR_VCO_SC (100000000 >> STG4K3_PLL_SCALER) /* Min VCO rate (restricted) */ +#define STG4K3_PLL_MAXR_VCO_SC (500000000 >> STG4K3_PLL_SCALER) /* Max VCO rate (restricted) */ +#define STG4K3_PLL_MINR_VCO 100000000 /* Min VCO rate (restricted) */ +#define STG4K3_PLL_MAX_VCO 500000000 /* Max VCO rate */ +#define STG4K3_PLL_MAXR_VCO 500000000 /* Max VCO rate (restricted) */ + +#define OS_DELAY(X) \ +{ \ +volatile u32 i,count=0; \ + for(i=0;i> 4; + dwChipSpeedIdx = (dwSubSysID & 0x180) >> 7; + + if (dwMemTypeIdx > 4 || dwChipSpeedIdx > 2) + return 0; + + /* Program SD-RAM interface */ + STG_WRITE_REG(SDRAMArbiterConf, adwSDRAMArgCfg0[dwMemTypeIdx]); + if (dwRevID < 5) { + STG_WRITE_REG(SDRAMConf0, 0x49A1); + STG_WRITE_REG(SDRAMConf1, adwSDRAMCfg1[dwMemTypeIdx]); + } else { + STG_WRITE_REG(SDRAMConf0, 0x4DF1); + STG_WRITE_REG(SDRAMConf1, adwSDRAMCfg2[dwMemTypeIdx]); + } + + STG_WRITE_REG(SDRAMConf2, 0x31); + STG_WRITE_REG(SDRAMRefresh, adwSDRAMRsh[dwChipSpeedIdx]); + + return adwChipSpeed[dwChipSpeedIdx] * 10000; +} + +u32 ProgramClock(u32 refClock, + u32 coreClock, + u32 * FOut, u32 * ROut, u32 * POut) +{ + u32 R = 0, F = 0, OD = 0, ODIndex = 0; + u32 ulBestR = 0, ulBestF = 0, ulBestOD = 0; + u32 ulBestVCO = 0, ulBestClk = 0, ulBestScore = 0; + u32 ulScore, ulPhaseScore, ulVcoScore; + u32 ulTmp = 0, ulVCO; + u32 ulScaleClockReq, ulMinClock, ulMaxClock; + u32 ODValues[] = { 1, 2, 0 }; + + /* Translate clock in Hz */ + coreClock *= 100; /* in Hz */ + refClock *= 1000; /* in Hz */ + + /* Work out acceptable clock + * The method calculates ~ +- 0.4% (1/256) + */ + ulMinClock = coreClock - (coreClock >> 8); + ulMaxClock = coreClock + (coreClock >> 8); + + /* Scale clock required for use in calculations */ + ulScaleClockReq = coreClock >> STG4K3_PLL_SCALER; + + /* Iterate through post divider values */ + for (ODIndex = 0; ODIndex < 3; ODIndex++) { + OD = ODValues[ODIndex]; + R = STG4K3_PLL_MIN_R; + + /* loop for pre-divider from min to max */ + while (R <= STG4K3_PLL_MAX_R) { + /* estimate required feedback multiplier */ + ulTmp = R * (ulScaleClockReq << OD); + + /* F = ClkRequired * R * (2^OD) / Fref */ + F = (u32)(ulTmp / (refClock >> STG4K3_PLL_SCALER)); + + /* compensate for accuracy */ + if (F > STG4K3_PLL_MIN_F) + F--; + + + /* + * We should be close to our target frequency (if it's + * achievable with current OD & R) let's iterate + * through F for best fit + */ + while ((F >= STG4K3_PLL_MIN_F) && + (F <= STG4K3_PLL_MAX_F)) { + /* Calc VCO at full accuracy */ + ulVCO = refClock / R; + ulVCO = F * ulVCO; + + /* + * Check it's within restricted VCO range + * unless of course the desired frequency is + * above the restricted range, then test + * against VCO limit + */ + if ((ulVCO >= STG4K3_PLL_MINR_VCO) && + ((ulVCO <= STG4K3_PLL_MAXR_VCO) || + ((coreClock > STG4K3_PLL_MAXR_VCO) + && (ulVCO <= STG4K3_PLL_MAX_VCO)))) { + ulTmp = (ulVCO >> OD); /* Clock = VCO / (2^OD) */ + + /* Is this clock good enough? */ + if ((ulTmp >= ulMinClock) + && (ulTmp <= ulMaxClock)) { + ulPhaseScore = (((refClock / R) - (refClock / STG4K3_PLL_MAX_R))) / ((refClock - (refClock / STG4K3_PLL_MAX_R)) >> 10); + + ulVcoScore = ((ulVCO - STG4K3_PLL_MINR_VCO)) / ((STG4K3_PLL_MAXR_VCO - STG4K3_PLL_MINR_VCO) >> 10); + ulScore = ulPhaseScore + ulVcoScore; + + if (!ulBestScore) { + ulBestVCO = ulVCO; + ulBestOD = OD; + ulBestF = F; + ulBestR = R; + ulBestClk = ulTmp; + ulBestScore = + ulScore; + } + /* is this better, ( aim for highest Score) */ + /*-------------------------------------------------------------------------- + Here we want to use a scoring system which will take account of both the + value at the phase comparater and the VCO output + to do this we will use a cumulative score between the two + The way this ends up is that we choose the first value in the loop anyway + but we shall keep this code in case new restrictions come into play + --------------------------------------------------------------------------*/ + if ((ulScore >= ulBestScore) && (OD > 0)) { + ulBestVCO = ulVCO; + ulBestOD = OD; + ulBestF = F; + ulBestR = R; + ulBestClk = ulTmp; + ulBestScore = + ulScore; + } + } + } + F++; + } + R++; + } + } + + /* + did we find anything? + Then return RFOD + */ + if (ulBestScore) { + *ROut = ulBestR; + *FOut = ulBestF; + + if ((ulBestOD == 2) || (ulBestOD == 3)) { + *POut = 3; + } else + *POut = ulBestOD; + + } + + return (ulBestClk); +} + +int SetCoreClockPLL(volatile STG4000REG __iomem *pSTGReg, struct pci_dev *pDev) +{ + u32 F, R, P; + u16 core_pll = 0, sub; + u32 ulCoreClock; + u32 tmp; + u32 ulChipSpeed; + u8 rev; + + STG_WRITE_REG(IntMask, 0xFFFF); + + /* Disable Primary Core Thread0 */ + tmp = STG_READ_REG(Thread0Enable); + CLEAR_BIT(0); + STG_WRITE_REG(Thread0Enable, tmp); + + /* Disable Primary Core Thread1 */ + tmp = STG_READ_REG(Thread1Enable); + CLEAR_BIT(0); + STG_WRITE_REG(Thread1Enable, tmp); + + STG_WRITE_REG(SoftwareReset, + PMX2_SOFTRESET_REG_RST | PMX2_SOFTRESET_ROM_RST); + STG_WRITE_REG(SoftwareReset, + PMX2_SOFTRESET_REG_RST | PMX2_SOFTRESET_TA_RST | + PMX2_SOFTRESET_ROM_RST); + + /* Need to play around to reset TA */ + STG_WRITE_REG(TAConfiguration, 0); + STG_WRITE_REG(SoftwareReset, + PMX2_SOFTRESET_REG_RST | PMX2_SOFTRESET_ROM_RST); + STG_WRITE_REG(SoftwareReset, + PMX2_SOFTRESET_REG_RST | PMX2_SOFTRESET_TA_RST | + PMX2_SOFTRESET_ROM_RST); + + pci_read_config_word(pDev, PCI_CONFIG_SUBSYS_ID, &sub); + pci_read_config_byte(pDev, PCI_REVISION_ID, &rev); + + ulChipSpeed = InitSDRAMRegisters(pSTGReg, (u32)sub, (u32)rev); + + if (ulChipSpeed == 0) + return -EINVAL; + + ulCoreClock = ProgramClock(REF_FREQ, CORE_PLL_FREQ, &F, &R, &P); + + core_pll |= ((P) | ((F - 2) << 2) | ((R - 2) << 11)); + + /* Set Core PLL Control to Core PLL Mode */ + + /* Send bits 0:7 of the Core PLL Mode register */ + tmp = ((CORE_PLL_MODE_REG_0_7 << 8) | (core_pll & 0x00FF)); + pci_write_config_word(pDev, CorePllControl, tmp); + /* Without some delay between the PCI config writes the clock does + not reliably set when the code is compiled -O3 + */ + OS_DELAY(1000000); + + tmp |= SET_BIT(14); + pci_write_config_word(pDev, CorePllControl, tmp); + OS_DELAY(1000000); + + /* Send bits 8:15 of the Core PLL Mode register */ + tmp = + ((CORE_PLL_MODE_REG_8_15 << 8) | ((core_pll & 0xFF00) >> 8)); + pci_write_config_word(pDev, CorePllControl, tmp); + OS_DELAY(1000000); + + tmp |= SET_BIT(14); + pci_write_config_word(pDev, CorePllControl, tmp); + OS_DELAY(1000000); + + STG_WRITE_REG(SoftwareReset, PMX2_SOFTRESET_ALL); + +#if 0 + /* Enable Primary Core Thread0 */ + tmp = ((STG_READ_REG(Thread0Enable)) | SET_BIT(0)); + STG_WRITE_REG(Thread0Enable, tmp); + + /* Enable Primary Core Thread1 */ + tmp = ((STG_READ_REG(Thread1Enable)) | SET_BIT(0)); + STG_WRITE_REG(Thread1Enable, tmp); +#endif + + return 0; +} diff --git a/drivers/video/kyro/STG4000Interface.h b/drivers/video/kyro/STG4000Interface.h new file mode 100644 index 00000000000..e75b3b4a4aa --- /dev/null +++ b/drivers/video/kyro/STG4000Interface.h @@ -0,0 +1,60 @@ +/* + * linux/drivers/video/kyro/STG4000Interface.h + * + * Copyright (C) 2002 STMicroelectronics + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#ifndef _STG4000INTERFACE_H +#define _STG4000INTERFACE_H + +struct pci_dev; + +/* + * Ramdac Setup + */ +extern int InitialiseRamdac(volatile STG4000REG __iomem *pSTGReg, u32 displayDepth, + u32 displayWidth, u32 displayHeight, + s32 HSyncPolarity, s32 VSyncPolarity, + u32 *pixelClock); + +extern void DisableRamdacOutput(volatile STG4000REG __iomem *pSTGReg); +extern void EnableRamdacOutput(volatile STG4000REG __iomem *pSTGReg); + +/* + * Timing generator setup + */ +extern void DisableVGA(volatile STG4000REG __iomem *pSTGReg); +extern void StopVTG(volatile STG4000REG __iomem *pSTGReg); +extern void StartVTG(volatile STG4000REG __iomem *pSTGReg); +extern void SetupVTG(volatile STG4000REG __iomem *pSTGReg, + const struct kyrofb_info * pTiming); + +extern u32 ProgramClock(u32 refClock, u32 coreClock, u32 *FOut, u32 *ROut, u32 *POut); +extern int SetCoreClockPLL(volatile STG4000REG __iomem *pSTGReg, struct pci_dev *pDev); + +/* + * Overlay setup + */ +extern void ResetOverlayRegisters(volatile STG4000REG __iomem *pSTGReg); + +extern int CreateOverlaySurface(volatile STG4000REG __iomem *pSTGReg, + u32 ulWidth, u32 ulHeight, + int bLinear, + u32 ulOverlayOffset, + u32 * retStride, u32 * retUVStride); + +extern int SetOverlayBlendMode(volatile STG4000REG __iomem *pSTGReg, + OVRL_BLEND_MODE mode, + u32 ulAlpha, u32 ulColorKey); + +extern int SetOverlayViewPort(volatile STG4000REG __iomem *pSTGReg, + u32 left, u32 top, + u32 right, u32 bottom); + +extern void EnableOverlayPlane(volatile STG4000REG __iomem *pSTGReg); + +#endif /* _STG4000INTERFACE_H */ diff --git a/drivers/video/kyro/STG4000OverlayDevice.c b/drivers/video/kyro/STG4000OverlayDevice.c new file mode 100644 index 00000000000..2ae9bafacdd --- /dev/null +++ b/drivers/video/kyro/STG4000OverlayDevice.c @@ -0,0 +1,600 @@ +/* + * linux/drivers/video/kyro/STG4000OverlayDevice.c + * + * Copyright (C) 2000 Imagination Technologies Ltd + * Copyright (C) 2002 STMicroelectronics + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#include +#include +#include + +#include "STG4000Reg.h" + +/* HW Defines */ + +#define STG4000_NO_SCALING 0x800 +#define STG4000_NO_DECIMATION 0xFFFFFFFF + +/* Primary surface */ +#define STG4000_PRIM_NUM_PIX 5 +#define STG4000_PRIM_ALIGN 4 +#define STG4000_PRIM_ADDR_BITS 20 + +#define STG4000_PRIM_MIN_WIDTH 640 +#define STG4000_PRIM_MAX_WIDTH 1600 +#define STG4000_PRIM_MIN_HEIGHT 480 +#define STG4000_PRIM_MAX_HEIGHT 1200 + +/* Overlay surface */ +#define STG4000_OVRL_NUM_PIX 4 +#define STG4000_OVRL_ALIGN 2 +#define STG4000_OVRL_ADDR_BITS 20 +#define STG4000_OVRL_NUM_MODES 5 + +#define STG4000_OVRL_MIN_WIDTH 0 +#define STG4000_OVRL_MAX_WIDTH 720 +#define STG4000_OVRL_MIN_HEIGHT 0 +#define STG4000_OVRL_MAX_HEIGHT 576 + +/* Decimation and Scaling */ +static u32 adwDecim8[33] = { + 0xffffffff, 0xfffeffff, 0xffdffbff, 0xfefefeff, 0xfdf7efbf, + 0xfbdf7bdf, 0xf7bbddef, 0xeeeeeeef, 0xeeddbb77, 0xedb76db7, + 0xdb6db6db, 0xdb5b5b5b, 0xdab5ad6b, 0xd5ab55ab, 0xd555aaab, + 0xaaaaaaab, 0xaaaa5555, 0xaa952a55, 0xa94a5295, 0xa5252525, + 0xa4924925, 0x92491249, 0x91224489, 0x91111111, 0x90884211, + 0x88410821, 0x88102041, 0x81010101, 0x80800801, 0x80010001, + 0x80000001, 0x00000001, 0x00000000 +}; + +typedef struct _OVRL_SRC_DEST { + /*clipped on-screen pixel position of overlay */ + u32 ulDstX1; + u32 ulDstY1; + u32 ulDstX2; + u32 ulDstY2; + + /*clipped pixel pos of source data within buffer thses need to be 128 bit word aligned */ + u32 ulSrcX1; + u32 ulSrcY1; + u32 ulSrcX2; + u32 ulSrcY2; + + /* on-screen pixel position of overlay */ + s32 lDstX1; + s32 lDstY1; + s32 lDstX2; + s32 lDstY2; +} OVRL_SRC_DEST; + +static u32 ovlWidth, ovlHeight, ovlStride; +static int ovlLinear; + +void ResetOverlayRegisters(volatile STG4000REG __iomem *pSTGReg) +{ + u32 tmp; + + /* Set Overlay address to default */ + tmp = STG_READ_REG(DACOverlayAddr); + CLEAR_BITS_FRM_TO(0, 20); + CLEAR_BIT(31); + STG_WRITE_REG(DACOverlayAddr, tmp); + + /* Set Overlay U address */ + tmp = STG_READ_REG(DACOverlayUAddr); + CLEAR_BITS_FRM_TO(0, 20); + STG_WRITE_REG(DACOverlayUAddr, tmp); + + /* Set Overlay V address */ + tmp = STG_READ_REG(DACOverlayVAddr); + CLEAR_BITS_FRM_TO(0, 20); + STG_WRITE_REG(DACOverlayVAddr, tmp); + + /* Set Overlay Size */ + tmp = STG_READ_REG(DACOverlaySize); + CLEAR_BITS_FRM_TO(0, 10); + CLEAR_BITS_FRM_TO(12, 31); + STG_WRITE_REG(DACOverlaySize, tmp); + + /* Set Overlay Vt Decimation */ + tmp = STG4000_NO_DECIMATION; + STG_WRITE_REG(DACOverlayVtDec, tmp); + + /* Set Overlay format to default value */ + tmp = STG_READ_REG(DACPixelFormat); + CLEAR_BITS_FRM_TO(4, 7); + CLEAR_BITS_FRM_TO(16, 22); + STG_WRITE_REG(DACPixelFormat, tmp); + + /* Set Vertical scaling to default */ + tmp = STG_READ_REG(DACVerticalScal); + CLEAR_BITS_FRM_TO(0, 11); + CLEAR_BITS_FRM_TO(16, 22); + tmp |= STG4000_NO_SCALING; /* Set to no scaling */ + STG_WRITE_REG(DACVerticalScal, tmp); + + /* Set Horizontal Scaling to default */ + tmp = STG_READ_REG(DACHorizontalScal); + CLEAR_BITS_FRM_TO(0, 11); + CLEAR_BITS_FRM_TO(16, 17); + tmp |= STG4000_NO_SCALING; /* Set to no scaling */ + STG_WRITE_REG(DACHorizontalScal, tmp); + + /* Set Blend mode to Alpha Blend */ + /* ????? SG 08/11/2001 Surely this isn't the alpha blend mode, + hopefully its overwrite + */ + tmp = STG_READ_REG(DACBlendCtrl); + CLEAR_BITS_FRM_TO(0, 30); + tmp = (GRAPHICS_MODE << 28); + STG_WRITE_REG(DACBlendCtrl, tmp); + +} + +int CreateOverlaySurface(volatile STG4000REG __iomem *pSTGReg, + u32 inWidth, + u32 inHeight, + int bLinear, + u32 ulOverlayOffset, + u32 * retStride, u32 * retUVStride) +{ + u32 tmp; + u32 ulStride; + + if (inWidth > STG4000_OVRL_MAX_WIDTH || + inHeight > STG4000_OVRL_MAX_HEIGHT) { + return -EINVAL; + } + + /* Stride in 16 byte words - 16Bpp */ + if (bLinear) { + /* Format is 16bits so num 16 byte words is width/8 */ + if ((inWidth & 0x7) == 0) { /* inWidth % 8 */ + ulStride = (inWidth / 8); + } else { + /* Round up to next 16byte boundary */ + ulStride = ((inWidth + 8) / 8); + } + } else { + /* Y component is 8bits so num 16 byte words is width/16 */ + if ((inWidth & 0xf) == 0) { /* inWidth % 16 */ + ulStride = (inWidth / 16); + } else { + /* Round up to next 16byte boundary */ + ulStride = ((inWidth + 16) / 16); + } + } + + + /* Set Overlay address and Format mode */ + tmp = STG_READ_REG(DACOverlayAddr); + CLEAR_BITS_FRM_TO(0, 20); + if (bLinear) { + CLEAR_BIT(31); /* Overlay format to Linear */ + } else { + tmp |= SET_BIT(31); /* Overlay format to Planer */ + } + + /* Only bits 24:4 of the Overlay address */ + tmp |= (ulOverlayOffset >> 4); + STG_WRITE_REG(DACOverlayAddr, tmp); + + if (!bLinear) { + u32 uvSize = + (inWidth & 0x1) ? (inWidth + 1 / 2) : (inWidth / 2); + u32 uvStride; + u32 ulOffset; + /* Y component is 8bits so num 32 byte words is width/32 */ + if ((uvSize & 0xf) == 0) { /* inWidth % 16 */ + uvStride = (uvSize / 16); + } else { + /* Round up to next 32byte boundary */ + uvStride = ((uvSize + 16) / 16); + } + + ulOffset = ulOverlayOffset + (inHeight * (ulStride * 16)); + /* Align U,V data to 32byte boundary */ + if ((ulOffset & 0x1f) != 0) + ulOffset = (ulOffset + 32L) & 0xffffffE0L; + + tmp = STG_READ_REG(DACOverlayUAddr); + CLEAR_BITS_FRM_TO(0, 20); + tmp |= (ulOffset >> 4); + STG_WRITE_REG(DACOverlayUAddr, tmp); + + ulOffset += (inHeight / 2) * (uvStride * 16); + /* Align U,V data to 32byte boundary */ + if ((ulOffset & 0x1f) != 0) + ulOffset = (ulOffset + 32L) & 0xffffffE0L; + + tmp = STG_READ_REG(DACOverlayVAddr); + CLEAR_BITS_FRM_TO(0, 20); + tmp |= (ulOffset >> 4); + STG_WRITE_REG(DACOverlayVAddr, tmp); + + *retUVStride = uvStride * 16; + } + + + /* Set Overlay YUV pixel format + * Make sure that LUT not used - ?????? + */ + tmp = STG_READ_REG(DACPixelFormat); + /* Only support Planer or UYVY linear formats */ + CLEAR_BITS_FRM_TO(4, 9); + STG_WRITE_REG(DACPixelFormat, tmp); + + ovlWidth = inWidth; + ovlHeight = inHeight; + ovlStride = ulStride; + ovlLinear = bLinear; + *retStride = ulStride << 4; /* In bytes */ + + return 0; +} + +int SetOverlayBlendMode(volatile STG4000REG __iomem *pSTGReg, + OVRL_BLEND_MODE mode, + u32 ulAlpha, u32 ulColorKey) +{ + u32 tmp; + + tmp = STG_READ_REG(DACBlendCtrl); + CLEAR_BITS_FRM_TO(28, 30); + tmp |= (mode << 28); + + switch (mode) { + case COLOR_KEY: + CLEAR_BITS_FRM_TO(0, 23); + tmp |= (ulColorKey & 0x00FFFFFF); + break; + + case GLOBAL_ALPHA: + CLEAR_BITS_FRM_TO(24, 27); + tmp |= ((ulAlpha & 0xF) << 24); + break; + + case CK_PIXEL_ALPHA: + CLEAR_BITS_FRM_TO(0, 23); + tmp |= (ulColorKey & 0x00FFFFFF); + break; + + case CK_GLOBAL_ALPHA: + CLEAR_BITS_FRM_TO(0, 23); + tmp |= (ulColorKey & 0x00FFFFFF); + CLEAR_BITS_FRM_TO(24, 27); + tmp |= ((ulAlpha & 0xF) << 24); + break; + + case GRAPHICS_MODE: + case PER_PIXEL_ALPHA: + break; + + default: + return -EINVAL; + } + + STG_WRITE_REG(DACBlendCtrl, tmp); + + return 0; +} + +void EnableOverlayPlane(volatile STG4000REG __iomem *pSTGReg) +{ + u32 tmp; + /* Enable Overlay */ + tmp = STG_READ_REG(DACPixelFormat); + tmp |= SET_BIT(7); + STG_WRITE_REG(DACPixelFormat, tmp); + + /* Set video stream control */ + tmp = STG_READ_REG(DACStreamCtrl); + tmp |= SET_BIT(1); /* video stream */ + STG_WRITE_REG(DACStreamCtrl, tmp); +} + +static u32 Overlap(u32 ulBits, u32 ulPattern) +{ + u32 ulCount = 0; + + while (ulBits) { + if (!(ulPattern & 1)) + ulCount++; + ulBits--; + ulPattern = ulPattern >> 1; + } + + return ulCount; + +} + +int SetOverlayViewPort(volatile STG4000REG __iomem *pSTGReg, + u32 left, u32 top, + u32 right, u32 bottom) +{ + OVRL_SRC_DEST srcDest; + + u32 ulSrcTop, ulSrcBottom; + u32 ulSrc, ulDest; + u32 ulFxScale, ulFxOffset; + u32 ulHeight, ulWidth; + u32 ulPattern; + u32 ulDecimate, ulDecimated; + u32 ulApplied; + u32 ulDacXScale, ulDacYScale; + u32 ulScale; + u32 ulLeft, ulRight; + u32 ulSrcLeft, ulSrcRight; + u32 ulScaleLeft, ulScaleRight; + u32 ulhDecim; + u32 ulsVal; + u32 ulVertDecFactor; + int bResult; + u32 ulClipOff = 0; + u32 ulBits = 0; + u32 ulsAdd = 0; + u32 tmp, ulStride; + u32 ulExcessPixels, ulClip, ulExtraLines; + + + srcDest.ulSrcX1 = 0; + srcDest.ulSrcY1 = 0; + srcDest.ulSrcX2 = ovlWidth - 1; + srcDest.ulSrcY2 = ovlHeight - 1; + + srcDest.ulDstX1 = left; + srcDest.ulDstY1 = top; + srcDest.ulDstX2 = right; + srcDest.ulDstY2 = bottom; + + srcDest.lDstX1 = srcDest.ulDstX1; + srcDest.lDstY1 = srcDest.ulDstY1; + srcDest.lDstX2 = srcDest.ulDstX2; + srcDest.lDstY2 = srcDest.ulDstY2; + + /************* Vertical decimation/scaling ******************/ + + /* Get Src Top and Bottom */ + ulSrcTop = srcDest.ulSrcY1; + ulSrcBottom = srcDest.ulSrcY2; + + ulSrc = ulSrcBottom - ulSrcTop; + ulDest = srcDest.lDstY2 - srcDest.lDstY1; /* on-screen overlay */ + + if (ulSrc <= 1) + return -EINVAL; + + /* First work out the position we are to display as offset from the + * source of the buffer + */ + ulFxScale = (ulDest << 11) / ulSrc; /* fixed point scale factor */ + ulFxOffset = (srcDest.lDstY2 - srcDest.ulDstY2) << 11; + + ulSrcBottom = ulSrcBottom - (ulFxOffset / ulFxScale); + ulSrc = ulSrcBottom - ulSrcTop; + ulHeight = ulSrc; + + ulDest = srcDest.ulDstY2 - (srcDest.ulDstY1 - 1); + ulPattern = adwDecim8[ulBits]; + + /* At this point ulSrc represents the input decimator */ + if (ulSrc > ulDest) { + ulDecimate = ulSrc - ulDest; + ulBits = 0; + ulApplied = ulSrc / 32; + + while (((ulBits * ulApplied) + + Overlap((ulSrc % 32), + adwDecim8[ulBits])) < ulDecimate) + ulBits++; + + ulPattern = adwDecim8[ulBits]; + ulDecimated = + (ulBits * ulApplied) + Overlap((ulSrc % 32), + ulPattern); + ulSrc = ulSrc - ulDecimated; /* the number number of lines that will go into the scaler */ + } + + if (ulBits && (ulBits != 32)) { + ulVertDecFactor = (63 - ulBits) / (32 - ulBits); /* vertical decimation factor scaled up to nearest integer */ + } else { + ulVertDecFactor = 1; + } + + ulDacYScale = ((ulSrc - 1) * 2048) / (ulDest + 1); + + tmp = STG_READ_REG(DACOverlayVtDec); /* Decimation */ + CLEAR_BITS_FRM_TO(0, 31); + tmp = ulPattern; + STG_WRITE_REG(DACOverlayVtDec, tmp); + + /***************** Horizontal decimation/scaling ***************************/ + + /* + * Now we handle the horizontal case, this is a simplified verison of + * the vertical case in that we decimate by factors of 2. as we are + * working in words we should always be able to decimate by these + * factors. as we always have to have a buffer which is aligned to a + * whole number of 128 bit words, we must align the left side to the + * lowest to the next lowest 128 bit boundary, and the right hand edge + * to the next largets boundary, (in a similar way to how we didi it in + * PMX1) as the left and right hand edges are aligned to these + * boundaries normally this only becomes an issue when we are chopping + * of one of the sides We shall work out vertical stuff first + */ + ulSrc = srcDest.ulSrcX2 - srcDest.ulSrcX1; + ulDest = srcDest.lDstX2 - srcDest.lDstX1; +#ifdef _OLDCODE + ulLeft = srcDest.ulDstX1; + ulRight = srcDest.ulDstX2; +#else + if (srcDest.ulDstX1 > 2) { + ulLeft = srcDest.ulDstX1 + 2; + ulRight = srcDest.ulDstX2 + 1; + } else { + ulLeft = srcDest.ulDstX1; + ulRight = srcDest.ulDstX2 + 1; + } +#endif + /* first work out the position we are to display as offset from the source of the buffer */ + bResult = 1; + + do { + if (ulDest == 0) + return -EINVAL; + + /* source pixels per dest pixel <<11 */ + ulFxScale = ((ulSrc - 1) << 11) / (ulDest); + + /* then number of destination pixels out we are */ + ulFxOffset = ulFxScale * ((srcDest.ulDstX1 - srcDest.lDstX1) + ulClipOff); + ulFxOffset >>= 11; + + /* this replaces the code which was making a decision as to use either ulFxOffset or ulSrcX1 */ + ulSrcLeft = srcDest.ulSrcX1 + ulFxOffset; + + /* then number of destination pixels out we are */ + ulFxOffset = ulFxScale * (srcDest.lDstX2 - srcDest.ulDstX2); + ulFxOffset >>= 11; + + ulSrcRight = srcDest.ulSrcX2 - ulFxOffset; + + /* + * we must align these to our 128 bit boundaries. we shall + * round down the pixel pos to the nearest 8 pixels. + */ + ulScaleLeft = ulSrcLeft; + ulScaleRight = ulSrcRight; + + /* shift fxscale until it is in the range of the scaler */ + ulhDecim = 0; + ulScale = (((ulSrcRight - ulSrcLeft) - 1) << (11 - ulhDecim)) / (ulRight - ulLeft + 2); + + while (ulScale > 0x800) { + ulhDecim++; + ulScale = (((ulSrcRight - ulSrcLeft) - 1) << (11 - ulhDecim)) / (ulRight - ulLeft + 2); + } + + /* + * to try and get the best values We first try and use + * src/dwdest for the scale factor, then we move onto src-1 + * + * we want to check to see if we will need to clip data, if so + * then we should clip our source so that we don't need to + */ + if (!ovlLinear) { + ulSrcLeft &= ~0x1f; + + /* + * we must align the right hand edge to the next 32 + * pixel` boundary, must be on a 256 boundary so u, and + * v are 128 bit aligned + */ + ulSrcRight = (ulSrcRight + 0x1f) & ~0x1f; + } else { + ulSrcLeft &= ~0x7; + + /* + * we must align the right hand edge to the next + * 8pixel` boundary + */ + ulSrcRight = (ulSrcRight + 0x7) & ~0x7; + } + + /* this is the input size line store needs to cope with */ + ulWidth = ulSrcRight - ulSrcLeft; + + /* + * use unclipped value to work out scale factror this is the + * scale factor we want we shall now work out the horizonal + * decimation and scaling + */ + ulsVal = ((ulWidth / 8) >> ulhDecim); + + if ((ulWidth != (ulsVal << ulhDecim) * 8)) + ulsAdd = 1; + + /* input pixels to scaler; */ + ulSrc = ulWidth >> ulhDecim; + + if (ulSrc <= 2) + return -EINVAL; + + ulExcessPixels = ((((ulScaleLeft - ulSrcLeft)) << (11 - ulhDecim)) / ulScale); + + ulClip = (ulSrc << 11) / ulScale; + ulClip -= (ulRight - ulLeft); + ulClip += ulExcessPixels; + + if (ulClip) + ulClip--; + + /* We may need to do more here if we really have a HW rev < 5 */ + } while (!bResult); + + ulExtraLines = (1 << ulhDecim) * ulVertDecFactor; + ulExtraLines += 64; + ulHeight += ulExtraLines; + + ulDacXScale = ulScale; + + + tmp = STG_READ_REG(DACVerticalScal); + CLEAR_BITS_FRM_TO(0, 11); + CLEAR_BITS_FRM_TO(16, 22); /* Vertical Scaling */ + + /* Calculate new output line stride, this is always the number of 422 + words in the line buffer, so it doesn't matter if the + mode is 420. Then set the vertical scale register. + */ + ulStride = (ulWidth >> (ulhDecim + 3)) + ulsAdd; + tmp |= ((ulStride << 16) | (ulDacYScale)); /* DAC_LS_CTRL = stride */ + STG_WRITE_REG(DACVerticalScal, tmp); + + /* Now set up the overlay size using the modified width and height + from decimate and scaling calculations + */ + tmp = STG_READ_REG(DACOverlaySize); + CLEAR_BITS_FRM_TO(0, 10); + CLEAR_BITS_FRM_TO(12, 31); + + if (ovlLinear) { + tmp |= + (ovlStride | ((ulHeight + 1) << 12) | + (((ulWidth / 8) - 1) << 23)); + } else { + tmp |= + (ovlStride | ((ulHeight + 1) << 12) | + (((ulWidth / 32) - 1) << 23)); + } + + STG_WRITE_REG(DACOverlaySize, tmp); + + /* Set Video Window Start */ + tmp = ((ulLeft << 16)) | (srcDest.ulDstY1); + STG_WRITE_REG(DACVidWinStart, tmp); + + /* Set Video Window End */ + tmp = ((ulRight) << 16) | (srcDest.ulDstY2); + STG_WRITE_REG(DACVidWinEnd, tmp); + + /* Finally set up the rest of the overlay regs in the order + done in the IMG driver + */ + tmp = STG_READ_REG(DACPixelFormat); + tmp = ((ulExcessPixels << 16) | tmp) & 0x7fffffff; + STG_WRITE_REG(DACPixelFormat, tmp); + + tmp = STG_READ_REG(DACHorizontalScal); + CLEAR_BITS_FRM_TO(0, 11); + CLEAR_BITS_FRM_TO(16, 17); + tmp |= ((ulhDecim << 16) | (ulDacXScale)); + STG_WRITE_REG(DACHorizontalScal, tmp); + + return 0; +} diff --git a/drivers/video/kyro/STG4000Ramdac.c b/drivers/video/kyro/STG4000Ramdac.c new file mode 100644 index 00000000000..e6ad037e439 --- /dev/null +++ b/drivers/video/kyro/STG4000Ramdac.c @@ -0,0 +1,163 @@ +/* + * linux/drivers/video/kyro/STG4000Ramdac.c + * + * Copyright (C) 2002 STMicroelectronics + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#include +#include +#include +#include