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