diff options
| author | Tomi Valkeinen <tomi.valkeinen@ti.com> | 2014-02-13 08:31:38 -0500 |
|---|---|---|
| committer | Tomi Valkeinen <tomi.valkeinen@ti.com> | 2014-04-17 01:10:19 -0400 |
| commit | f7018c21350204c4cf628462f229d44d03545254 (patch) | |
| tree | 408787177164cf51cc06f7aabdb04fcff8d2b6aa /drivers/video/fbdev/kyro | |
| parent | c26ef3eb3c11274bad1b64498d0a134f85755250 (diff) | |
video: move fbdev to drivers/video/fbdev
The drivers/video directory is a mess. It contains generic video related
files, directories for backlight, console, linux logo, lots of fbdev
device drivers, fbdev framework files.
Make some order into the chaos by creating drivers/video/fbdev
directory, and move all fbdev related files there.
No functionality is changed, although I guess it is possible that some
subtle Makefile build order related issue could be created by this
patch.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Geert Uytterhoeven <geert@linux-m68k.org>
Acked-by: Rob Clark <robdclark@gmail.com>
Acked-by: Jingoo Han <jg1.han@samsung.com>
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/video/fbdev/kyro')
| -rw-r--r-- | drivers/video/fbdev/kyro/Makefile | 8 | ||||
| -rw-r--r-- | drivers/video/fbdev/kyro/STG4000InitDevice.c | 326 | ||||
| -rw-r--r-- | drivers/video/fbdev/kyro/STG4000Interface.h | 61 | ||||
| -rw-r--r-- | drivers/video/fbdev/kyro/STG4000OverlayDevice.c | 601 | ||||
| -rw-r--r-- | drivers/video/fbdev/kyro/STG4000Ramdac.c | 163 | ||||
| -rw-r--r-- | drivers/video/fbdev/kyro/STG4000Reg.h | 283 | ||||
| -rw-r--r-- | drivers/video/fbdev/kyro/STG4000VTG.c | 170 | ||||
| -rw-r--r-- | drivers/video/fbdev/kyro/fbdev.c | 808 |
8 files changed, 2420 insertions, 0 deletions
diff --git a/drivers/video/fbdev/kyro/Makefile b/drivers/video/fbdev/kyro/Makefile new file mode 100644 index 000000000000..2fd66f551bae --- /dev/null +++ b/drivers/video/fbdev/kyro/Makefile | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | # | ||
| 2 | # Makefile for the Kyro framebuffer driver | ||
| 3 | # | ||
| 4 | |||
| 5 | obj-$(CONFIG_FB_KYRO) += kyrofb.o | ||
| 6 | |||
| 7 | kyrofb-objs := STG4000Ramdac.o STG4000VTG.o STG4000OverlayDevice.o \ | ||
| 8 | STG4000InitDevice.o fbdev.o | ||
diff --git a/drivers/video/fbdev/kyro/STG4000InitDevice.c b/drivers/video/fbdev/kyro/STG4000InitDevice.c new file mode 100644 index 000000000000..1d3f2080aa6f --- /dev/null +++ b/drivers/video/fbdev/kyro/STG4000InitDevice.c | |||
| @@ -0,0 +1,326 @@ | |||
| 1 | /* | ||
| 2 | * linux/drivers/video/kyro/STG4000InitDevice.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 2000 Imagination Technologies Ltd | ||
| 5 | * Copyright (C) 2002 STMicroelectronics | ||
| 6 | * | ||
| 7 | * This file is subject to the terms and conditions of the GNU General Public | ||
| 8 | * License. See the file COPYING in the main directory of this archive | ||
| 9 | * for more details. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/kernel.h> | ||
| 13 | #include <linux/errno.h> | ||
| 14 | #include <linux/types.h> | ||
| 15 | #include <linux/pci.h> | ||
| 16 | |||
| 17 | #include "STG4000Reg.h" | ||
| 18 | #include "STG4000Interface.h" | ||
| 19 | |||
| 20 | /* SDRAM fixed settings */ | ||
| 21 | #define SDRAM_CFG_0 0x49A1 | ||
| 22 | #define SDRAM_CFG_1 0xA732 | ||
| 23 | #define SDRAM_CFG_2 0x31 | ||
| 24 | #define SDRAM_ARB_CFG 0xA0 | ||
| 25 | #define SDRAM_REFRESH 0x20 | ||
| 26 | |||
| 27 | /* Reset values */ | ||
| 28 | #define PMX2_SOFTRESET_DAC_RST 0x0001 | ||
| 29 | #define PMX2_SOFTRESET_C1_RST 0x0004 | ||
| 30 | #define PMX2_SOFTRESET_C2_RST 0x0008 | ||
| 31 | #define PMX2_SOFTRESET_3D_RST 0x0010 | ||
| 32 | #define PMX2_SOFTRESET_VIDIN_RST 0x0020 | ||
| 33 | #define PMX2_SOFTRESET_TLB_RST 0x0040 | ||
| 34 | #define PMX2_SOFTRESET_SD_RST 0x0080 | ||
| 35 | #define PMX2_SOFTRESET_VGA_RST 0x0100 | ||
| 36 | #define PMX2_SOFTRESET_ROM_RST 0x0200 /* reserved bit, do not reset */ | ||
| 37 | #define PMX2_SOFTRESET_TA_RST 0x0400 | ||
| 38 | #define PMX2_SOFTRESET_REG_RST 0x4000 | ||
| 39 | #define PMX2_SOFTRESET_ALL 0x7fff | ||
| 40 | |||
| 41 | /* Core clock freq */ | ||
| 42 | #define CORE_PLL_FREQ 1000000 | ||
| 43 | |||
| 44 | /* Reference Clock freq */ | ||
| 45 | #define REF_FREQ 14318 | ||
| 46 | |||
| 47 | /* PCI Registers */ | ||
| 48 | static u16 CorePllControl = 0x70; | ||
| 49 | |||
| 50 | #define PCI_CONFIG_SUBSYS_ID 0x2e | ||
| 51 | |||
| 52 | /* Misc */ | ||
| 53 | #define CORE_PLL_MODE_REG_0_7 3 | ||
| 54 | #define CORE_PLL_MODE_REG_8_15 2 | ||
| 55 | #define CORE_PLL_MODE_CONFIG_REG 1 | ||
| 56 | #define DAC_PLL_CONFIG_REG 0 | ||
| 57 | |||
| 58 | #define STG_MAX_VCO 500000 | ||
| 59 | #define STG_MIN_VCO 100000 | ||
| 60 | |||
| 61 | /* PLL Clock */ | ||
| 62 | #define STG4K3_PLL_SCALER 8 /* scale numbers by 2^8 for fixed point calc */ | ||
| 63 | #define STG4K3_PLL_MIN_R 2 /* Minimum multiplier */ | ||
| 64 | #define STG4K3_PLL_MAX_R 33 /* Max */ | ||
| 65 | #define STG4K3_PLL_MIN_F 2 /* Minimum divisor */ | ||
| 66 | #define STG4K3_PLL_MAX_F 513 /* Max */ | ||
| 67 | #define STG4K3_PLL_MIN_OD 0 /* Min output divider (shift) */ | ||
| 68 | #define STG4K3_PLL_MAX_OD 2 /* Max */ | ||
| 69 | #define STG4K3_PLL_MIN_VCO_SC (100000000 >> STG4K3_PLL_SCALER) /* Min VCO rate */ | ||
| 70 | #define STG4K3_PLL_MAX_VCO_SC (500000000 >> STG4K3_PLL_SCALER) /* Max VCO rate */ | ||
| 71 | #define STG4K3_PLL_MINR_VCO_SC (100000000 >> STG4K3_PLL_SCALER) /* Min VCO rate (restricted) */ | ||
| 72 | #define STG4K3_PLL_MAXR_VCO_SC (500000000 >> STG4K3_PLL_SCALER) /* Max VCO rate (restricted) */ | ||
| 73 | #define STG4K3_PLL_MINR_VCO 100000000 /* Min VCO rate (restricted) */ | ||
| 74 | #define STG4K3_PLL_MAX_VCO 500000000 /* Max VCO rate */ | ||
| 75 | #define STG4K3_PLL_MAXR_VCO 500000000 /* Max VCO rate (restricted) */ | ||
| 76 | |||
| 77 | #define OS_DELAY(X) \ | ||
| 78 | { \ | ||
| 79 | volatile u32 i,count=0; \ | ||
| 80 | for(i=0;i<X;i++) count++; \ | ||
| 81 | } | ||
| 82 | |||
| 83 | static u32 InitSDRAMRegisters(volatile STG4000REG __iomem *pSTGReg, | ||
| 84 | u32 dwSubSysID, u32 dwRevID) | ||
| 85 | { | ||
| 86 | u32 adwSDRAMArgCfg0[] = { 0xa0, 0x80, 0xa0, 0xa0, 0xa0 }; | ||
| 87 | u32 adwSDRAMCfg1[] = { 0x8732, 0x8732, 0xa732, 0xa732, 0x8732 }; | ||
| 88 | u32 adwSDRAMCfg2[] = { 0x87d2, 0x87d2, 0xa7d2, 0x87d2, 0xa7d2 }; | ||
| 89 | u32 adwSDRAMRsh[] = { 36, 39, 40 }; | ||
| 90 | u32 adwChipSpeed[] = { 110, 120, 125 }; | ||
| 91 | u32 dwMemTypeIdx; | ||
| 92 | u32 dwChipSpeedIdx; | ||
| 93 | |||
| 94 | /* Get memory tpye and chip speed indexs from the SubSysDevID */ | ||
| 95 | dwMemTypeIdx = (dwSubSysID & 0x70) >> 4; | ||
| 96 | dwChipSpeedIdx = (dwSubSysID & 0x180) >> 7; | ||
| 97 | |||
| 98 | if (dwMemTypeIdx > 4 || dwChipSpeedIdx > 2) | ||
| 99 | return 0; | ||
| 100 | |||
| 101 | /* Program SD-RAM interface */ | ||
| 102 | STG_WRITE_REG(SDRAMArbiterConf, adwSDRAMArgCfg0[dwMemTypeIdx]); | ||
| 103 | if (dwRevID < 5) { | ||
| 104 | STG_WRITE_REG(SDRAMConf0, 0x49A1); | ||
| 105 | STG_WRITE_REG(SDRAMConf1, adwSDRAMCfg1[dwMemTypeIdx]); | ||
| 106 | } else { | ||
| 107 | STG_WRITE_REG(SDRAMConf0, 0x4DF1); | ||
| 108 | STG_WRITE_REG(SDRAMConf1, adwSDRAMCfg2[dwMemTypeIdx]); | ||
| 109 | } | ||
| 110 | |||
| 111 | STG_WRITE_REG(SDRAMConf2, 0x31); | ||
| 112 | STG_WRITE_REG(SDRAMRefresh, adwSDRAMRsh[dwChipSpeedIdx]); | ||
| 113 | |||
| 114 | return adwChipSpeed[dwChipSpeedIdx] * 10000; | ||
| 115 | } | ||
| 116 | |||
| 117 | u32 ProgramClock(u32 refClock, | ||
| 118 | u32 coreClock, | ||
| 119 | u32 * FOut, u32 * ROut, u32 * POut) | ||
| 120 | { | ||
| 121 | u32 R = 0, F = 0, OD = 0, ODIndex = 0; | ||
| 122 | u32 ulBestR = 0, ulBestF = 0, ulBestOD = 0; | ||
| 123 | u32 ulBestVCO = 0, ulBestClk = 0, ulBestScore = 0; | ||
| 124 | u32 ulScore, ulPhaseScore, ulVcoScore; | ||
| 125 | u32 ulTmp = 0, ulVCO; | ||
| 126 | u32 ulScaleClockReq, ulMinClock, ulMaxClock; | ||
| 127 | u32 ODValues[] = { 1, 2, 0 }; | ||
| 128 | |||
| 129 | /* Translate clock in Hz */ | ||
| 130 | coreClock *= 100; /* in Hz */ | ||
| 131 | refClock *= 1000; /* in Hz */ | ||
| 132 | |||
| 133 | /* Work out acceptable clock | ||
| 134 | * The method calculates ~ +- 0.4% (1/256) | ||
| 135 | */ | ||
| 136 | ulMinClock = coreClock - (coreClock >> 8); | ||
| 137 | ulMaxClock = coreClock + (coreClock >> 8); | ||
| 138 | |||
| 139 | /* Scale clock required for use in calculations */ | ||
| 140 | ulScaleClockReq = coreClock >> STG4K3_PLL_SCALER; | ||
| 141 | |||
| 142 | /* Iterate through post divider values */ | ||
| 143 | for (ODIndex = 0; ODIndex < 3; ODIndex++) { | ||
| 144 | OD = ODValues[ODIndex]; | ||
| 145 | R = STG4K3_PLL_MIN_R; | ||
| 146 | |||
| 147 | /* loop for pre-divider from min to max */ | ||
| 148 | while (R <= STG4K3_PLL_MAX_R) { | ||
| 149 | /* estimate required feedback multiplier */ | ||
| 150 | ulTmp = R * (ulScaleClockReq << OD); | ||
| 151 | |||
| 152 | /* F = ClkRequired * R * (2^OD) / Fref */ | ||
| 153 | F = (u32)(ulTmp / (refClock >> STG4K3_PLL_SCALER)); | ||
| 154 | |||
| 155 | /* compensate for accuracy */ | ||
| 156 | if (F > STG4K3_PLL_MIN_F) | ||
| 157 | F--; | ||
| 158 | |||
| 159 | |||
| 160 | /* | ||
| 161 | * We should be close to our target frequency (if it's | ||
| 162 | * achievable with current OD & R) let's iterate | ||
| 163 | * through F for best fit | ||
| 164 | */ | ||
| 165 | while ((F >= STG4K3_PLL_MIN_F) && | ||
| 166 | (F <= STG4K3_PLL_MAX_F)) { | ||
| 167 | /* Calc VCO at full accuracy */ | ||
| 168 | ulVCO = refClock / R; | ||
| 169 | ulVCO = F * ulVCO; | ||
| 170 | |||
| 171 | /* | ||
| 172 | * Check it's within restricted VCO range | ||
| 173 | * unless of course the desired frequency is | ||
| 174 | * above the restricted range, then test | ||
| 175 | * against VCO limit | ||
| 176 | */ | ||
| 177 | if ((ulVCO >= STG4K3_PLL_MINR_VCO) && | ||
| 178 | ((ulVCO <= STG4K3_PLL_MAXR_VCO) || | ||
| 179 | ((coreClock > STG4K3_PLL_MAXR_VCO) | ||
| 180 | && (ulVCO <= STG4K3_PLL_MAX_VCO)))) { | ||
| 181 | ulTmp = (ulVCO >> OD); /* Clock = VCO / (2^OD) */ | ||
| 182 | |||
| 183 | /* Is this clock good enough? */ | ||
| 184 | if ((ulTmp >= ulMinClock) | ||
| 185 | && (ulTmp <= ulMaxClock)) { | ||
| 186 | ulPhaseScore = (((refClock / R) - (refClock / STG4K3_PLL_MAX_R))) / ((refClock - (refClock / STG4K3_PLL_MAX_R)) >> 10); | ||
| 187 | |||
| 188 | ulVcoScore = ((ulVCO - STG4K3_PLL_MINR_VCO)) / ((STG4K3_PLL_MAXR_VCO - STG4K3_PLL_MINR_VCO) >> 10); | ||
| 189 | ulScore = ulPhaseScore + ulVcoScore; | ||
| 190 | |||
| 191 | if (!ulBestScore) { | ||
| 192 | ulBestVCO = ulVCO; | ||
| 193 | ulBestOD = OD; | ||
| 194 | ulBestF = F; | ||
| 195 | ulBestR = R; | ||
| 196 | ulBestClk = ulTmp; | ||
| 197 | ulBestScore = | ||
| 198 | ulScore; | ||
| 199 | } | ||
| 200 | /* is this better, ( aim for highest Score) */ | ||
| 201 | /*-------------------------------------------------------------------------- | ||
| 202 | Here we want to use a scoring system which will take account of both the | ||
| 203 | value at the phase comparater and the VCO output | ||
| 204 | to do this we will use a cumulative score between the two | ||
| 205 | The way this ends up is that we choose the first value in the loop anyway | ||
| 206 | but we shall keep this code in case new restrictions come into play | ||
| 207 | --------------------------------------------------------------------------*/ | ||
| 208 | if ((ulScore >= ulBestScore) && (OD > 0)) { | ||
| 209 | ulBestVCO = ulVCO; | ||
| 210 | ulBestOD = OD; | ||
| 211 | ulBestF = F; | ||
| 212 | ulBestR = R; | ||
| 213 | ulBestClk = ulTmp; | ||
| 214 | ulBestScore = | ||
| 215 | ulScore; | ||
| 216 | } | ||
| 217 | } | ||
| 218 | } | ||
| 219 | F++; | ||
| 220 | } | ||
| 221 | R++; | ||
| 222 | } | ||
| 223 | } | ||
| 224 | |||
| 225 | /* | ||
| 226 | did we find anything? | ||
| 227 | Then return RFOD | ||
| 228 | */ | ||
| 229 | if (ulBestScore) { | ||
| 230 | *ROut = ulBestR; | ||
| 231 | *FOut = ulBestF; | ||
| 232 | |||
| 233 | if ((ulBestOD == 2) || (ulBestOD == 3)) { | ||
| 234 | *POut = 3; | ||
| 235 | } else | ||
| 236 | *POut = ulBestOD; | ||
| 237 | |||
| 238 | } | ||
| 239 | |||
| 240 | return (ulBestClk); | ||
| 241 | } | ||
| 242 | |||
| 243 | int SetCoreClockPLL(volatile STG4000REG __iomem *pSTGReg, struct pci_dev *pDev) | ||
| 244 | { | ||
| 245 | u32 F, R, P; | ||
| 246 | u16 core_pll = 0, sub; | ||
| 247 | u32 ulCoreClock; | ||
| 248 | u32 tmp; | ||
| 249 | u32 ulChipSpeed; | ||
| 250 | |||
| 251 | STG_WRITE_REG(IntMask, 0xFFFF); | ||
| 252 | |||
| 253 | /* Disable Primary Core Thread0 */ | ||
| 254 | tmp = STG_READ_REG(Thread0Enable); | ||
| 255 | CLEAR_BIT(0); | ||
| 256 | STG_WRITE_REG(Thread0Enable, tmp); | ||
| 257 | |||
| 258 | /* Disable Primary Core Thread1 */ | ||
| 259 | tmp = STG_READ_REG(Thread1Enable); | ||
| 260 | CLEAR_BIT(0); | ||
| 261 | STG_WRITE_REG(Thread1Enable, tmp); | ||
| 262 | |||
| 263 | STG_WRITE_REG(SoftwareReset, | ||
| 264 | PMX2_SOFTRESET_REG_RST | PMX2_SOFTRESET_ROM_RST); | ||
| 265 | STG_WRITE_REG(SoftwareReset, | ||
| 266 | PMX2_SOFTRESET_REG_RST | PMX2_SOFTRESET_TA_RST | | ||
| 267 | PMX2_SOFTRESET_ROM_RST); | ||
| 268 | |||
| 269 | /* Need to play around to reset TA */ | ||
| 270 | STG_WRITE_REG(TAConfiguration, 0); | ||
| 271 | STG_WRITE_REG(SoftwareReset, | ||
| 272 | PMX2_SOFTRESET_REG_RST | PMX2_SOFTRESET_ROM_RST); | ||
| 273 | STG_WRITE_REG(SoftwareReset, | ||
| 274 | PMX2_SOFTRESET_REG_RST | PMX2_SOFTRESET_TA_RST | | ||
| 275 | PMX2_SOFTRESET_ROM_RST); | ||
| 276 | |||
| 277 | pci_read_config_word(pDev, PCI_CONFIG_SUBSYS_ID, &sub); | ||
| 278 | |||
| 279 | ulChipSpeed = InitSDRAMRegisters(pSTGReg, (u32)sub, | ||
| 280 | (u32)pDev->revision); | ||
| 281 | |||
| 282 | if (ulChipSpeed == 0) | ||
| 283 | return -EINVAL; | ||
| 284 | |||
| 285 | ulCoreClock = ProgramClock(REF_FREQ, CORE_PLL_FREQ, &F, &R, &P); | ||
| 286 | |||
| 287 | core_pll |= ((P) | ((F - 2) << 2) | ((R - 2) << 11)); | ||
| 288 | |||
| 289 | /* Set Core PLL Control to Core PLL Mode */ | ||
| 290 | |||
| 291 | /* Send bits 0:7 of the Core PLL Mode register */ | ||
| 292 | tmp = ((CORE_PLL_MODE_REG_0_7 << 8) | (core_pll & 0x00FF)); | ||
| 293 | pci_write_config_word(pDev, CorePllControl, tmp); | ||
| 294 | /* Without some delay between the PCI config writes the clock does | ||
| 295 | not reliably set when the code is compiled -O3 | ||
| 296 | */ | ||
| 297 | OS_DELAY(1000000); | ||
| 298 | |||
| 299 | tmp |= SET_BIT(14); | ||
| 300 | pci_write_config_word(pDev, CorePllControl, tmp); | ||
| 301 | OS_DELAY(1000000); | ||
| 302 | |||
| 303 | /* Send bits 8:15 of the Core PLL Mode register */ | ||
| 304 | tmp = | ||
| 305 | ((CORE_PLL_MODE_REG_8_15 << 8) | ((core_pll & 0xFF00) >> 8)); | ||
| 306 | pci_write_config_word(pDev, CorePllControl, tmp); | ||
| 307 | OS_DELAY(1000000); | ||
| 308 | |||
| 309 | tmp |= SET_BIT(14); | ||
| 310 | pci_write_config_word(pDev, CorePllControl, tmp); | ||
| 311 | OS_DELAY(1000000); | ||
| 312 | |||
| 313 | STG_WRITE_REG(SoftwareReset, PMX2_SOFTRESET_ALL); | ||
| 314 | |||
| 315 | #if 0 | ||
| 316 | /* Enable Primary Core Thread0 */ | ||
| 317 | tmp = ((STG_READ_REG(Thread0Enable)) | SET_BIT(0)); | ||
| 318 | STG_WRITE_REG(Thread0Enable, tmp); | ||
| 319 | |||
| 320 | /* Enable Primary Core Thread1 */ | ||
| 321 | tmp = ((STG_READ_REG(Thread1Enable)) | SET_BIT(0)); | ||
| 322 | STG_WRITE_REG(Thread1Enable, tmp); | ||
| 323 | #endif | ||
| 324 | |||
| 325 | return 0; | ||
| 326 | } | ||
diff --git a/drivers/video/fbdev/kyro/STG4000Interface.h b/drivers/video/fbdev/kyro/STG4000Interface.h new file mode 100644 index 000000000000..b7c83d5dfb13 --- /dev/null +++ b/drivers/video/fbdev/kyro/STG4000Interface.h | |||
| @@ -0,0 +1,61 @@ | |||
| 1 | /* | ||
| 2 | * linux/drivers/video/kyro/STG4000Interface.h | ||
| 3 | * | ||
| 4 | * Copyright (C) 2002 STMicroelectronics | ||
| 5 | * | ||
| 6 | * This file is subject to the terms and conditions of the GNU General Public | ||
| 7 | * License. See the file COPYING in the main directory of this archive | ||
| 8 | * for more details. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #ifndef _STG4000INTERFACE_H | ||
| 12 | #define _STG4000INTERFACE_H | ||
| 13 | |||
| 14 | #include <linux/pci.h> | ||
| 15 | #include <video/kyro.h> | ||
| 16 | |||
| 17 | /* | ||
| 18 | * Ramdac Setup | ||
| 19 | */ | ||
| 20 | extern int InitialiseRamdac(volatile STG4000REG __iomem *pSTGReg, u32 displayDepth, | ||
| 21 | u32 displayWidth, u32 displayHeight, | ||
| 22 | s32 HSyncPolarity, s32 VSyncPolarity, | ||
| 23 | u32 *pixelClock); | ||
| 24 | |||
| 25 | extern void DisableRamdacOutput(volatile STG4000REG __iomem *pSTGReg); | ||
| 26 | extern void EnableRamdacOutput(volatile STG4000REG __iomem *pSTGReg); | ||
| 27 | |||
| 28 | /* | ||
| 29 | * Timing generator setup | ||
| 30 | */ | ||
| 31 | extern void DisableVGA(volatile STG4000REG __iomem *pSTGReg); | ||
| 32 | extern void StopVTG(volatile STG4000REG __iomem *pSTGReg); | ||
| 33 | extern void StartVTG(volatile STG4000REG __iomem *pSTGReg); | ||
| 34 | extern void SetupVTG(volatile STG4000REG __iomem *pSTGReg, | ||
| 35 | const struct kyrofb_info * pTiming); | ||
| 36 | |||
| 37 | extern u32 ProgramClock(u32 refClock, u32 coreClock, u32 *FOut, u32 *ROut, u32 *POut); | ||
| 38 | extern int SetCoreClockPLL(volatile STG4000REG __iomem *pSTGReg, struct pci_dev *pDev); | ||
| 39 | |||
| 40 | /* | ||
| 41 | * Overlay setup | ||
| 42 | */ | ||
| 43 | extern void ResetOverlayRegisters(volatile STG4000REG __iomem *pSTGReg); | ||
| 44 | |||
| 45 | extern int CreateOverlaySurface(volatile STG4000REG __iomem *pSTGReg, | ||
| 46 | u32 ulWidth, u32 ulHeight, | ||
| 47 | int bLinear, | ||
| 48 | u32 ulOverlayOffset, | ||
| 49 | u32 * retStride, u32 * retUVStride); | ||
| 50 | |||
| 51 | extern int SetOverlayBlendMode(volatile STG4000REG __iomem *pSTGReg, | ||
| 52 | OVRL_BLEND_MODE mode, | ||
| 53 | u32 ulAlpha, u32 ulColorKey); | ||
| 54 | |||
| 55 | extern int SetOverlayViewPort(volatile STG4000REG __iomem *pSTGReg, | ||
| 56 | u32 left, u32 top, | ||
| 57 | u32 right, u32 bottom); | ||
| 58 | |||
| 59 | extern void EnableOverlayPlane(volatile STG4000REG __iomem *pSTGReg); | ||
| 60 | |||
| 61 | #endif /* _STG4000INTERFACE_H */ | ||
diff --git a/drivers/video/fbdev/kyro/STG4000OverlayDevice.c b/drivers/video/fbdev/kyro/STG4000OverlayDevice.c new file mode 100644 index 000000000000..0aeeaa10708b --- /dev/null +++ b/drivers/video/fbdev/kyro/STG4000OverlayDevice.c | |||
| @@ -0,0 +1,601 @@ | |||
| 1 | /* | ||
| 2 | * linux/drivers/video/kyro/STG4000OverlayDevice.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 2000 Imagination Technologies Ltd | ||
| 5 | * Copyright (C) 2002 STMicroelectronics | ||
| 6 | * | ||
| 7 | * This file is subject to the terms and conditions of the GNU General Public | ||
| 8 | * License. See the file COPYING in the main directory of this archive | ||
| 9 | * for more details. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/kernel.h> | ||
| 13 | #include <linux/errno.h> | ||
| 14 | #include <linux/types.h> | ||
| 15 | |||
| 16 | #include "STG4000Reg.h" | ||
| 17 | #include "STG4000Interface.h" | ||
| 18 | |||
| 19 | /* HW Defines */ | ||
| 20 | |||
| 21 | #define STG4000_NO_SCALING 0x800 | ||
| 22 | #define STG4000_NO_DECIMATION 0xFFFFFFFF | ||
| 23 | |||
| 24 | /* Primary surface */ | ||
| 25 | #define STG4000_PRIM_NUM_PIX 5 | ||
| 26 | #define STG4000_PRIM_ALIGN 4 | ||
| 27 | #define STG4000_PRIM_ADDR_BITS 20 | ||
| 28 | |||
| 29 | #define STG4000_PRIM_MIN_WIDTH 640 | ||
| 30 | #define STG4000_PRIM_MAX_WIDTH 1600 | ||
| 31 | #define STG4000_PRIM_MIN_HEIGHT 480 | ||
| 32 | #define STG4000_PRIM_MAX_HEIGHT 1200 | ||
| 33 | |||
| 34 | /* Overlay surface */ | ||
| 35 | #define STG4000_OVRL_NUM_PIX 4 | ||
| 36 | #define STG4000_OVRL_ALIGN 2 | ||
| 37 | #define STG4000_OVRL_ADDR_BITS 20 | ||
| 38 | #define STG4000_OVRL_NUM_MODES 5 | ||
| 39 | |||
| 40 | #define STG4000_OVRL_MIN_WIDTH 0 | ||
| 41 | #define STG4000_OVRL_MAX_WIDTH 720 | ||
| 42 | #define STG4000_OVRL_MIN_HEIGHT 0 | ||
| 43 | #define STG4000_OVRL_MAX_HEIGHT 576 | ||
| 44 | |||
| 45 | /* Decimation and Scaling */ | ||
| 46 | static u32 adwDecim8[33] = { | ||
| 47 | 0xffffffff, 0xfffeffff, 0xffdffbff, 0xfefefeff, 0xfdf7efbf, | ||
| 48 | 0xfbdf7bdf, 0xf7bbddef, 0xeeeeeeef, 0xeeddbb77, 0xedb76db7, | ||
| 49 | 0xdb6db6db, 0xdb5b5b5b, 0xdab5ad6b, 0xd5ab55ab, 0xd555aaab, | ||
| 50 | 0xaaaaaaab, 0xaaaa5555, 0xaa952a55, 0xa94a5295, 0xa5252525, | ||
| 51 | 0xa4924925, 0x92491249, 0x91224489, 0x91111111, 0x90884211, | ||
| 52 | 0x88410821, 0x88102041, 0x81010101, 0x80800801, 0x80010001, | ||
| 53 | 0x80000001, 0x00000001, 0x00000000 | ||
| 54 | }; | ||
| 55 | |||
| 56 | typedef struct _OVRL_SRC_DEST { | ||
| 57 | /*clipped on-screen pixel position of overlay */ | ||
| 58 | u32 ulDstX1; | ||
| 59 | u32 ulDstY1; | ||
| 60 | u32 ulDstX2; | ||
| 61 | u32 ulDstY2; | ||
| 62 | |||
| 63 | /*clipped pixel pos of source data within buffer thses need to be 128 bit word aligned */ | ||
| 64 | u32 ulSrcX1; | ||
| 65 | u32 ulSrcY1; | ||
| 66 | u32 ulSrcX2; | ||
| 67 | u32 ulSrcY2; | ||
| 68 | |||
| 69 | /* on-screen pixel position of overlay */ | ||
| 70 | s32 lDstX1; | ||
| 71 | s32 lDstY1; | ||
| 72 | s32 lDstX2; | ||
| 73 | s32 lDstY2; | ||
| 74 | } OVRL_SRC_DEST; | ||
| 75 | |||
| 76 | static u32 ovlWidth, ovlHeight, ovlStride; | ||
| 77 | static int ovlLinear; | ||
| 78 | |||
| 79 | void ResetOverlayRegisters(volatile STG4000REG __iomem *pSTGReg) | ||
| 80 | { | ||
| 81 | u32 tmp; | ||
| 82 | |||
| 83 | /* Set Overlay address to default */ | ||
| 84 | tmp = STG_READ_REG(DACOverlayAddr); | ||
| 85 | CLEAR_BITS_FRM_TO(0, 20); | ||
| 86 | CLEAR_BIT(31); | ||
| 87 | STG_WRITE_REG(DACOverlayAddr, tmp); | ||
| 88 | |||
| 89 | /* Set Overlay U address */ | ||
| 90 | tmp = STG_READ_REG(DACOverlayUAddr); | ||
| 91 | CLEAR_BITS_FRM_TO(0, 20); | ||
| 92 | STG_WRITE_REG(DACOverlayUAddr, tmp); | ||
| 93 | |||
| 94 | /* Set Overlay V address */ | ||
| 95 | tmp = STG_READ_REG(DACOverlayVAddr); | ||
| 96 | CLEAR_BITS_FRM_TO(0, 20); | ||
| 97 | STG_WRITE_REG(DACOverlayVAddr, tmp); | ||
| 98 | |||
| 99 | /* Set Overlay Size */ | ||
| 100 | tmp = STG_READ_REG(DACOverlaySize); | ||
| 101 | CLEAR_BITS_FRM_TO(0, 10); | ||
| 102 | CLEAR_BITS_FRM_TO(12, 31); | ||
| 103 | STG_WRITE_REG(DACOverlaySize, tmp); | ||
| 104 | |||
| 105 | /* Set Overlay Vt Decimation */ | ||
| 106 | tmp = STG4000_NO_DECIMATION; | ||
| 107 | STG_WRITE_REG(DACOverlayVtDec, tmp); | ||
| 108 | |||
| 109 | /* Set Overlay format to default value */ | ||
| 110 | tmp = STG_READ_REG(DACPixelFormat); | ||
| 111 | CLEAR_BITS_FRM_TO(4, 7); | ||
| 112 | CLEAR_BITS_FRM_TO(16, 22); | ||
| 113 | STG_WRITE_REG(DACPixelFormat, tmp); | ||
| 114 | |||
| 115 | /* Set Vertical scaling to default */ | ||
| 116 | tmp = STG_READ_REG(DACVerticalScal); | ||
| 117 | CLEAR_BITS_FRM_TO(0, 11); | ||
| 118 | CLEAR_BITS_FRM_TO(16, 22); | ||
| 119 | tmp |= STG4000_NO_SCALING; /* Set to no scaling */ | ||
| 120 | STG_WRITE_REG(DACVerticalScal, tmp); | ||
| 121 | |||
| 122 | /* Set Horizontal Scaling to default */ | ||
| 123 | tmp = STG_READ_REG(DACHorizontalScal); | ||
| 124 | CLEAR_BITS_FRM_TO(0, 11); | ||
| 125 | CLEAR_BITS_FRM_TO(16, 17); | ||
| 126 | tmp |= STG4000_NO_SCALING; /* Set to no scaling */ | ||
| 127 | STG_WRITE_REG(DACHorizontalScal, tmp); | ||
| 128 | |||
| 129 | /* Set Blend mode to Alpha Blend */ | ||
| 130 | /* ????? SG 08/11/2001 Surely this isn't the alpha blend mode, | ||
| 131 | hopefully its overwrite | ||
| 132 | */ | ||
| 133 | tmp = STG_READ_REG(DACBlendCtrl); | ||
| 134 | CLEAR_BITS_FRM_TO(0, 30); | ||
| 135 | tmp = (GRAPHICS_MODE << 28); | ||
| 136 | STG_WRITE_REG(DACBlendCtrl, tmp); | ||
| 137 | |||
| 138 | } | ||
| 139 | |||
| 140 | int CreateOverlaySurface(volatile STG4000REG __iomem *pSTGReg, | ||
| 141 | u32 inWidth, | ||
| 142 | u32 inHeight, | ||
| 143 | int bLinear, | ||
| 144 | u32 ulOverlayOffset, | ||
| 145 | u32 * retStride, u32 * retUVStride) | ||
| 146 | { | ||
| 147 | u32 tmp; | ||
| 148 | u32 ulStride; | ||
| 149 | |||
| 150 | if (inWidth > STG4000_OVRL_MAX_WIDTH || | ||
| 151 | inHeight > STG4000_OVRL_MAX_HEIGHT) { | ||
| 152 | return -EINVAL; | ||
| 153 | } | ||
| 154 | |||
| 155 | /* Stride in 16 byte words - 16Bpp */ | ||
| 156 | if (bLinear) { | ||
| 157 | /* Format is 16bits so num 16 byte words is width/8 */ | ||
| 158 | if ((inWidth & 0x7) == 0) { /* inWidth % 8 */ | ||
| 159 | ulStride = (inWidth / 8); | ||
| 160 | } else { | ||
| 161 | /* Round up to next 16byte boundary */ | ||
| 162 | ulStride = ((inWidth + 8) / 8); | ||
| 163 | } | ||
| 164 | } else { | ||
| 165 | /* Y component is 8bits so num 16 byte words is width/16 */ | ||
| 166 | if ((inWidth & 0xf) == 0) { /* inWidth % 16 */ | ||
| 167 | ulStride = (inWidth / 16); | ||
| 168 | } else { | ||
| 169 | /* Round up to next 16byte boundary */ | ||
| 170 | ulStride = ((inWidth + 16) / 16); | ||
| 171 | } | ||
| 172 | } | ||
| 173 | |||
| 174 | |||
| 175 | /* Set Overlay address and Format mode */ | ||
| 176 | tmp = STG_READ_REG(DACOverlayAddr); | ||
| 177 | CLEAR_BITS_FRM_TO(0, 20); | ||
| 178 | if (bLinear) { | ||
| 179 | CLEAR_BIT(31); /* Overlay format to Linear */ | ||
| 180 | } else { | ||
| 181 | tmp |= SET_BIT(31); /* Overlay format to Planer */ | ||
| 182 | } | ||
| 183 | |||
| 184 | /* Only bits 24:4 of the Overlay address */ | ||
| 185 | tmp |= (ulOverlayOffset >> 4); | ||
| 186 | STG_WRITE_REG(DACOverlayAddr, tmp); | ||
| 187 | |||
| 188 | if (!bLinear) { | ||
| 189 | u32 uvSize = | ||
| 190 | (inWidth & 0x1) ? (inWidth + 1 / 2) : (inWidth / 2); | ||
| 191 | u32 uvStride; | ||
| 192 | u32 ulOffset; | ||
| 193 | /* Y component is 8bits so num 32 byte words is width/32 */ | ||
| 194 | if ((uvSize & 0xf) == 0) { /* inWidth % 16 */ | ||
| 195 | uvStride = (uvSize / 16); | ||
| 196 | } else { | ||
| 197 | /* Round up to next 32byte boundary */ | ||
| 198 | uvStride = ((uvSize + 16) / 16); | ||
| 199 | } | ||
| 200 | |||
| 201 | ulOffset = ulOverlayOffset + (inHeight * (ulStride * 16)); | ||
| 202 | /* Align U,V data to 32byte boundary */ | ||
| 203 | if ((ulOffset & 0x1f) != 0) | ||
| 204 | ulOffset = (ulOffset + 32L) & 0xffffffE0L; | ||
| 205 | |||
| 206 | tmp = STG_READ_REG(DACOverlayUAddr); | ||
| 207 | CLEAR_BITS_FRM_TO(0, 20); | ||
| 208 | tmp |= (ulOffset >> 4); | ||
| 209 | STG_WRITE_REG(DACOverlayUAddr, tmp); | ||
| 210 | |||
| 211 | ulOffset += (inHeight / 2) * (uvStride * 16); | ||
| 212 | /* Align U,V data to 32byte boundary */ | ||
| 213 | if ((ulOffset & 0x1f) != 0) | ||
| 214 | ulOffset = (ulOffset + 32L) & 0xffffffE0L; | ||
| 215 | |||
| 216 | tmp = STG_READ_REG(DACOverlayVAddr); | ||
| 217 | CLEAR_BITS_FRM_TO(0, 20); | ||
| 218 | tmp |= (ulOffset >> 4); | ||
| 219 | STG_WRITE_REG(DACOverlayVAddr, tmp); | ||
| 220 | |||
| 221 | *retUVStride = uvStride * 16; | ||
| 222 | } | ||
| 223 | |||
| 224 | |||
| 225 | /* Set Overlay YUV pixel format | ||
| 226 | * Make sure that LUT not used - ?????? | ||
| 227 | */ | ||
| 228 | tmp = STG_READ_REG(DACPixelFormat); | ||
| 229 | /* Only support Planer or UYVY linear formats */ | ||
| 230 | CLEAR_BITS_FRM_TO(4, 9); | ||
| 231 | STG_WRITE_REG(DACPixelFormat, tmp); | ||
| 232 | |||
| 233 | ovlWidth = inWidth; | ||
| 234 | ovlHeight = inHeight; | ||
| 235 | ovlStride = ulStride; | ||
| 236 | ovlLinear = bLinear; | ||
| 237 | *retStride = ulStride << 4; /* In bytes */ | ||
| 238 | |||
| 239 | return 0; | ||
| 240 | } | ||
| 241 | |||
| 242 | int SetOverlayBlendMode(volatile STG4000REG __iomem *pSTGReg, | ||
| 243 | OVRL_BLEND_MODE mode, | ||
| 244 | u32 ulAlpha, u32 ulColorKey) | ||
| 245 | { | ||
| 246 | u32 tmp; | ||
| 247 | |||
| 248 | tmp = STG_READ_REG(DACBlendCtrl); | ||
| 249 | CLEAR_BITS_FRM_TO(28, 30); | ||
| 250 | tmp |= (mode << 28); | ||
| 251 | |||
| 252 | switch (mode) { | ||
| 253 | case COLOR_KEY: | ||
| 254 | CLEAR_BITS_FRM_TO(0, 23); | ||
| 255 | tmp |= (ulColorKey & 0x00FFFFFF); | ||
| 256 | break; | ||
| 257 | |||
| 258 | case GLOBAL_ALPHA: | ||
| 259 | CLEAR_BITS_FRM_TO(24, 27); | ||
| 260 | tmp |= ((ulAlpha & 0xF) << 24); | ||
| 261 | break; | ||
| 262 | |||
| 263 | case CK_PIXEL_ALPHA: | ||
| 264 | CLEAR_BITS_FRM_TO(0, 23); | ||
| 265 | tmp |= (ulColorKey & 0x00FFFFFF); | ||
| 266 | break; | ||
| 267 | |||
| 268 | case CK_GLOBAL_ALPHA: | ||
| 269 | CLEAR_BITS_FRM_TO(0, 23); | ||
| 270 | tmp |= (ulColorKey & 0x00FFFFFF); | ||
| 271 | CLEAR_BITS_FRM_TO(24, 27); | ||
| 272 | tmp |= ((ulAlpha & 0xF) << 24); | ||
| 273 | break; | ||
| 274 | |||
| 275 | case GRAPHICS_MODE: | ||
| 276 | case PER_PIXEL_ALPHA: | ||
| 277 | break; | ||
| 278 | |||
| 279 | default: | ||
| 280 | return -EINVAL; | ||
| 281 | } | ||
| 282 | |||
| 283 | STG_WRITE_REG(DACBlendCtrl, tmp); | ||
| 284 | |||
| 285 | return 0; | ||
| 286 | } | ||
| 287 | |||
| 288 | void EnableOverlayPlane(volatile STG4000REG __iomem *pSTGReg) | ||
| 289 | { | ||
| 290 | u32 tmp; | ||
| 291 | /* Enable Overlay */ | ||
| 292 | tmp = STG_READ_REG(DACPixelFormat); | ||
| 293 | tmp |= SET_BIT(7); | ||
| 294 | STG_WRITE_REG(DACPixelFormat, tmp); | ||
| 295 | |||
| 296 | /* Set video stream control */ | ||
| 297 | tmp = STG_READ_REG(DACStreamCtrl); | ||
| 298 | tmp |= SET_BIT(1); /* video stream */ | ||
| 299 | STG_WRITE_REG(DACStreamCtrl, tmp); | ||
| 300 | } | ||
| 301 | |||
| 302 | static u32 Overlap(u32 ulBits, u32 ulPattern) | ||
| 303 | { | ||
| 304 | u32 ulCount = 0; | ||
| 305 | |||
| 306 | while (ulBits) { | ||
| 307 | if (!(ulPattern & 1)) | ||
| 308 | ulCount++; | ||
| 309 | ulBits--; | ||
| 310 | ulPattern = ulPattern >> 1; | ||
| 311 | } | ||
| 312 | |||
| 313 | return ulCount; | ||
| 314 | |||
| 315 | } | ||
| 316 | |||
| 317 | int SetOverlayViewPort(volatile STG4000REG __iomem *pSTGReg, | ||
| 318 | u32 left, u32 top, | ||
| 319 | u32 right, u32 bottom) | ||
| 320 | { | ||
| 321 | OVRL_SRC_DEST srcDest; | ||
| 322 | |||
| 323 | u32 ulSrcTop, ulSrcBottom; | ||
| 324 | u32 ulSrc, ulDest; | ||
| 325 | u32 ulFxScale, ulFxOffset; | ||
| 326 | u32 ulHeight, ulWidth; | ||
| 327 | u32 ulPattern; | ||
| 328 | u32 ulDecimate, ulDecimated; | ||
| 329 | u32 ulApplied; | ||
| 330 | u32 ulDacXScale, ulDacYScale; | ||
| 331 | u32 ulScale; | ||
| 332 | u32 ulLeft, ulRight; | ||
| 333 | u32 ulSrcLeft, ulSrcRight; | ||
| 334 | u32 ulScaleLeft, ulScaleRight; | ||
| 335 | u32 ulhDecim; | ||
| 336 | u32 ulsVal; | ||
| 337 | u32 ulVertDecFactor; | ||
| 338 | int bResult; | ||
| 339 | u32 ulClipOff = 0; | ||
| 340 | u32 ulBits = 0; | ||
| 341 | u32 ulsAdd = 0; | ||
| 342 | u32 tmp, ulStride; | ||
| 343 | u32 ulExcessPixels, ulClip, ulExtraLines; | ||
| 344 | |||
| 345 | |||
| 346 | srcDest.ulSrcX1 = 0; | ||
| 347 | srcDest.ulSrcY1 = 0; | ||
| 348 | srcDest.ulSrcX2 = ovlWidth - 1; | ||
| 349 | srcDest.ulSrcY2 = ovlHeight - 1; | ||
| 350 | |||
| 351 | srcDest.ulDstX1 = left; | ||
| 352 | srcDest.ulDstY1 = top; | ||
| 353 | srcDest.ulDstX2 = right; | ||
| 354 | srcDest.ulDstY2 = bottom; | ||
| 355 | |||
| 356 | srcDest.lDstX1 = srcDest.ulDstX1; | ||
| 357 | srcDest.lDstY1 = srcDest.ulDstY1; | ||
| 358 | srcDest.lDstX2 = srcDest.ulDstX2; | ||
| 359 | srcDest.lDstY2 = srcDest.ulDstY2; | ||
| 360 | |||
| 361 | /************* Vertical decimation/scaling ******************/ | ||
| 362 | |||
| 363 | /* Get Src Top and Bottom */ | ||
| 364 | ulSrcTop = srcDest.ulSrcY1; | ||
| 365 | ulSrcBottom = srcDest.ulSrcY2; | ||
| 366 | |||
| 367 | ulSrc = ulSrcBottom - ulSrcTop; | ||
| 368 | ulDest = srcDest.lDstY2 - srcDest.lDstY1; /* on-screen overlay */ | ||
| 369 | |||
| 370 | if (ulSrc <= 1) | ||
| 371 | return -EINVAL; | ||
| 372 | |||
| 373 | /* First work out the position we are to display as offset from the | ||
| 374 | * source of the buffer | ||
| 375 | */ | ||
| 376 | ulFxScale = (ulDest << 11) / ulSrc; /* fixed point scale factor */ | ||
| 377 | ulFxOffset = (srcDest.lDstY2 - srcDest.ulDstY2) << 11; | ||
| 378 | |||
| 379 | ulSrcBottom = ulSrcBottom - (ulFxOffset / ulFxScale); | ||
| 380 | ulSrc = ulSrcBottom - ulSrcTop; | ||
| 381 | ulHeight = ulSrc; | ||
| 382 | |||
| 383 | ulDest = srcDest.ulDstY2 - (srcDest.ulDstY1 - 1); | ||
| 384 | ulPattern = adwDecim8[ulBits]; | ||
| 385 | |||
| 386 | /* At this point ulSrc represents the input decimator */ | ||
| 387 | if (ulSrc > ulDest) { | ||
| 388 | ulDecimate = ulSrc - ulDest; | ||
| 389 | ulBits = 0; | ||
| 390 | ulApplied = ulSrc / 32; | ||
| 391 | |||
| 392 | while (((ulBits * ulApplied) + | ||
| 393 | Overlap((ulSrc % 32), | ||
| 394 | adwDecim8[ulBits])) < ulDecimate) | ||
| 395 | ulBits++; | ||
| 396 | |||
| 397 | ulPattern = adwDecim8[ulBits]; | ||
| 398 | ulDecimated = | ||
| 399 | (ulBits * ulApplied) + Overlap((ulSrc % 32), | ||
| 400 | ulPattern); | ||
| 401 | ulSrc = ulSrc - ulDecimated; /* the number number of lines that will go into the scaler */ | ||
| 402 | } | ||
| 403 | |||
| 404 | if (ulBits && (ulBits != 32)) { | ||
| 405 | ulVertDecFactor = (63 - ulBits) / (32 - ulBits); /* vertical decimation factor scaled up to nearest integer */ | ||
| 406 | } else { | ||
| 407 | ulVertDecFactor = 1; | ||
| 408 | } | ||
| 409 | |||
| 410 | ulDacYScale = ((ulSrc - 1) * 2048) / (ulDest + 1); | ||
| 411 | |||
| 412 | tmp = STG_READ_REG(DACOverlayVtDec); /* Decimation */ | ||
| 413 | CLEAR_BITS_FRM_TO(0, 31); | ||
| 414 | tmp = ulPattern; | ||
| 415 | STG_WRITE_REG(DACOverlayVtDec, tmp); | ||
| 416 | |||
| 417 | /***************** Horizontal decimation/scaling ***************************/ | ||
| 418 | |||
| 419 | /* | ||
| 420 | * Now we handle the horizontal case, this is a simplified version of | ||
| 421 | * the vertical case in that we decimate by factors of 2. as we are | ||
| 422 | * working in words we should always be able to decimate by these | ||
| 423 | * factors. as we always have to have a buffer which is aligned to a | ||
| 424 | * whole number of 128 bit words, we must align the left side to the | ||
| 425 | * lowest to the next lowest 128 bit boundary, and the right hand edge | ||
| 426 | * to the next largets boundary, (in a similar way to how we didi it in | ||
| 427 | * PMX1) as the left and right hand edges are aligned to these | ||
| 428 | * boundaries normally this only becomes an issue when we are chopping | ||
| 429 | * of one of the sides We shall work out vertical stuff first | ||
| 430 | */ | ||
| 431 | ulSrc = srcDest.ulSrcX2 - srcDest.ulSrcX1; | ||
| 432 | ulDest = srcDest.lDstX2 - srcDest.lDstX1; | ||
| 433 | #ifdef _OLDCODE | ||
| 434 | ulLeft = srcDest.ulDstX1; | ||
| 435 | ulRight = srcDest.ulDstX2; | ||
| 436 | #else | ||
| 437 | if (srcDest.ulDstX1 > 2) { | ||
| 438 | ulLeft = srcDest.ulDstX1 + 2; | ||
| 439 | ulRight = srcDest.ulDstX2 + 1; | ||
| 440 | } else { | ||
| 441 | ulLeft = srcDest.ulDstX1; | ||
| 442 | ulRight = srcDest.ulDstX2 + 1; | ||
| 443 | } | ||
| 444 | #endif | ||
| 445 | /* first work out the position we are to display as offset from the source of the buffer */ | ||
| 446 | bResult = 1; | ||
| 447 | |||
| 448 | do { | ||
| 449 | if (ulDest == 0) | ||
| 450 | return -EINVAL; | ||
| 451 | |||
| 452 | /* source pixels per dest pixel <<11 */ | ||
| 453 | ulFxScale = ((ulSrc - 1) << 11) / (ulDest); | ||
| 454 | |||
| 455 | /* then number of destination pixels out we are */ | ||
| 456 | ulFxOffset = ulFxScale * ((srcDest.ulDstX1 - srcDest.lDstX1) + ulClipOff); | ||
| 457 | ulFxOffset >>= 11; | ||
| 458 | |||
| 459 | /* this replaces the code which was making a decision as to use either ulFxOffset or ulSrcX1 */ | ||
| 460 | ulSrcLeft = srcDest.ulSrcX1 + ulFxOffset; | ||
| 461 | |||
| 462 | /* then number of destination pixels out we are */ | ||
| 463 | ulFxOffset = ulFxScale * (srcDest.lDstX2 - srcDest.ulDstX2); | ||
| 464 | ulFxOffset >>= 11; | ||
| 465 | |||
| 466 | ulSrcRight = srcDest.ulSrcX2 - ulFxOffset; | ||
| 467 | |||
| 468 | /* | ||
| 469 | * we must align these to our 128 bit boundaries. we shall | ||
| 470 | * round down the pixel pos to the nearest 8 pixels. | ||
| 471 | */ | ||
| 472 | ulScaleLeft = ulSrcLeft; | ||
| 473 | ulScaleRight = ulSrcRight; | ||
| 474 | |||
| 475 | /* shift fxscale until it is in the range of the scaler */ | ||
| 476 | ulhDecim = 0; | ||
| 477 | ulScale = (((ulSrcRight - ulSrcLeft) - 1) << (11 - ulhDecim)) / (ulRight - ulLeft + 2); | ||
| 478 | |||
| 479 | while (ulScale > 0x800) { | ||
| 480 | ulhDecim++; | ||
| 481 | ulScale = (((ulSrcRight - ulSrcLeft) - 1) << (11 - ulhDecim)) / (ulRight - ulLeft + 2); | ||
| 482 | } | ||
| 483 | |||
| 484 | /* | ||
| 485 | * to try and get the best values We first try and use | ||
| 486 | * src/dwdest for the scale factor, then we move onto src-1 | ||
| 487 | * | ||
| 488 | * we want to check to see if we will need to clip data, if so | ||
| 489 | * then we should clip our source so that we don't need to | ||
| 490 | */ | ||
| 491 | if (!ovlLinear) { | ||
| 492 | ulSrcLeft &= ~0x1f; | ||
| 493 | |||
| 494 | /* | ||
| 495 | * we must align the right hand edge to the next 32 | ||
| 496 | * pixel` boundary, must be on a 256 boundary so u, and | ||
| 497 | * v are 128 bit aligned | ||
| 498 | */ | ||
| 499 | ulSrcRight = (ulSrcRight + 0x1f) & ~0x1f; | ||
| 500 | } else { | ||
| 501 | ulSrcLeft &= ~0x7; | ||
| 502 | |||
| 503 | /* | ||
| 504 | * we must align the right hand edge to the next | ||
| 505 | * 8pixel` boundary | ||
| 506 | */ | ||
| 507 | ulSrcRight = (ulSrcRight + 0x7) & ~0x7; | ||
| 508 | } | ||
| 509 | |||
| 510 | /* this is the input size line store needs to cope with */ | ||
| 511 | ulWidth = ulSrcRight - ulSrcLeft; | ||
| 512 | |||
| 513 | /* | ||
| 514 | * use unclipped value to work out scale factror this is the | ||
| 515 | * scale factor we want we shall now work out the horizonal | ||
| 516 | * decimation and scaling | ||
| 517 | */ | ||
| 518 | ulsVal = ((ulWidth / 8) >> ulhDecim); | ||
| 519 | |||
| 520 | if ((ulWidth != (ulsVal << ulhDecim) * 8)) | ||
| 521 | ulsAdd = 1; | ||
| 522 | |||
| 523 | /* input pixels to scaler; */ | ||
| 524 | ulSrc = ulWidth >> ulhDecim; | ||
| 525 | |||
| 526 | if (ulSrc <= 2) | ||
| 527 | return -EINVAL; | ||
| 528 | |||
| 529 | ulExcessPixels = ((((ulScaleLeft - ulSrcLeft)) << (11 - ulhDecim)) / ulScale); | ||
| 530 | |||
| 531 | ulClip = (ulSrc << 11) / ulScale; | ||
| 532 | ulClip -= (ulRight - ulLeft); | ||
| 533 | ulClip += ulExcessPixels; | ||
| 534 | |||
| 535 | if (ulClip) | ||
| 536 | ulClip--; | ||
| 537 | |||
| 538 | /* We may need to do more here if we really have a HW rev < 5 */ | ||
| 539 | } while (!bResult); | ||
| 540 | |||
| 541 | ulExtraLines = (1 << ulhDecim) * ulVertDecFactor; | ||
| 542 | ulExtraLines += 64; | ||
| 543 | ulHeight += ulExtraLines; | ||
| 544 | |||
| 545 | ulDacXScale = ulScale; | ||
| 546 | |||
| 547 | |||
| 548 | tmp = STG_READ_REG(DACVerticalScal); | ||
| 549 | CLEAR_BITS_FRM_TO(0, 11); | ||
| 550 | CLEAR_BITS_FRM_TO(16, 22); /* Vertical Scaling */ | ||
| 551 | |||
| 552 | /* Calculate new output line stride, this is always the number of 422 | ||
| 553 | words in the line buffer, so it doesn't matter if the | ||
| 554 | mode is 420. Then set the vertical scale register. | ||
| 555 | */ | ||
| 556 | ulStride = (ulWidth >> (ulhDecim + 3)) + ulsAdd; | ||
| 557 | tmp |= ((ulStride << 16) | (ulDacYScale)); /* DAC_LS_CTRL = stride */ | ||
| 558 | STG_WRITE_REG(DACVerticalScal, tmp); | ||
| 559 | |||
| 560 | /* Now set up the overlay size using the modified width and height | ||
| 561 | from decimate and scaling calculations | ||
| 562 | */ | ||
| 563 | tmp = STG_READ_REG(DACOverlaySize); | ||
| 564 | CLEAR_BITS_FRM_TO(0, 10); | ||
| 565 | CLEAR_BITS_FRM_TO(12, 31); | ||
| 566 | |||
| 567 | if (ovlLinear) { | ||
| 568 | tmp |= | ||
| 569 | (ovlStride | ((ulHeight + 1) << 12) | | ||
| 570 | (((ulWidth / 8) - 1) << 23)); | ||
| 571 | } else { | ||
| 572 | tmp |= | ||
| 573 | (ovlStride | ((ulHeight + 1) << 12) | | ||
| 574 | (((ulWidth / 32) - 1) << 23)); | ||
| 575 | } | ||
| 576 | |||
| 577 | STG_WRITE_REG(DACOverlaySize, tmp); | ||
| 578 | |||
| 579 | /* Set Video Window Start */ | ||
| 580 | tmp = ((ulLeft << 16)) | (srcDest.ulDstY1); | ||
| 581 | STG_WRITE_REG(DACVidWinStart, tmp); | ||
| 582 | |||
| 583 | /* Set Video Window End */ | ||
| 584 | tmp = ((ulRight) << 16) | (srcDest.ulDstY2); | ||
| 585 | STG_WRITE_REG(DACVidWinEnd, tmp); | ||
| 586 | |||
| 587 | /* Finally set up the rest of the overlay regs in the order | ||
| 588 | done in the IMG driver | ||
| 589 | */ | ||
| 590 | tmp = STG_READ_REG(DACPixelFormat); | ||
| 591 | tmp = ((ulExcessPixels << 16) | tmp) & 0x7fffffff; | ||
| 592 | STG_WRITE_REG(DACPixelFormat, tmp); | ||
| 593 | |||
| 594 | tmp = STG_READ_REG(DACHorizontalScal); | ||
| 595 | CLEAR_BITS_FRM_TO(0, 11); | ||
| 596 | CLEAR_BITS_FRM_TO(16, 17); | ||
| 597 | tmp |= ((ulhDecim << 16) | (ulDacXScale)); | ||
| 598 | STG_WRITE_REG(DACHorizontalScal, tmp); | ||
| 599 | |||
| 600 | return 0; | ||
| 601 | } | ||
diff --git a/drivers/video/fbdev/kyro/STG4000Ramdac.c b/drivers/video/fbdev/kyro/STG4000Ramdac.c new file mode 100644 index 000000000000..e6ad037e4396 --- /dev/null +++ b/drivers/video/fbdev/kyro/STG4000Ramdac.c | |||
| @@ -0,0 +1,163 @@ | |||
| 1 | /* | ||
| 2 | * linux/drivers/video/kyro/STG4000Ramdac.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 2002 STMicroelectronics | ||
| 5 | * | ||
| 6 | * This file is subject to the terms and conditions of the GNU General Public | ||
| 7 | * License. See the file COPYING in the main directory of this archive | ||
| 8 | * for more details. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <linux/kernel.h> | ||
| 12 | #include <linux/errno.h> | ||
| 13 | #include <linux/types.h> | ||
| 14 | #include <video/kyro.h> | ||
| 15 | |||
| 16 | #include "STG4000Reg.h" | ||
| 17 | #include "STG4000Interface.h" | ||
| 18 | |||
| 19 | static u32 STG_PIXEL_BUS_WIDTH = 128; /* 128 bit bus width */ | ||
| 20 | static u32 REF_CLOCK = 14318; | ||
| 21 | |||
| 22 | int InitialiseRamdac(volatile STG4000REG __iomem * pSTGReg, | ||
| 23 | u32 displayDepth, | ||
| 24 | u32 displayWidth, | ||
| 25 | u32 displayHeight, | ||
| 26 | s32 HSyncPolarity, | ||
| 27 | s32 VSyncPolarity, u32 * pixelClock) | ||
| 28 | { | ||
| 29 | u32 tmp = 0; | ||
| 30 | u32 F = 0, R = 0, P = 0; | ||
| 31 | u32 stride = 0; | ||
| 32 | u32 ulPdiv = 0; | ||
| 33 | u32 physicalPixelDepth = 0; | ||
| 34 | /* Make sure DAC is in Reset */ | ||
| 35 | tmp = STG_READ_REG(SoftwareReset); | ||
| 36 | |||
| 37 | if (tmp & 0x1) { | ||
| 38 | CLEAR_BIT(1); | ||
| 39 | STG_WRITE_REG(SoftwareReset, tmp); | ||
| 40 | } | ||
| 41 | |||
| 42 | /* Set Pixel Format */ | ||
| 43 | tmp = STG_READ_REG(DACPixelFormat); | ||
| 44 | CLEAR_BITS_FRM_TO(0, 2); | ||
| 45 | |||
| 46 | /* Set LUT not used from 16bpp to 32 bpp ??? */ | ||
| 47 | CLEAR_BITS_FRM_TO(8, 9); | ||
| 48 | |||
| 49 | switch (displayDepth) { | ||
| 50 | case 16: | ||
| 51 | { | ||
| 52 | physicalPixelDepth = 16; | ||
| 53 | tmp |= _16BPP; | ||
| 54 | break; | ||
| 55 | } | ||
| 56 | case 32: | ||
| 57 | { | ||
| 58 | /* Set for 32 bits per pixel */ | ||
| 59 | physicalPixelDepth = 32; | ||
| 60 | tmp |= _32BPP; | ||
| 61 | break; | ||
| 62 | } | ||
| 63 | default: | ||
| 64 | return -EINVAL; | ||
| 65 | } | ||
| 66 | |||
| 67 | STG_WRITE_REG(DACPixelFormat, tmp); | ||
| 68 | |||
| 69 | /* Workout Bus transfer bandwidth according to pixel format */ | ||
| 70 | ulPdiv = STG_PIXEL_BUS_WIDTH / physicalPixelDepth; | ||
| 71 | |||
| 72 | /* Get Screen Stride in pixels */ | ||
| 73 | stride = displayWidth; | ||
| 74 | |||
| 75 | /* Set Primary size info */ | ||
| 76 | tmp = STG_READ_REG(DACPrimSize); | ||
| 77 | CLEAR_BITS_FRM_TO(0, 10); | ||
| 78 | CLEAR_BITS_FRM_TO(12, 31); | ||
| 79 | tmp |= | ||
| 80 | ((((displayHeight - 1) << 12) | (((displayWidth / ulPdiv) - | ||
| 81 | 1) << 23)) | ||
| 82 | | (stride / ulPdiv)); | ||
| 83 | STG_WRITE_REG(DACPrimSize, tmp); | ||
| 84 | |||
| 85 | |||
| 86 | /* Set Pixel Clock */ | ||
| 87 | *pixelClock = ProgramClock(REF_CLOCK, *pixelClock, &F, &R, &P); | ||
| 88 | |||
| 89 | /* Set DAC PLL Mode */ | ||
| 90 | tmp = STG_READ_REG(DACPLLMode); | ||
| 91 | CLEAR_BITS_FRM_TO(0, 15); | ||
| 92 | /* tmp |= ((P-1) | ((F-2) << 2) | ((R-2) << 11)); */ | ||
| 93 | tmp |= ((P) | ((F - 2) << 2) | ((R - 2) << 11)); | ||
| 94 | STG_WRITE_REG(DACPLLMode, tmp); | ||
| 95 | |||
| 96 | /* Set Prim Address */ | ||
| 97 | tmp = STG_READ_REG(DACPrimAddress); | ||
| 98 | CLEAR_BITS_FRM_TO(0, 20); | ||
| 99 | CLEAR_BITS_FRM_TO(20, 31); | ||
| 100 | STG_WRITE_REG(DACPrimAddress, tmp); | ||
| 101 | |||
| 102 | /* Set Cursor details with HW Cursor disabled */ | ||
| 103 | tmp = STG_READ_REG(DACCursorCtrl); | ||
| 104 | tmp &= ~SET_BIT(31); | ||
| 105 | STG_WRITE_REG(DACCursorCtrl, tmp); | ||
| 106 | |||
| 107 | tmp = STG_READ_REG(DACCursorAddr); | ||
| 108 | CLEAR_BITS_FRM_TO(0, 20); | ||
| 109 | STG_WRITE_REG(DACCursorAddr, tmp); | ||
| 110 | |||
| 111 | /* Set Video Window */ | ||
| 112 | tmp = STG_READ_REG(DACVidWinStart); | ||
| 113 | CLEAR_BITS_FRM_TO(0, 10); | ||
| 114 | CLEAR_BITS_FRM_TO(16, 26); | ||
| 115 | STG_WRITE_REG(DACVidWinStart, tmp); | ||
| 116 | |||
| 117 | tmp = STG_READ_REG(DACVidWinEnd); | ||
| 118 | CLEAR_BITS_FRM_TO(0, 10); | ||
| 119 | CLEAR_BITS_FRM_TO(16, 26); | ||
| 120 | STG_WRITE_REG(DACVidWinEnd, tmp); | ||
| 121 | |||
| 122 | /* Set DAC Border Color to default */ | ||
| 123 | tmp = STG_READ_REG(DACBorderColor); | ||
| 124 | CLEAR_BITS_FRM_TO(0, 23); | ||
| 125 | STG_WRITE_REG(DACBorderColor, tmp); | ||
| 126 | |||
| 127 | /* Set Graphics and Overlay Burst Control */ | ||
| 128 | STG_WRITE_REG(DACBurstCtrl, 0x0404); | ||
| 129 | |||
| 130 | /* Set CRC Trigger to default */ | ||
| 131 | tmp = STG_READ_REG(DACCrcTrigger); | ||
| 132 | CLEAR_BIT(0); | ||
| 133 | STG_WRITE_REG(DACCrcTrigger, tmp); | ||
| 134 | |||
| 135 | /* Set Video Port Control to default */ | ||
| 136 | tmp = STG_READ_REG(DigVidPortCtrl); | ||
| 137 | CLEAR_BIT(8); | ||
| 138 | CLEAR_BITS_FRM_TO(16, 27); | ||
| 139 | CLEAR_BITS_FRM_TO(1, 3); | ||
| 140 | CLEAR_BITS_FRM_TO(10, 11); | ||
| 141 | STG_WRITE_REG(DigVidPortCtrl, tmp); | ||
| 142 | |||
| 143 | return 0; | ||
| 144 | } | ||
| 145 | |||
| 146 | /* Ramdac control, turning output to the screen on and off */ | ||
| 147 | void DisableRamdacOutput(volatile STG4000REG __iomem * pSTGReg) | ||
| 148 | { | ||
| 149 | u32 tmp; | ||
| 150 | |||
| 151 | /* Disable DAC for Graphics Stream Control */ | ||
| 152 | tmp = (STG_READ_REG(DACStreamCtrl)) & ~SET_BIT(0); | ||
| 153 | STG_WRITE_REG(DACStreamCtrl, tmp); | ||
| 154 | } | ||
| 155 | |||
| 156 | void EnableRamdacOutput(volatile STG4000REG __iomem * pSTGReg) | ||
| 157 | { | ||
| 158 | u32 tmp; | ||
| 159 | |||
| 160 | /* Enable DAC for Graphics Stream Control */ | ||
| 161 | tmp = (STG_READ_REG(DACStreamCtrl)) | SET_BIT(0); | ||
| 162 | STG_WRITE_REG(DACStreamCtrl, tmp); | ||
| 163 | } | ||
diff --git a/drivers/video/fbdev/kyro/STG4000Reg.h b/drivers/video/fbdev/kyro/STG4000Reg.h new file mode 100644 index 000000000000..50f4670e9252 --- /dev/null +++ b/drivers/video/fbdev/kyro/STG4000Reg.h | |||
| @@ -0,0 +1,283 @@ | |||
| 1 | /* | ||
| 2 | * linux/drivers/video/kyro/STG4000Reg.h | ||
| 3 | * | ||
| 4 | * Copyright (C) 2002 STMicroelectronics | ||
| 5 | * | ||
| 6 | * This file is subject to the terms and conditions of the GNU General Public | ||
| 7 | * License. See the file COPYING in the main directory of this archive | ||
| 8 | * for more details. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #ifndef _STG4000REG_H | ||
| 12 | #define _STG4000REG_H | ||
| 13 | |||
| 14 | #define DWFILL unsigned long :32 | ||
| 15 | #define WFILL unsigned short :16 | ||
| 16 | |||
| 17 | /* | ||
| 18 | * Macros that access memory mapped card registers in PCI space | ||
| 19 | * Add an appropriate section for your OS or processor architecture. | ||
| 20 | */ | ||
| 21 | #if defined(__KERNEL__) | ||
| 22 | #include <asm/page.h> | ||
| 23 | #include <asm/io.h> | ||
| 24 | #define STG_WRITE_REG(reg,data) (writel(data,&pSTGReg->reg)) | ||
| 25 | #define STG_READ_REG(reg) (readl(&pSTGReg->reg)) | ||
| 26 | #else | ||
| 27 | #define STG_WRITE_REG(reg,data) (pSTGReg->reg = data) | ||
| 28 | #define STG_READ_REG(reg) (pSTGReg->reg) | ||
| 29 | #endif /* __KERNEL__ */ | ||
| 30 | |||
| 31 | #define SET_BIT(n) (1<<(n)) | ||
| 32 | #define CLEAR_BIT(n) (tmp &= ~(1<<n)) | ||
| 33 | #define CLEAR_BITS_FRM_TO(frm, to) \ | ||
| 34 | {\ | ||
| 35 | int i; \ | ||
| 36 | for(i = frm; i<= to; i++) \ | ||
| 37 | { \ | ||
| 38 | tmp &= ~(1<<i); \ | ||
| 39 | } \ | ||
| 40 | } | ||
| 41 | |||
| 42 | #define CLEAR_BIT_2(n) (usTemp &= ~(1<<n)) | ||
| 43 | #define CLEAR_BITS_FRM_TO_2(frm, to) \ | ||
| 44 | {\ | ||
| 45 | int i; \ | ||
| 46 | for(i = frm; i<= to; i++) \ | ||
| 47 | { \ | ||
| 48 | usTemp &= ~(1<<i); \ | ||
| 49 | } \ | ||
| 50 | } | ||
| 51 | |||
| 52 | /* LUT select */ | ||
| 53 | typedef enum _LUT_USES { | ||
| 54 | NO_LUT = 0, RESERVED, GRAPHICS, OVERLAY | ||
| 55 | } LUT_USES; | ||
| 56 | |||
| 57 | /* Primary surface pixel format select */ | ||
| 58 | typedef enum _PIXEL_FORMAT { | ||
| 59 | _8BPP = 0, _15BPP, _16BPP, _24BPP, _32BPP | ||
| 60 | } PIXEL_FORMAT; | ||
| 61 | |||
| 62 | /* Overlay blending mode select */ | ||
| 63 | typedef enum _BLEND_MODE { | ||
| 64 | GRAPHICS_MODE = 0, COLOR_KEY, PER_PIXEL_ALPHA, GLOBAL_ALPHA, | ||
| 65 | CK_PIXEL_ALPHA, CK_GLOBAL_ALPHA | ||
| 66 | } OVRL_BLEND_MODE; | ||
| 67 | |||
| 68 | /* Overlay Pixel format select */ | ||
| 69 | typedef enum _OVRL_PIX_FORMAT { | ||
| 70 | UYVY, VYUY, YUYV, YVYU | ||
| 71 | } OVRL_PIX_FORMAT; | ||
| 72 | |||
| 73 | /* Register Table */ | ||
| 74 | typedef struct { | ||
| 75 | /* 0h */ | ||
| 76 | volatile u32 Thread0Enable; /* 0x0000 */ | ||
| 77 | volatile u32 Thread1Enable; /* 0x0004 */ | ||
| 78 | volatile u32 Thread0Recover; /* 0x0008 */ | ||
| 79 | volatile u32 Thread1Recover; /* 0x000C */ | ||
| 80 | volatile u32 Thread0Step; /* 0x0010 */ | ||
| 81 | volatile u32 Thread1Step; /* 0x0014 */ | ||
| 82 | volatile u32 VideoInStatus; /* 0x0018 */ | ||
| 83 | volatile u32 Core2InSignStart; /* 0x001C */ | ||
| 84 | volatile u32 Core1ResetVector; /* 0x0020 */ | ||
| 85 | volatile u32 Core1ROMOffset; /* 0x0024 */ | ||
| 86 | volatile u32 Core1ArbiterPriority; /* 0x0028 */ | ||
| 87 | volatile u32 VideoInControl; /* 0x002C */ | ||
| 88 | volatile u32 VideoInReg0CtrlA; /* 0x0030 */ | ||
| 89 | volatile u32 VideoInReg0CtrlB; /* 0x0034 */ | ||
| 90 | volatile u32 VideoInReg1CtrlA; /* 0x0038 */ | ||
| 91 | volatile u32 VideoInReg1CtrlB; /* 0x003C */ | ||
| 92 | volatile u32 Thread0Kicker; /* 0x0040 */ | ||
| 93 | volatile u32 Core2InputSign; /* 0x0044 */ | ||
| 94 | volatile u32 Thread0ProgCtr; /* 0x0048 */ | ||
| 95 | volatile u32 Thread1ProgCtr; /* 0x004C */ | ||
| 96 | volatile u32 Thread1Kicker; /* 0x0050 */ | ||
| 97 | volatile u32 GPRegister1; /* 0x0054 */ | ||
| 98 | volatile u32 GPRegister2; /* 0x0058 */ | ||
| 99 | volatile u32 GPRegister3; /* 0x005C */ | ||
| 100 | volatile u32 GPRegister4; /* 0x0060 */ | ||
| 101 | volatile u32 SerialIntA; /* 0x0064 */ | ||
| 102 | |||
| 103 | volatile u32 Fill0[6]; /* GAP 0x0068 - 0x007C */ | ||
| 104 | |||
| 105 | volatile u32 SoftwareReset; /* 0x0080 */ | ||
| 106 | volatile u32 SerialIntB; /* 0x0084 */ | ||
| 107 | |||
| 108 | volatile u32 Fill1[37]; /* GAP 0x0088 - 0x011C */ | ||
| 109 | |||
| 110 | volatile u32 ROMELQV; /* 0x011C */ | ||
| 111 | volatile u32 WLWH; /* 0x0120 */ | ||
| 112 | volatile u32 ROMELWL; /* 0x0124 */ | ||
| 113 | |||
| 114 | volatile u32 dwFill_1; /* GAP 0x0128 */ | ||
| 115 | |||
| 116 | volatile u32 IntStatus; /* 0x012C */ | ||
| 117 | volatile u32 IntMask; /* 0x0130 */ | ||
| 118 | volatile u32 IntClear; /* 0x0134 */ | ||
| 119 | |||
| 120 | volatile u32 Fill2[6]; /* GAP 0x0138 - 0x014C */ | ||
| 121 | |||
| 122 | volatile u32 ROMGPIOA; /* 0x0150 */ | ||
| 123 | volatile u32 ROMGPIOB; /* 0x0154 */ | ||
| 124 | volatile u32 ROMGPIOC; /* 0x0158 */ | ||
| 125 | volatile u32 ROMGPIOD; /* 0x015C */ | ||
| 126 | |||
| 127 | volatile u32 Fill3[2]; /* GAP 0x0160 - 0x0168 */ | ||
| 128 | |||
| 129 | volatile u32 AGPIntID; /* 0x0168 */ | ||
| 130 | volatile u32 AGPIntClassCode; /* 0x016C */ | ||
| 131 | volatile u32 AGPIntBIST; /* 0x0170 */ | ||
| 132 | volatile u32 AGPIntSSID; /* 0x0174 */ | ||
| 133 | volatile u32 AGPIntPMCSR; /* 0x0178 */ | ||
| 134 | volatile u32 VGAFrameBufBase; /* 0x017C */ | ||
| 135 | volatile u32 VGANotify; /* 0x0180 */ | ||
| 136 | volatile u32 DACPLLMode; /* 0x0184 */ | ||
| 137 | volatile u32 Core1VideoClockDiv; /* 0x0188 */ | ||
| 138 | volatile u32 AGPIntStat; /* 0x018C */ | ||
| 139 | |||
| 140 | /* | ||
| 141 | volatile u32 Fill4[0x0400/4 - 0x0190/4]; //GAP 0x0190 - 0x0400 | ||
| 142 | volatile u32 Fill5[0x05FC/4 - 0x0400/4]; //GAP 0x0400 - 0x05FC Fog Table | ||
| 143 | volatile u32 Fill6[0x0604/4 - 0x0600/4]; //GAP 0x0600 - 0x0604 | ||
| 144 | volatile u32 Fill7[0x0680/4 - 0x0608/4]; //GAP 0x0608 - 0x0680 | ||
| 145 | volatile u32 Fill8[0x07FC/4 - 0x0684/4]; //GAP 0x0684 - 0x07FC | ||
| 146 | */ | ||
| 147 | volatile u32 Fill4[412]; /* 0x0190 - 0x07FC */ | ||
| 148 | |||
| 149 | volatile u32 TACtrlStreamBase; /* 0x0800 */ | ||
| 150 | volatile u32 TAObjDataBase; /* 0x0804 */ | ||
| 151 | volatile u32 TAPtrDataBase; /* 0x0808 */ | ||
| 152 | volatile u32 TARegionDataBase; /* 0x080C */ | ||
| 153 | volatile u32 TATailPtrBase; /* 0x0810 */ | ||
| 154 | volatile u32 TAPtrRegionSize; /* 0x0814 */ | ||
| 155 | volatile u32 TAConfiguration; /* 0x0818 */ | ||
| 156 | volatile u32 TAObjDataStartAddr; /* 0x081C */ | ||
| 157 | volatile u32 TAObjDataEndAddr; /* 0x0820 */ | ||
| 158 | volatile u32 TAXScreenClip; /* 0x0824 */ | ||
| 159 | volatile u32 TAYScreenClip; /* 0x0828 */ | ||
| 160 | volatile u32 TARHWClamp; /* 0x082C */ | ||
| 161 | volatile u32 TARHWCompare; /* 0x0830 */ | ||
| 162 | volatile u32 TAStart; /* 0x0834 */ | ||
| 163 | volatile u32 TAObjReStart; /* 0x0838 */ | ||
| 164 | volatile u32 TAPtrReStart; /* 0x083C */ | ||
| 165 | volatile u32 TAStatus1; /* 0x0840 */ | ||
| 166 | volatile u32 TAStatus2; /* 0x0844 */ | ||
| 167 | volatile u32 TAIntStatus; /* 0x0848 */ | ||
| 168 | volatile u32 TAIntMask; /* 0x084C */ | ||
| 169 | |||
| 170 | volatile u32 Fill5[235]; /* GAP 0x0850 - 0x0BF8 */ | ||
| 171 | |||
| 172 | volatile u32 TextureAddrThresh; /* 0x0BFC */ | ||
| 173 | volatile u32 Core1Translation; /* 0x0C00 */ | ||
| 174 | volatile u32 TextureAddrReMap; /* 0x0C04 */ | ||
| 175 | volatile u32 RenderOutAGPRemap; /* 0x0C08 */ | ||
| 176 | volatile u32 _3DRegionReadTrans; /* 0x0C0C */ | ||
| 177 | volatile u32 _3DPtrReadTrans; /* 0x0C10 */ | ||
| 178 | volatile u32 _3DParamReadTrans; /* 0x0C14 */ | ||
| 179 | volatile u32 _3DRegionReadThresh; /* 0x0C18 */ | ||
| 180 | volatile u32 _3DPtrReadThresh; /* 0x0C1C */ | ||
| 181 | volatile u32 _3DParamReadThresh; /* 0x0C20 */ | ||
| 182 | volatile u32 _3DRegionReadAGPRemap; /* 0x0C24 */ | ||
| 183 | volatile u32 _3DPtrReadAGPRemap; /* 0x0C28 */ | ||
| 184 | volatile u32 _3DParamReadAGPRemap; /* 0x0C2C */ | ||
| 185 | volatile u32 ZBufferAGPRemap; /* 0x0C30 */ | ||
| 186 | volatile u32 TAIndexAGPRemap; /* 0x0C34 */ | ||
| 187 | volatile u32 TAVertexAGPRemap; /* 0x0C38 */ | ||
| 188 | volatile u32 TAUVAddrTrans; /* 0x0C3C */ | ||
| 189 | volatile u32 TATailPtrCacheTrans; /* 0x0C40 */ | ||
| 190 | volatile u32 TAParamWriteTrans; /* 0x0C44 */ | ||
| 191 | volatile u32 TAPtrWriteTrans; /* 0x0C48 */ | ||
| 192 | volatile u32 TAParamWriteThresh; /* 0x0C4C */ | ||
| 193 | volatile u32 TAPtrWriteThresh; /* 0x0C50 */ | ||
| 194 | volatile u32 TATailPtrCacheAGPRe; /* 0x0C54 */ | ||
| 195 | volatile u32 TAParamWriteAGPRe; /* 0x0C58 */ | ||
| 196 | volatile u32 TAPtrWriteAGPRe; /* 0x0C5C */ | ||
| 197 | volatile u32 SDRAMArbiterConf; /* 0x0C60 */ | ||
| 198 | volatile u32 SDRAMConf0; /* 0x0C64 */ | ||
| 199 | volatile u32 SDRAMConf1; /* 0x0C68 */ | ||
| 200 | volatile u32 SDRAMConf2; /* 0x0C6C */ | ||
| 201 | volatile u32 SDRAMRefresh; /* 0x0C70 */ | ||
| 202 | volatile u32 SDRAMPowerStat; /* 0x0C74 */ | ||
| 203 | |||
| 204 | volatile u32 Fill6[2]; /* GAP 0x0C78 - 0x0C7C */ | ||
| 205 | |||
| 206 | volatile u32 RAMBistData; /* 0x0C80 */ | ||
| 207 | volatile u32 RAMBistCtrl; /* 0x0C84 */ | ||
| 208 | volatile u32 FIFOBistKey; /* 0x0C88 */ | ||
| 209 | volatile u32 RAMBistResult; /* 0x0C8C */ | ||
| 210 | volatile u32 FIFOBistResult; /* 0x0C90 */ | ||
| 211 | |||
| 212 | /* | ||
| 213 | volatile u32 Fill11[0x0CBC/4 - 0x0C94/4]; //GAP 0x0C94 - 0x0CBC | ||
| 214 | volatile u32 Fill12[0x0CD0/4 - 0x0CC0/4]; //GAP 0x0CC0 - 0x0CD0 3DRegisters | ||
| 215 | */ | ||
| 216 | |||
| 217 | volatile u32 Fill7[16]; /* 0x0c94 - 0x0cd0 */ | ||
| 218 | |||
| 219 | volatile u32 SDRAMAddrSign; /* 0x0CD4 */ | ||
| 220 | volatile u32 SDRAMDataSign; /* 0x0CD8 */ | ||
| 221 | volatile u32 SDRAMSignConf; /* 0x0CDC */ | ||
| 222 | |||
| 223 | /* DWFILL; //GAP 0x0CE0 */ | ||
| 224 | volatile u32 dwFill_2; | ||
| 225 | |||
| 226 | volatile u32 ISPSignature; /* 0x0CE4 */ | ||
| 227 | |||
| 228 | volatile u32 Fill8[454]; /*GAP 0x0CE8 - 0x13FC */ | ||
| 229 | |||
| 230 | volatile u32 DACPrimAddress; /* 0x1400 */ | ||
| 231 | volatile u32 DACPrimSize; /* 0x1404 */ | ||
| 232 | volatile u32 DACCursorAddr; /* 0x1408 */ | ||
| 233 | volatile u32 DACCursorCtrl; /* 0x140C */ | ||
| 234 | volatile u32 DACOverlayAddr; /* 0x1410 */ | ||
| 235 | volatile u32 DACOverlayUAddr; /* 0x1414 */ | ||
| 236 | volatile u32 DACOverlayVAddr; /* 0x1418 */ | ||
| 237 | volatile u32 DACOverlaySize; /* 0x141C */ | ||
| 238 | volatile u32 DACOverlayVtDec; /* 0x1420 */ | ||
| 239 | |||
| 240 | volatile u32 Fill9[9]; /* GAP 0x1424 - 0x1444 */ | ||
| 241 | |||
| 242 | volatile u32 DACVerticalScal; /* 0x1448 */ | ||
| 243 | volatile u32 DACPixelFormat; /* 0x144C */ | ||
| 244 | volatile u32 DACHorizontalScal; /* 0x1450 */ | ||
| 245 | volatile u32 DACVidWinStart; /* 0x1454 */ | ||
| 246 | volatile u32 DACVidWinEnd; /* 0x1458 */ | ||
| 247 | volatile u32 DACBlendCtrl; /* 0x145C */ | ||
| 248 | volatile u32 DACHorTim1; /* 0x1460 */ | ||
| 249 | volatile u32 DACHorTim2; /* 0x1464 */ | ||
| 250 | volatile u32 DACHorTim3; /* 0x1468 */ | ||
| 251 | volatile u32 DACVerTim1; /* 0x146C */ | ||
| 252 | volatile u32 DACVerTim2; /* 0x1470 */ | ||
| 253 | volatile u32 DACVerTim3; /* 0x1474 */ | ||
| 254 | volatile u32 DACBorderColor; /* 0x1478 */ | ||
| 255 | volatile u32 DACSyncCtrl; /* 0x147C */ | ||
| 256 | volatile u32 DACStreamCtrl; /* 0x1480 */ | ||
| 257 | volatile u32 DACLUTAddress; /* 0x1484 */ | ||
| 258 | volatile u32 DACLUTData; /* 0x1488 */ | ||
| 259 | volatile u32 DACBurstCtrl; /* 0x148C */ | ||
| 260 | volatile u32 DACCrcTrigger; /* 0x1490 */ | ||
| 261 | volatile u32 DACCrcDone; /* 0x1494 */ | ||
| 262 | volatile u32 DACCrcResult1; /* 0x1498 */ | ||
| 263 | volatile u32 DACCrcResult2; /* 0x149C */ | ||
| 264 | volatile u32 DACLinecount; /* 0x14A0 */ | ||
| 265 | |||
| 266 | volatile u32 Fill10[151]; /*GAP 0x14A4 - 0x16FC */ | ||
| 267 | |||
| 268 | volatile u32 DigVidPortCtrl; /* 0x1700 */ | ||
| 269 | volatile u32 DigVidPortStat; /* 0x1704 */ | ||
| 270 | |||
| 271 | /* | ||
| 272 | volatile u32 Fill11[0x1FFC/4 - 0x1708/4]; //GAP 0x1708 - 0x1FFC | ||
| 273 | volatile u32 Fill17[0x3000/4 - 0x2FFC/4]; //GAP 0x2000 - 0x2FFC ALUT | ||
| 274 | */ | ||
| 275 | |||
| 276 | volatile u32 Fill11[1598]; | ||
| 277 | |||
| 278 | /* DWFILL; //GAP 0x3000 ALUT 256MB offset */ | ||
| 279 | volatile u32 Fill_3; | ||
| 280 | |||
| 281 | } STG4000REG; | ||
| 282 | |||
| 283 | #endif /* _STG4000REG_H */ | ||
diff --git a/drivers/video/fbdev/kyro/STG4000VTG.c b/drivers/video/fbdev/kyro/STG4000VTG.c new file mode 100644 index 000000000000..bd389709d234 --- /dev/null +++ b/drivers/video/fbdev/kyro/STG4000VTG.c | |||
| @@ -0,0 +1,170 @@ | |||
| 1 | /* | ||
| 2 | * linux/drivers/video/kyro/STG4000VTG.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 2002 STMicroelectronics | ||
| 5 | * | ||
| 6 | * This file is subject to the terms and conditions of the GNU General Public | ||
| 7 | * License. See the file COPYING in the main directory of this archive | ||
| 8 | * for more details. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <linux/types.h> | ||
| 12 | #include <video/kyro.h> | ||
| 13 | |||
| 14 | #include "STG4000Reg.h" | ||
| 15 | #include "STG4000Interface.h" | ||
| 16 | |||
| 17 | void DisableVGA(volatile STG4000REG __iomem *pSTGReg) | ||
| 18 | { | ||
| 19 | u32 tmp; | ||
| 20 | volatile u32 count = 0, i; | ||
| 21 | |||
| 22 | /* Reset the VGA registers */ | ||
| 23 | tmp = STG_READ_REG(SoftwareReset); | ||
| 24 | CLEAR_BIT(8); | ||
| 25 | STG_WRITE_REG(SoftwareReset, tmp); | ||
| 26 | |||
| 27 | /* Just for Delay */ | ||
| 28 | for (i = 0; i < 1000; i++) { | ||
| 29 | count++; | ||
| 30 | } | ||
| 31 | |||
| 32 | /* Pull-out the VGA registers from reset */ | ||
| 33 | tmp = STG_READ_REG(SoftwareReset); | ||
| 34 | tmp |= SET_BIT(8); | ||
| 35 | STG_WRITE_REG(SoftwareReset, tmp); | ||
| 36 | } | ||
| 37 | |||
| 38 | void StopVTG(volatile STG4000REG __iomem *pSTGReg) | ||
| 39 | { | ||
| 40 | u32 tmp = 0; | ||
| 41 | |||
| 42 | /* Stop Ver and Hor Sync Generator */ | ||
| 43 | tmp = (STG_READ_REG(DACSyncCtrl)) | SET_BIT(0) | SET_BIT(2); | ||
| 44 | CLEAR_BIT(31); | ||
| 45 | STG_WRITE_REG(DACSyncCtrl, tmp); | ||
| 46 | } | ||
| 47 | |||
| 48 | void StartVTG(volatile STG4000REG __iomem *pSTGReg) | ||
| 49 | { | ||
| 50 | u32 tmp = 0; | ||
| 51 | |||
| 52 | /* Start Ver and Hor Sync Generator */ | ||
| 53 | tmp = ((STG_READ_REG(DACSyncCtrl)) | SET_BIT(31)); | ||
| 54 | CLEAR_BIT(0); | ||
| 55 | CLEAR_BIT(2); | ||
| 56 | STG_WRITE_REG(DACSyncCtrl, tmp); | ||
| 57 | } | ||
| 58 | |||
| 59 | void SetupVTG(volatile STG4000REG __iomem *pSTGReg, | ||
| 60 | const struct kyrofb_info * pTiming) | ||
| 61 | { | ||
| 62 | u32 tmp = 0; | ||
| 63 | u32 margins = 0; | ||
| 64 | u32 ulBorder; | ||
| 65 | u32 xRes = pTiming->XRES; | ||
| 66 | u32 yRes = pTiming->YRES; | ||
| 67 | |||
| 68 | /* Horizontal */ | ||
| 69 | u32 HAddrTime, HRightBorder, HLeftBorder; | ||
| 70 | u32 HBackPorcStrt, HFrontPorchStrt, HTotal, | ||
| 71 | HLeftBorderStrt, HRightBorderStrt, HDisplayStrt; | ||
| 72 | |||
| 73 | /* Vertical */ | ||
| 74 | u32 VDisplayStrt, VBottomBorder, VTopBorder; | ||
| 75 | u32 VBackPorchStrt, VTotal, VTopBorderStrt, | ||
| 76 | VFrontPorchStrt, VBottomBorderStrt, VAddrTime; | ||
| 77 | |||
| 78 | /* Need to calculate the right border */ | ||
| 79 | if ((xRes == 640) && (yRes == 480)) { | ||
| 80 | if ((pTiming->VFREQ == 60) || (pTiming->VFREQ == 72)) { | ||
| 81 | margins = 8; | ||
| 82 | } | ||
| 83 | } | ||
| 84 | |||
| 85 | /* Work out the Border */ | ||
| 86 | ulBorder = | ||
| 87 | (pTiming->HTot - | ||
| 88 | (pTiming->HST + (pTiming->HBP - margins) + xRes + | ||
| 89 | (pTiming->HFP - margins))) >> 1; | ||
| 90 | |||
| 91 | /* Border the same for Vertical and Horizontal */ | ||
| 92 | VBottomBorder = HLeftBorder = VTopBorder = HRightBorder = ulBorder; | ||
| 93 | |||
| 94 | /************ Get Timing values for Horizontal ******************/ | ||
| 95 | HAddrTime = xRes; | ||
| 96 | HBackPorcStrt = pTiming->HST; | ||
| 97 | HTotal = pTiming->HTot; | ||
| 98 | HDisplayStrt = | ||
| 99 | pTiming->HST + (pTiming->HBP - margins) + HLeftBorder; | ||
| 100 | HLeftBorderStrt = HDisplayStrt - HLeftBorder; | ||
| 101 | HFrontPorchStrt = | ||
| 102 | pTiming->HST + (pTiming->HBP - margins) + HLeftBorder + | ||
| 103 | HAddrTime + HRightBorder; | ||
| 104 | HRightBorderStrt = HFrontPorchStrt - HRightBorder; | ||
| 105 | |||
| 106 | /************ Get Timing values for Vertical ******************/ | ||
| 107 | VAddrTime = yRes; | ||
| 108 | VBackPorchStrt = pTiming->VST; | ||
| 109 | VTotal = pTiming->VTot; | ||
| 110 | VDisplayStrt = | ||
| 111 | pTiming->VST + (pTiming->VBP - margins) + VTopBorder; | ||
| 112 | VTopBorderStrt = VDisplayStrt - VTopBorder; | ||
| 113 | VFrontPorchStrt = | ||
| 114 | pTiming->VST + (pTiming->VBP - margins) + VTopBorder + | ||
| 115 | VAddrTime + VBottomBorder; | ||
| 116 | VBottomBorderStrt = VFrontPorchStrt - VBottomBorder; | ||
| 117 | |||
| 118 | /* Set Hor Timing 1, 2, 3 */ | ||
| 119 | tmp = STG_READ_REG(DACHorTim1); | ||
| 120 | CLEAR_BITS_FRM_TO(0, 11); | ||
| 121 | CLEAR_BITS_FRM_TO(16, 27); | ||
| 122 | tmp |= (HTotal) | (HBackPorcStrt << 16); | ||
| 123 | STG_WRITE_REG(DACHorTim1, tmp); | ||
| 124 | |||
| 125 | tmp = STG_READ_REG(DACHorTim2); | ||
| 126 | CLEAR_BITS_FRM_TO(0, 11); | ||
| 127 | CLEAR_BITS_FRM_TO(16, 27); | ||
| 128 | tmp |= (HDisplayStrt << 16) | HLeftBorderStrt; | ||
| 129 | STG_WRITE_REG(DACHorTim2, tmp); | ||
| 130 | |||
| 131 | tmp = STG_READ_REG(DACHorTim3); | ||
| 132 | CLEAR_BITS_FRM_TO(0, 11); | ||
| 133 | CLEAR_BITS_FRM_TO(16, 27); | ||
| 134 | tmp |= (HFrontPorchStrt << 16) | HRightBorderStrt; | ||
| 135 | STG_WRITE_REG(DACHorTim3, tmp); | ||
| 136 | |||
| 137 | /* Set Ver Timing 1, 2, 3 */ | ||
| 138 | tmp = STG_READ_REG(DACVerTim1); | ||
| 139 | CLEAR_BITS_FRM_TO(0, 11); | ||
| 140 | CLEAR_BITS_FRM_TO(16, 27); | ||
| 141 | tmp |= (VBackPorchStrt << 16) | (VTotal); | ||
| 142 | STG_WRITE_REG(DACVerTim1, tmp); | ||
| 143 | |||
| 144 | tmp = STG_READ_REG(DACVerTim2); | ||
| 145 | CLEAR_BITS_FRM_TO(0, 11); | ||
| 146 | CLEAR_BITS_FRM_TO(16, 27); | ||
| 147 | tmp |= (VDisplayStrt << 16) | VTopBorderStrt; | ||
| 148 | STG_WRITE_REG(DACVerTim2, tmp); | ||
| 149 | |||
| 150 | tmp = STG_READ_REG(DACVerTim3); | ||
| 151 | CLEAR_BITS_FRM_TO(0, 11); | ||
| 152 | CLEAR_BITS_FRM_TO(16, 27); | ||
| 153 | tmp |= (VFrontPorchStrt << 16) | VBottomBorderStrt; | ||
| 154 | STG_WRITE_REG(DACVerTim3, tmp); | ||
| 155 | |||
| 156 | /* Set Verical and Horizontal Polarity */ | ||
| 157 | tmp = STG_READ_REG(DACSyncCtrl) | SET_BIT(3) | SET_BIT(1); | ||
| 158 | |||
| 159 | if ((pTiming->HSP > 0) && (pTiming->VSP < 0)) { /* +hsync -vsync */ | ||
| 160 | tmp &= ~0x8; | ||
| 161 | } else if ((pTiming->HSP < 0) && (pTiming->VSP > 0)) { /* -hsync +vsync */ | ||
| 162 | tmp &= ~0x2; | ||
| 163 | } else if ((pTiming->HSP < 0) && (pTiming->VSP < 0)) { /* -hsync -vsync */ | ||
| 164 | tmp &= ~0xA; | ||
| 165 | } else if ((pTiming->HSP > 0) && (pTiming->VSP > 0)) { /* +hsync -vsync */ | ||
| 166 | tmp &= ~0x0; | ||
| 167 | } | ||
| 168 | |||
| 169 | STG_WRITE_REG(DACSyncCtrl, tmp); | ||
| 170 | } | ||
diff --git a/drivers/video/fbdev/kyro/fbdev.c b/drivers/video/fbdev/kyro/fbdev.c new file mode 100644 index 000000000000..65041e15fd59 --- /dev/null +++ b/drivers/video/fbdev/kyro/fbdev.c | |||
| @@ -0,0 +1,808 @@ | |||
| 1 | /* | ||
| 2 | * linux/drivers/video/kyro/fbdev.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 2002 STMicroelectronics | ||
| 5 | * Copyright (C) 2003, 2004 Paul Mundt | ||
| 6 | * | ||
| 7 | * This file is subject to the terms and conditions of the GNU General Public | ||
| 8 | * License. See the file COPYING in the main directory of this archive | ||
| 9 | * for more details. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/module.h> | ||
| 13 | #include <linux/types.h> | ||
| 14 | #include <linux/kernel.h> | ||
| 15 | #include <linux/mm.h> | ||
| 16 | #include <linux/errno.h> | ||
| 17 | #include <linux/string.h> | ||
| 18 | #include <linux/delay.h> | ||
| 19 | #include <linux/fb.h> | ||
| 20 | #include <linux/ioctl.h> | ||
| 21 | #include <linux/init.h> | ||
| 22 | #include <linux/pci.h> | ||
| 23 | #include <asm/io.h> | ||
| 24 | #include <linux/uaccess.h> | ||
| 25 | #ifdef CONFIG_MTRR | ||
| 26 | #include <asm/mtrr.h> | ||
| 27 | #endif | ||
| 28 | |||
| 29 | #include <video/kyro.h> | ||
| 30 | |||
| 31 | #include "STG4000Reg.h" | ||
| 32 | #include "STG4000Interface.h" | ||
| 33 | |||
| 34 | /* | ||
| 35 | * PCI Definitions | ||
| 36 | */ | ||
| 37 | #define PCI_VENDOR_ID_ST 0x104a | ||
| 38 | #define PCI_DEVICE_ID_STG4000 0x0010 | ||
| 39 | |||
| 40 | #define KHZ2PICOS(a) (1000000000UL/(a)) | ||
| 41 | |||
| 42 | /****************************************************************************/ | ||
| 43 | static struct fb_fix_screeninfo kyro_fix = { | ||
| 44 | .id = "ST Kyro", | ||
| 45 | .type = FB_TYPE_PACKED_PIXELS, | ||
| 46 | .visual = FB_VISUAL_TRUECOLOR, | ||
| 47 | .accel = FB_ACCEL_NONE, | ||
| 48 | }; | ||
| 49 | |||
| 50 | static struct fb_var_screeninfo kyro_var = { | ||
| 51 | /* 640x480, 16bpp @ 60 Hz */ | ||
| 52 | .xres = 640, | ||
| 53 | .yres = 480, | ||
| 54 | .xres_virtual = 640, | ||
| 55 | .yres_virtual = 480, | ||
| 56 | .bits_per_pixel = 16, | ||
| 57 | .red = { 11, 5, 0 }, | ||
| 58 | .green = { 5, 6, 0 }, | ||
| 59 | .blue = { 0, 5, 0 }, | ||
| 60 | .activate = FB_ACTIVATE_NOW, | ||
| 61 | .height = -1, | ||
| 62 | .width = -1, | ||
| 63 | .pixclock = KHZ2PICOS(25175), | ||
| 64 | .left_margin = 48, | ||
| 65 | .right_margin = 16, | ||
| 66 | .upper_margin = 33, | ||
| 67 | .lower_margin = 10, | ||
| 68 | .hsync_len = 96, | ||
| 69 | .vsync_len = 2, | ||
| 70 | .vmode = FB_VMODE_NONINTERLACED, | ||
| 71 | }; | ||
| 72 | |||
| 73 | typedef struct { | ||
| 74 | STG4000REG __iomem *pSTGReg; /* Virtual address of PCI register region */ | ||
| 75 | u32 ulNextFreeVidMem; /* Offset from start of vid mem to next free region */ | ||
| 76 | u32 ulOverlayOffset; /* Offset from start of vid mem to overlay */ | ||
| 77 | u32 ulOverlayStride; /* Interleaved YUV and 422 mode Y stride */ | ||
| 78 | u32 ulOverlayUVStride; /* 422 mode U & V stride */ | ||
| 79 | } device_info_t; | ||
| 80 | |||
| 81 | /* global graphics card info structure (one per card) */ | ||
| 82 | static device_info_t deviceInfo; | ||
| 83 | |||
| 84 | static char *mode_option = NULL; | ||
| 85 | static int nopan = 0; | ||
| 86 | static int nowrap = 1; | ||
| 87 | #ifdef CONFIG_MTRR | ||
| 88 | static int nomtrr = 0; | ||
| 89 | #endif | ||
| 90 | |||
| 91 | /* PCI driver prototypes */ | ||
| 92 | static int kyrofb_probe(struct pci_dev *pdev, const struct pci_device_id *ent); | ||
| 93 | static void kyrofb_remove(struct pci_dev *pdev); | ||
| 94 | |||
| 95 | static struct fb_videomode kyro_modedb[] = { | ||
| 96 | { | ||
| 97 | /* 640x350 @ 85Hz */ | ||
| 98 | NULL, 85, 640, 350, KHZ2PICOS(31500), | ||
| 99 | 96, 32, 60, 32, 64, 3, | ||
| 100 | FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED | ||
| 101 | }, { | ||
| 102 | /* 640x400 @ 85Hz */ | ||
| 103 | NULL, 85, 640, 400, KHZ2PICOS(31500), | ||
| 104 | 96, 32, 41, 1, 64, 3, | ||
| 105 | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED | ||
| 106 | }, { | ||
| 107 | /* 720x400 @ 85Hz */ | ||
| 108 | NULL, 85, 720, 400, KHZ2PICOS(35500), | ||
| 109 | 108, 36, 42, 1, 72, 3, | ||
| 110 | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED | ||
| 111 | }, { | ||
| 112 | /* 640x480 @ 60Hz */ | ||
| 113 | NULL, 60, 640, 480, KHZ2PICOS(25175), | ||
| 114 | 48, 16, 33, 10, 96, 2, | ||
| 115 | 0, FB_VMODE_NONINTERLACED | ||
| 116 | }, { | ||
| 117 | /* 640x480 @ 72Hz */ | ||
| 118 | NULL, 72, 640, 480, KHZ2PICOS(31500), | ||
| 119 | 128, 24, 28, 9, 40, 3, | ||
| 120 | 0, FB_VMODE_NONINTERLACED | ||
| 121 | }, { | ||
| 122 | /* 640x480 @ 75Hz */ | ||
| 123 | NULL, 75, 640, 480, KHZ2PICOS(31500), | ||
| 124 | 120, 16, 16, 1, 64, 3, | ||
| 125 | 0, FB_VMODE_NONINTERLACED | ||
| 126 | }, { | ||
| 127 | /* 640x480 @ 85Hz */ | ||
| 128 | NULL, 85, 640, 480, KHZ2PICOS(36000), | ||
| 129 | 80, 56, 25, 1, 56, 3, | ||
| 130 | 0, FB_VMODE_NONINTERLACED | ||
| 131 | }, { | ||
| 132 | /* 800x600 @ 56Hz */ | ||
| 133 | NULL, 56, 800, 600, KHZ2PICOS(36000), | ||
| 134 | 128, 24, 22, 1, 72, 2, | ||
| 135 | FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED | ||
| 136 | }, { | ||
| 137 | /* 800x600 @ 60Hz */ | ||
| 138 | NULL, 60, 800, 600, KHZ2PICOS(40000), | ||
| 139 | 88, 40, 23, 1, 128, 4, | ||
| 140 | FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED | ||
| 141 | }, { | ||
| 142 | /* 800x600 @ 72Hz */ | ||
| 143 | NULL, 72, 800, 600, KHZ2PICOS(50000), | ||
| 144 | 64, 56, 23, 37, 120, 6, | ||
| 145 | FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED | ||
| 146 | }, { | ||
| 147 | /* 800x600 @ 75Hz */ | ||
| 148 | NULL, 75, 800, 600, KHZ2PICOS(49500), | ||
| 149 | 160, 16, 21, 1, 80, 3, | ||
| 150 | FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED | ||
| 151 | }, { | ||
| 152 | /* 800x600 @ 85Hz */ | ||
| 153 | NULL, 85, 800, 600, KHZ2PICOS(56250), | ||
| 154 | 152, 32, 27, 1, 64, 3, | ||
| 155 | FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED | ||
| 156 | }, { | ||
| 157 | /* 1024x768 @ 60Hz */ | ||
| 158 | NULL, 60, 1024, 768, KHZ2PICOS(65000), | ||
| 159 | 160, 24, 29, 3, 136, 6, | ||
| 160 | 0, FB_VMODE_NONINTERLACED | ||
| 161 | }, { | ||
| 162 | /* 1024x768 @ 70Hz */ | ||
| 163 | NULL, 70, 1024, 768, KHZ2PICOS(75000), | ||
| 164 | 144, 24, 29, 3, 136, 6, | ||
| 165 | 0, FB_VMODE_NONINTERLACED | ||
| 166 | }, { | ||
| 167 | /* 1024x768 @ 75Hz */ | ||
| 168 | NULL, 75, 1024, 768, KHZ2PICOS(78750), | ||
| 169 | 176, 16, 28, 1, 96, 3, | ||
| 170 | FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED | ||
| 171 | }, { | ||
| 172 | /* 1024x768 @ 85Hz */ | ||
| 173 | NULL, 85, 1024, 768, KHZ2PICOS(94500), | ||
| 174 | 208, 48, 36, 1, 96, 3, | ||
| 175 | FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED | ||
| 176 | }, { | ||
| 177 | /* 1152x864 @ 75Hz */ | ||
| 178 | NULL, 75, 1152, 864, KHZ2PICOS(108000), | ||
| 179 | 256, 64, 32, 1, 128, 3, | ||
| 180 | FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED | ||
| 181 | }, { | ||
| 182 | /* 1280x960 @ 60Hz */ | ||
| 183 | NULL, 60, 1280, 960, KHZ2PICOS(108000), | ||
| 184 | 312, 96, 36, 1, 112, 3, | ||
| 185 | FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED | ||
| 186 | }, { | ||
| 187 | /* 1280x960 @ 85Hz */ | ||
| 188 | NULL, 85, 1280, 960, KHZ2PICOS(148500), | ||
| 189 | 224, 64, 47, 1, 160, 3, | ||
| 190 | FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED | ||
| 191 | }, { | ||
| 192 | /* 1280x1024 @ 60Hz */ | ||
| 193 | NULL, 60, 1280, 1024, KHZ2PICOS(108000), | ||
| 194 | 248, 48, 38, 1, 112, 3, | ||
| 195 | FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED | ||
| 196 | }, { | ||
| 197 | /* 1280x1024 @ 75Hz */ | ||
| 198 | NULL, 75, 1280, 1024, KHZ2PICOS(135000), | ||
| 199 | 248, 16, 38, 1, 144, 3, | ||
| 200 | FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED | ||
| 201 | }, { | ||
| 202 | /* 1280x1024 @ 85Hz */ | ||
| 203 | NULL, 85, 1280, 1024, KHZ2PICOS(157500), | ||
| 204 | 224, 64, 44, 1, 160, 3, | ||
| 205 | FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED | ||
| 206 | }, { | ||
| 207 | /* 1600x1200 @ 60Hz */ | ||
| 208 | NULL, 60, 1600, 1200, KHZ2PICOS(162000), | ||
| 209 | 304, 64, 46, 1, 192, 3, | ||
| 210 | FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED | ||
| 211 | }, { | ||
| 212 | /* 1600x1200 @ 65Hz */ | ||
| 213 | NULL, 65, 1600, 1200, KHZ2PICOS(175500), | ||
| 214 | 304, 64, 46, 1, 192, 3, | ||
| 215 | FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED | ||
| 216 | }, { | ||
| 217 | /* 1600x1200 @ 70Hz */ | ||
| 218 | NULL, 70, 1600, 1200, KHZ2PICOS(189000), | ||
| 219 | 304, 64, 46, 1, 192, 3, | ||
| 220 | FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED | ||
| 221 | }, { | ||
| 222 | /* 1600x1200 @ 75Hz */ | ||
| 223 | NULL, 75, 1600, 1200, KHZ2PICOS(202500), | ||
| 224 | 304, 64, 46, 1, 192, 3, | ||
| 225 | FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED | ||
| 226 | }, { | ||
| 227 | /* 1600x1200 @ 85Hz */ | ||
| 228 | NULL, 85, 1600, 1200, KHZ2PICOS(229500), | ||
| 229 | 304, 64, 46, 1, 192, 3, | ||
| 230 | FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED | ||
| 231 | }, { | ||
| 232 | /* 1792x1344 @ 60Hz */ | ||
| 233 | NULL, 60, 1792, 1344, KHZ2PICOS(204750), | ||
| 234 | 328, 128, 46, 1, 200, 3, | ||
| 235 | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED | ||
| 236 | }, { | ||
| 237 | /* 1792x1344 @ 75Hz */ | ||
| 238 | NULL, 75, 1792, 1344, KHZ2PICOS(261000), | ||
| 239 | 352, 96, 69, 1, 216, 3, | ||
| 240 | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED | ||
| 241 | }, { | ||
| 242 | /* 1856x1392 @ 60Hz */ | ||
| 243 | NULL, 60, 1856, 1392, KHZ2PICOS(218250), | ||
| 244 | 352, 96, 43, 1, 224, 3, | ||
| 245 | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED | ||
| 246 | }, { | ||
| 247 | /* 1856x1392 @ 75Hz */ | ||
| 248 | NULL, 75, 1856, 1392, KHZ2PICOS(288000), | ||
| 249 | 352, 128, 104, 1, 224, 3, | ||
| 250 | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED | ||
| 251 | }, { | ||
| 252 | /* 1920x1440 @ 60Hz */ | ||
| 253 | NULL, 60, 1920, 1440, KHZ2PICOS(234000), | ||
| 254 | 344, 128, 56, 1, 208, 3, | ||
| 255 | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED | ||
| 256 | }, { | ||
| 257 | /* 1920x1440 @ 75Hz */ | ||
| 258 | NULL, 75, 1920, 1440, KHZ2PICOS(297000), | ||
| 259 | 352, 144, 56, 1, 224, 3, | ||
| 260 | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED | ||
| 261 | }, | ||
| 262 | }; | ||
| 263 | #define NUM_TOTAL_MODES ARRAY_SIZE(kyro_modedb) | ||
| 264 | |||
| 265 | /* | ||
| 266 | * This needs to be kept ordered corresponding to kyro_modedb. | ||
| 267 | */ | ||
| 268 | enum { | ||
| 269 | VMODE_640_350_85, | ||
| 270 | VMODE_640_400_85, | ||
| 271 | VMODE_720_400_85, | ||
| 272 | VMODE_640_480_60, | ||
| 273 | VMODE_640_480_72, | ||
| 274 | VMODE_640_480_75, | ||
| 275 | VMODE_640_480_85, | ||
| 276 | VMODE_800_600_56, | ||
| 277 | VMODE_800_600_60, | ||
| 278 | VMODE_800_600_72, | ||
| 279 | VMODE_800_600_75, | ||
| 280 | VMODE_800_600_85, | ||
| 281 | VMODE_1024_768_60, | ||
| 282 | VMODE_1024_768_70, | ||
| 283 | VMODE_1024_768_75, | ||
| 284 | VMODE_1024_768_85, | ||
| 285 | VMODE_1152_864_75, | ||
| 286 | VMODE_1280_960_60, | ||
| 287 | VMODE_1280_960_85, | ||
| 288 | VMODE_1280_1024_60, | ||
| 289 | VMODE_1280_1024_75, | ||
| 290 | VMODE_1280_1024_85, | ||
| 291 | VMODE_1600_1200_60, | ||
| 292 | VMODE_1600_1200_65, | ||
| 293 | VMODE_1600_1200_70, | ||
| 294 | VMODE_1600_1200_75, | ||
| 295 | VMODE_1600_1200_85, | ||
| 296 | VMODE_1792_1344_60, | ||
| 297 | VMODE_1792_1344_75, | ||
| 298 | VMODE_1856_1392_60, | ||
| 299 | VMODE_1856_1392_75, | ||
| 300 | VMODE_1920_1440_60, | ||
| 301 | VMODE_1920_1440_75, | ||
| 302 | }; | ||
| 303 | |||
| 304 | /* Accessors */ | ||
| 305 | static int kyro_dev_video_mode_set(struct fb_info *info) | ||
| 306 | { | ||
| 307 | struct kyrofb_info *par = info->par; | ||
| 308 | |||
| 309 | /* Turn off display */ | ||
| 310 | StopVTG(deviceInfo.pSTGReg); | ||
| 311 | DisableRamdacOutput(deviceInfo.pSTGReg); | ||
| 312 | |||
| 313 | /* Bring us out of VGA and into Hi-Res mode, if not already. */ | ||
| 314 | DisableVGA(deviceInfo.pSTGReg); | ||
| 315 | |||
| 316 | if (InitialiseRamdac(deviceInfo.pSTGReg, | ||
| 317 | info->var.bits_per_pixel, | ||
| 318 | info->var.xres, info->var.yres, | ||
| 319 | par->HSP, par->VSP, &par->PIXCLK) < 0) | ||
| 320 | return -EINVAL; | ||
| 321 | |||
| 322 | SetupVTG(deviceInfo.pSTGReg, par); | ||
| 323 | |||
| 324 | ResetOverlayRegisters(deviceInfo.pSTGReg); | ||
| 325 | |||
| 326 | /* Turn on display in new mode */ | ||
| 327 | EnableRamdacOutput(deviceInfo.pSTGReg); | ||
| 328 | StartVTG(deviceInfo.pSTGReg); | ||
| 329 | |||
| 330 | deviceInfo.ulNextFreeVidMem = info->var.xres * info->var.yres * | ||
| 331 | info->var.bits_per_pixel; | ||
| 332 | deviceInfo.ulOverlayOffset = 0; | ||
| 333 | |||
| 334 | return 0; | ||
| 335 | } | ||
| 336 | |||
| 337 | static int kyro_dev_overlay_create(u32 ulWidth, | ||
| 338 | u32 ulHeight, int bLinear) | ||
| 339 | { | ||
| 340 | u32 offset; | ||
| 341 | u32 stride, uvStride; | ||
| 342 | |||
| 343 | if (deviceInfo.ulOverlayOffset != 0) | ||
| 344 | /* | ||
| 345 | * Can only create one overlay without resetting the card or | ||
| 346 | * changing display mode | ||
| 347 | */ | ||
| 348 | return -EINVAL; | ||
| 349 | |||
| 350 | ResetOverlayRegisters(deviceInfo.pSTGReg); | ||
| 351 | |||
| 352 | /* Overlays are addressed in multiples of 16bytes or 32bytes, so make | ||
| 353 | * sure the start offset is on an appropriate boundary. | ||
| 354 | */ | ||
| 355 | offset = deviceInfo.ulNextFreeVidMem; | ||
| 356 | if ((offset & 0x1f) != 0) { | ||
| 357 | offset = (offset + 32L) & 0xffffffE0L; | ||
| 358 | } | ||
| 359 | |||
| 360 | if (CreateOverlaySurface(deviceInfo.pSTGReg, ulWidth, ulHeight, | ||
| 361 | bLinear, offset, &stride, &uvStride) < 0) | ||
| 362 | return -EINVAL; | ||
| 363 | |||
| 364 | deviceInfo.ulOverlayOffset = offset; | ||
| 365 | deviceInfo.ulOverlayStride = stride; | ||
| 366 | deviceInfo.ulOverlayUVStride = uvStride; | ||
| 367 | deviceInfo.ulNextFreeVidMem = offset + (ulHeight * stride) + (ulHeight * 2 * uvStride); | ||
| 368 | |||
| 369 | SetOverlayBlendMode(deviceInfo.pSTGReg, GLOBAL_ALPHA, 0xf, 0x0); | ||
| 370 | |||
| 371 | return 0; | ||
| 372 | } | ||
| 373 | |||
| 374 | static int kyro_dev_overlay_viewport_set(u32 x, u32 y, u32 ulWidth, u32 ulHeight) | ||
| 375 | { | ||
| 376 | if (deviceInfo.ulOverlayOffset == 0) | ||
| 377 | /* probably haven't called CreateOverlay yet */ | ||
| 378 | return -EINVAL; | ||
| 379 | |||
| 380 | /* Stop Ramdac Output */ | ||
| 381 | DisableRamdacOutput(deviceInfo.pSTGReg); | ||
| 382 | |||
| 383 | SetOverlayViewPort(deviceInfo.pSTGReg, | ||
| 384 | x, y, x + ulWidth - 1, y + ulHeight - 1); | ||
| 385 | |||
| 386 | EnableOverlayPlane(deviceInfo.pSTGReg); | ||
| 387 | /* Start Ramdac Output */ | ||
| 388 | EnableRamdacOutput(deviceInfo.pSTGReg); | ||
| 389 | |||
| 390 | return 0; | ||
| 391 | } | ||
| 392 | |||
| 393 | static inline unsigned long get_line_length(int x, int bpp) | ||
| 394 | { | ||
| 395 | return (unsigned long)((((x*bpp)+31)&~31) >> 3); | ||
| 396 | } | ||
| 397 | |||
| 398 | static int kyrofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | ||
| 399 | { | ||
| 400 | struct kyrofb_info *par = info->par; | ||
| 401 | |||
| 402 | if (var->bits_per_pixel != 16 && var->bits_per_pixel != 32) { | ||
| 403 | printk(KERN_WARNING "kyrofb: depth not supported: %u\n", var->bits_per_pixel); | ||
| 404 | return -EINVAL; | ||
| 405 | } | ||
| 406 | |||
| 407 | switch (var->bits_per_pixel) { | ||
| 408 | case 16: | ||
| 409 | var->red.offset = 11; | ||
| 410 | var->red.length = 5; | ||
| 411 | var->green.offset = 5; | ||
| 412 | var->green.length = 6; | ||
| 413 | var->blue.length = 5; | ||
| 414 | break; | ||
| 415 | case 32: | ||
| 416 | var->transp.offset = 24; | ||
| 417 | var->red.offset = 16; | ||
| 418 | var->green.offset = 8; | ||
| 419 | var->blue.offset = 0; | ||
| 420 | |||
| 421 | var->red.length = 8; | ||
| 422 | var->green.length = 8; | ||
| 423 | var->blue.length = 8; | ||
| 424 | var->transp.length = 8; | ||
| 425 | break; | ||
| 426 | } | ||
| 427 | |||
| 428 | /* Height/Width of picture in mm */ | ||
| 429 | var->height = var->width = -1; | ||
| 430 | |||
| 431 | /* Timing information. All values are in picoseconds */ | ||
| 432 | |||
| 433 | /* par->PIXCLK is in 100Hz units. Convert to picoseconds - | ||
| 434 | * ensuring we do not exceed 32 bit precision | ||
| 435 | */ | ||
| 436 | /* | ||
| 437 | * XXX: Enabling this really screws over the pixclock value when we | ||
| 438 | * read it back with fbset. As such, leaving this commented out appears | ||
| 439 | * to do the right thing (at least for now) .. bearing in mind that we | ||
| 440 | * have infact already done the KHZ2PICOS conversion in both the modedb | ||
| 441 | * and kyro_var. -- PFM. | ||
| 442 | */ | ||
| 443 | // var->pixclock = 1000000000 / (par->PIXCLK / 10); | ||
| 444 | |||
| 445 | /* the header file claims we should use picoseconds | ||
| 446 | * - nobody else does though, the all use pixels and lines | ||
| 447 | * of h and v sizes. Both options here. | ||
| 448 | */ | ||
| 449 | |||
| 450 | /* | ||
| 451 | * If we're being called by __fb_try_mode(), then we don't want to | ||
| 452 | * override any of the var settings that we've already parsed | ||
| 453 | * from our modedb. -- PFM. | ||
| 454 | */ | ||
| 455 | if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_TEST) | ||
| 456 | return 0; | ||
| 457 | |||
| 458 | var->left_margin = par->HBP; | ||
| 459 | var->hsync_len = par->HST; | ||
| 460 | var->right_margin = par->HFP; | ||
| 461 | |||
| 462 | var->upper_margin = par->VBP; | ||
| 463 | var->vsync_len = par->VST; | ||
| 464 | var->lower_margin = par->VFP; | ||
| 465 | |||
| 466 | if (par->HSP == 1) | ||
| 467 | var->sync |= FB_SYNC_HOR_HIGH_ACT; | ||
| 468 | if (par->VSP == 1) | ||
| 469 | var->sync |= FB_SYNC_VERT_HIGH_ACT; | ||
| 470 | |||
| 471 | return 0; | ||
| 472 | } | ||
| 473 | |||
| 474 | static int kyrofb_set_par(struct fb_info *info) | ||
| 475 | { | ||
| 476 | struct kyrofb_info *par = info->par; | ||
| 477 | unsigned long lineclock; | ||
| 478 | unsigned long frameclock; | ||
| 479 | |||
| 480 | /* Actual resolution */ | ||
| 481 | par->XRES = info->var.xres; | ||
| 482 | par->YRES = info->var.yres; | ||
| 483 | |||
| 484 | /* pixel depth */ | ||
| 485 | par->PIXDEPTH = info->var.bits_per_pixel; | ||
| 486 | |||
| 487 | /* Refresh rate */ | ||
| 488 | /* time for a line in ns */ | ||
| 489 | lineclock = (info->var.pixclock * (info->var.xres + | ||
| 490 | info->var.right_margin + | ||
| 491 | info->var.hsync_len + | ||
| 492 | info->var.left_margin)) / 1000; | ||
| 493 | |||
| 494 | |||
| 495 | /* time for a frame in ns (precision in 32bpp) */ | ||
| 496 | frameclock = lineclock * (info->var.yres + | ||
| 497 | info->var.lower_margin + | ||
| 498 | info->var.vsync_len + | ||
| 499 | info->var.upper_margin); | ||
| 500 | |||
| 501 | /* Calculate refresh rate and horrizontal clocks */ | ||
| 502 | par->VFREQ = (1000000000 + (frameclock / 2)) / frameclock; | ||
| 503 | par->HCLK = (1000000000 + (lineclock / 2)) / lineclock; | ||
| 504 | par->PIXCLK = ((1000000000 + (info->var.pixclock / 2)) | ||
| 505 | / info->var.pixclock) * 10; | ||
| 506 | |||
| 507 | /* calculate horizontal timings */ | ||
| 508 | par->HFP = info->var.right_margin; | ||
| 509 | par->HST = info->var.hsync_len; | ||
| 510 | par->HBP = info->var.left_margin; | ||
| 511 | par->HTot = par->XRES + par->HBP + par->HST + par->HFP; | ||
| 512 | |||
| 513 | /* calculate vertical timings */ | ||
| 514 | par->VFP = info->var.lower_margin; | ||
| 515 | par->VST = info->var.vsync_len; | ||
| 516 | par->VBP = info->var.upper_margin; | ||
| 517 | par->VTot = par->YRES + par->VBP + par->VST + par->VFP; | ||
| 518 | |||
| 519 | par->HSP = (info->var.sync & FB_SYNC_HOR_HIGH_ACT) ? 1 : 0; | ||
| 520 | par->VSP = (info->var.sync & FB_SYNC_VERT_HIGH_ACT) ? 1 : 0; | ||
| 521 | |||
| 522 | kyro_dev_video_mode_set(info); | ||
| 523 | |||
| 524 | /* length of a line in bytes */ | ||
| 525 | info->fix.line_length = get_line_length(par->XRES, par->PIXDEPTH); | ||
| 526 | info->fix.visual = FB_VISUAL_TRUECOLOR; | ||
| 527 | |||
| 528 | return 0; | ||
| 529 | } | ||
| 530 | |||
| 531 | static int kyrofb_setcolreg(u_int regno, u_int red, u_int green, | ||
| 532 | u_int blue, u_int transp, struct fb_info *info) | ||
| 533 | { | ||
| 534 | struct kyrofb_info *par = info->par; | ||
| 535 | |||
| 536 | if (regno > 255) | ||
| 537 | return 1; /* Invalid register */ | ||
| 538 | |||
| 539 | if (regno < 16) { | ||
| 540 | switch (info->var.bits_per_pixel) { | ||
| 541 | case 16: | ||
| 542 | par->palette[regno] = | ||
| 543 | (red & 0xf800) | | ||
| 544 | ((green & 0xfc00) >> 5) | | ||
| 545 | ((blue & 0xf800) >> 11); | ||
| 546 | break; | ||
| 547 | case 32: | ||
| 548 | red >>= 8; green >>= 8; blue >>= 8; transp >>= 8; | ||
| 549 | par->palette[regno] = | ||
| 550 | (transp << 24) | (red << 16) | (green << 8) | blue; | ||
| 551 | break; | ||
| 552 | } | ||
| 553 | } | ||
| 554 | |||
| 555 | return 0; | ||
| 556 | } | ||
| 557 | |||
| 558 | #ifndef MODULE | ||
| 559 | static int __init kyrofb_setup(char *options) | ||
| 560 | { | ||
| 561 | char *this_opt; | ||
| 562 | |||
| 563 | if (!options || !*options) | ||
| 564 | return 0; | ||
| 565 | |||
| 566 | while ((this_opt = strsep(&options, ","))) { | ||
| 567 | if (!*this_opt) | ||
| 568 | continue; | ||
| 569 | if (strcmp(this_opt, "nopan") == 0) { | ||
| 570 | nopan = 1; | ||
| 571 | } else if (strcmp(this_opt, "nowrap") == 0) { | ||
| 572 | nowrap = 1; | ||
| 573 | #ifdef CONFIG_MTRR | ||
| 574 | } else if (strcmp(this_opt, "nomtrr") == 0) { | ||
| 575 | nomtrr = 1; | ||
| 576 | #endif | ||
| 577 | } else { | ||
| 578 | mode_option = this_opt; | ||
| 579 | } | ||
| 580 | } | ||
| 581 | |||
| 582 | return 0; | ||
| 583 | } | ||
| 584 | #endif | ||
| 585 | |||
| 586 | static int kyrofb_ioctl(struct fb_info *info, | ||
| 587 | unsigned int cmd, unsigned long arg) | ||
| 588 | { | ||
| 589 | overlay_create ol_create; | ||
| 590 | overlay_viewport_set ol_viewport_set; | ||
| 591 | void __user *argp = (void __user *)arg; | ||
| 592 | |||
| 593 | switch (cmd) { | ||
| 594 | case KYRO_IOCTL_OVERLAY_CREATE: | ||
| 595 | if (copy_from_user(&ol_create, argp, sizeof(overlay_create))) | ||
| 596 | return -EFAULT; | ||
| 597 | |||
| 598 | if (kyro_dev_overlay_create(ol_create.ulWidth, | ||
| 599 | ol_create.ulHeight, 0) < 0) { | ||
| 600 | printk(KERN_ERR "Kyro FB: failed to create overlay surface.\n"); | ||
| 601 | |||
| 602 | return -EINVAL; | ||
| 603 | } | ||
| 604 | break; | ||
| 605 | case KYRO_IOCTL_OVERLAY_VIEWPORT_SET: | ||
| 606 | if (copy_from_user(&ol_viewport_set, argp, | ||
| 607 | sizeof(overlay_viewport_set))) | ||
| 608 | return -EFAULT; | ||
| 609 | |||
| 610 | if (kyro_dev_overlay_viewport_set(ol_viewport_set.xOrgin, | ||
| 611 | ol_viewport_set.yOrgin, | ||
| 612 | ol_viewport_set.xSize, | ||
| 613 | ol_viewport_set.ySize) != 0) | ||
| 614 | { | ||
| 615 | printk(KERN_ERR "Kyro FB: failed to create overlay viewport.\n"); | ||
| 616 | return -EINVAL; | ||
| 617 | } | ||
| 618 | break; | ||
| 619 | case KYRO_IOCTL_SET_VIDEO_MODE: | ||
| 620 | { | ||
| 621 | printk(KERN_ERR "Kyro FB: KYRO_IOCTL_SET_VIDEO_MODE is" | ||
| 622 | "obsolete, use the appropriate fb_ioctl()" | ||
| 623 | "command instead.\n"); | ||
| 624 | return -EINVAL; | ||
| 625 | } | ||
| 626 | case KYRO_IOCTL_UVSTRIDE: | ||
| 627 | if (copy_to_user(argp, &deviceInfo.ulOverlayUVStride, sizeof(deviceInfo.ulOverlayUVStride))) | ||
| 628 | return -EFAULT; | ||
| 629 | break; | ||
| 630 | case KYRO_IOCTL_STRIDE: | ||
| 631 | if (copy_to_user(argp, &deviceInfo.ulOverlayStride, sizeof(deviceInfo.ulOverlayStride))) | ||
| 632 | return -EFAULT; | ||
| 633 | break; | ||
| 634 | case KYRO_IOCTL_OVERLAY_OFFSET: | ||
| 635 | if (copy_to_user(argp, &deviceInfo.ulOverlayOffset, sizeof(deviceInfo.ulOverlayOffset))) | ||
| 636 | return -EFAULT; | ||
| 637 | break; | ||
| 638 | } | ||
| 639 | |||
| 640 | return 0; | ||
| 641 | } | ||
| 642 | |||
| 643 | static struct pci_device_id kyrofb_pci_tbl[] = { | ||
| 644 | { PCI_VENDOR_ID_ST, PCI_DEVICE_ID_STG4000, | ||
| 645 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, | ||
| 646 | { 0, } | ||
| 647 | }; | ||
| 648 | |||
| 649 | MODULE_DEVICE_TABLE(pci, kyrofb_pci_tbl); | ||
| 650 | |||
| 651 | static struct pci_driver kyrofb_pci_driver = { | ||
| 652 | .name = "kyrofb", | ||
| 653 | .id_table = kyrofb_pci_tbl, | ||
| 654 | .probe = kyrofb_probe, | ||
| 655 | .remove = kyrofb_remove, | ||
| 656 | }; | ||
| 657 | |||
| 658 | static struct fb_ops kyrofb_ops = { | ||
| 659 | .owner = THIS_MODULE, | ||
| 660 | .fb_check_var = kyrofb_check_var, | ||
| 661 | .fb_set_par = kyrofb_set_par, | ||
| 662 | .fb_setcolreg = kyrofb_setcolreg, | ||
| 663 | .fb_ioctl = kyrofb_ioctl, | ||
| 664 | .fb_fillrect = cfb_fillrect, | ||
| 665 | .fb_copyarea = cfb_copyarea, | ||
| 666 | .fb_imageblit = cfb_imageblit, | ||
| 667 | }; | ||
| 668 | |||
| 669 | static int kyrofb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | ||
| 670 | { | ||
| 671 | struct fb_info *info; | ||
| 672 | struct kyrofb_info *currentpar; | ||
| 673 | unsigned long size; | ||
| 674 | int err; | ||
| 675 | |||
| 676 | if ((err = pci_enable_device(pdev))) { | ||
| 677 | printk(KERN_WARNING "kyrofb: Can't enable pdev: %d\n", err); | ||
| 678 | return err; | ||
| 679 | } | ||
| 680 | |||
| 681 | info = framebuffer_alloc(sizeof(struct kyrofb_info), &pdev->dev); | ||
| 682 | if (!info) | ||
| 683 | return -ENOMEM; | ||
| 684 | |||
| 685 | currentpar = info->par; | ||
| 686 | |||
| 687 | kyro_fix.smem_start = pci_resource_start(pdev, 0); | ||
| 688 | kyro_fix.smem_len = pci_resource_len(pdev, 0); | ||
| 689 | kyro_fix.mmio_start = pci_resource_start(pdev, 1); | ||
| 690 | kyro_fix.mmio_len = pci_resource_len(pdev, 1); | ||
| 691 | |||
| 692 | currentpar->regbase = deviceInfo.pSTGReg = | ||
| 693 | ioremap_nocache(kyro_fix.mmio_start, kyro_fix.mmio_len); | ||
| 694 | |||
| 695 | info->screen_base = ioremap_nocache(kyro_fix.smem_start, | ||
| 696 | kyro_fix.smem_len); | ||
| 697 | |||
| 698 | #ifdef CONFIG_MTRR | ||
| 699 | if (!nomtrr) | ||
| 700 | currentpar->mtrr_handle = | ||
| 701 | mtrr_add(kyro_fix.smem_start, | ||
| 702 | kyro_fix.smem_len, | ||
| 703 | MTRR_TYPE_WRCOMB, 1); | ||
| 704 | #endif | ||
| 705 | |||
| 706 | kyro_fix.ypanstep = nopan ? 0 : 1; | ||
| 707 | kyro_fix.ywrapstep = nowrap ? 0 : 1; | ||
| 708 | |||
| 709 | info->fbops = &kyrofb_ops; | ||
| 710 | info->fix = kyro_fix; | ||
| 711 | info->pseudo_palette = currentpar->palette; | ||
| 712 | info->flags = FBINFO_DEFAULT; | ||
| 713 | |||
| 714 | SetCoreClockPLL(deviceInfo.pSTGReg, pdev); | ||
| 715 | |||
| 716 | deviceInfo.ulNextFreeVidMem = 0; | ||
| 717 | deviceInfo.ulOverlayOffset = 0; | ||
| 718 | |||
| 719 | /* This should give a reasonable default video mode */ | ||
| 720 | if (!fb_find_mode(&info->var, info, mode_option, kyro_modedb, | ||
| 721 | NUM_TOTAL_MODES, &kyro_modedb[VMODE_1024_768_75], 32)) | ||
| 722 | info->var = kyro_var; | ||
| 723 | |||
| 724 | fb_alloc_cmap(&info->cmap, 256, 0); | ||
| 725 | |||
| 726 | kyrofb_set_par(info); | ||
| 727 | kyrofb_check_var(&info->var, info); | ||
| 728 | |||
| 729 | size = get_line_length(info->var.xres_virtual, | ||
| 730 | info->var.bits_per_pixel); | ||
| 731 | size *= info->var.yres_virtual; | ||
| 732 | |||
| 733 | fb_memset(info->screen_base, 0, size); | ||
| 734 | |||
| 735 | if (register_framebuffer(info) < 0) | ||
| 736 | goto out_unmap; | ||
| 737 | |||
| 738 | fb_info(info, "%s frame buffer device, at %dx%d@%d using %ldk/%ldk of VRAM\n", | ||
| 739 | info->fix.id, | ||
| 740 | info->var.xres, info->var.yres, info->var.bits_per_pixel, | ||
| 741 | size >> 10, (unsigned long)info->fix.smem_len >> 10); | ||
| 742 | |||
| 743 | pci_set_drvdata(pdev, info); | ||
| 744 | |||
| 745 | return 0; | ||
| 746 | |||
| 747 | out_unmap: | ||
| 748 | iounmap(currentpar->regbase); | ||
| 749 | iounmap(info->screen_base); | ||
| 750 | framebuffer_release(info); | ||
| 751 | |||
| 752 | return -EINVAL; | ||
| 753 | } | ||
| 754 | |||
| 755 | static void kyrofb_remove(struct pci_dev *pdev) | ||
| 756 | { | ||
| 757 | struct fb_info *info = pci_get_drvdata(pdev); | ||
| 758 | struct kyrofb_info *par = info->par; | ||
| 759 | |||
| 760 | /* Reset the board */ | ||
| 761 | StopVTG(deviceInfo.pSTGReg); | ||
| 762 | DisableRamdacOutput(deviceInfo.pSTGReg); | ||
| 763 | |||
| 764 | /* Sync up the PLL */ | ||
| 765 | SetCoreClockPLL(deviceInfo.pSTGReg, pdev); | ||
| 766 | |||
| 767 | deviceInfo.ulNextFreeVidMem = 0; | ||
| 768 | deviceInfo.ulOverlayOffset = 0; | ||
| 769 | |||
| 770 | iounmap(info->screen_base); | ||
| 771 | iounmap(par->regbase); | ||
| 772 | |||
| 773 | #ifdef CONFIG_MTRR | ||
| 774 | if (par->mtrr_handle) | ||
| 775 | mtrr_del(par->mtrr_handle, | ||
| 776 | info->fix.smem_start, | ||
| 777 | info->fix.smem_len); | ||
| 778 | #endif | ||
| 779 | |||
| 780 | unregister_framebuffer(info); | ||
| 781 | framebuffer_release(info); | ||
| 782 | } | ||
| 783 | |||
| 784 | static int __init kyrofb_init(void) | ||
| 785 | { | ||
| 786 | #ifndef MODULE | ||
| 787 | char *option = NULL; | ||
| 788 | |||
| 789 | if (fb_get_options("kyrofb", &option)) | ||
| 790 | return -ENODEV; | ||
| 791 | kyrofb_setup(option); | ||
| 792 | #endif | ||
| 793 | return pci_register_driver(&kyrofb_pci_driver); | ||
| 794 | } | ||
| 795 | |||
| 796 | static void __exit kyrofb_exit(void) | ||
| 797 | { | ||
| 798 | pci_unregister_driver(&kyrofb_pci_driver); | ||
| 799 | } | ||
| 800 | |||
| 801 | module_init(kyrofb_init); | ||
| 802 | |||
| 803 | #ifdef MODULE | ||
| 804 | module_exit(kyrofb_exit); | ||
| 805 | #endif | ||
| 806 | |||
| 807 | MODULE_AUTHOR("STMicroelectronics; Paul Mundt <lethal@linux-sh.org>"); | ||
| 808 | MODULE_LICENSE("GPL"); | ||
