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/fbdev.c |
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/fbdev.c')
-rw-r--r-- | drivers/video/kyro/fbdev.c | 820 |
1 files changed, 820 insertions, 0 deletions
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"); | ||