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