diff options
Diffstat (limited to 'drivers/video/geode/gx1fb_core.c')
-rw-r--r-- | drivers/video/geode/gx1fb_core.c | 182 |
1 files changed, 139 insertions, 43 deletions
diff --git a/drivers/video/geode/gx1fb_core.c b/drivers/video/geode/gx1fb_core.c index 83830d24bcda..74a5fca86b8a 100644 --- a/drivers/video/geode/gx1fb_core.c +++ b/drivers/video/geode/gx1fb_core.c | |||
@@ -30,6 +30,62 @@ static char mode_option[32] = "640x480-16@60"; | |||
30 | static int crt_option = 1; | 30 | static int crt_option = 1; |
31 | static char panel_option[32] = ""; | 31 | static char panel_option[32] = ""; |
32 | 32 | ||
33 | /* Modes relevant to the GX1 (taken from modedb.c) */ | ||
34 | static const struct fb_videomode __initdata gx1_modedb[] = { | ||
35 | /* 640x480-60 VESA */ | ||
36 | { NULL, 60, 640, 480, 39682, 48, 16, 33, 10, 96, 2, | ||
37 | 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, | ||
38 | /* 640x480-75 VESA */ | ||
39 | { NULL, 75, 640, 480, 31746, 120, 16, 16, 01, 64, 3, | ||
40 | 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, | ||
41 | /* 640x480-85 VESA */ | ||
42 | { NULL, 85, 640, 480, 27777, 80, 56, 25, 01, 56, 3, | ||
43 | 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, | ||
44 | /* 800x600-60 VESA */ | ||
45 | { NULL, 60, 800, 600, 25000, 88, 40, 23, 01, 128, 4, | ||
46 | FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | ||
47 | FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, | ||
48 | /* 800x600-75 VESA */ | ||
49 | { NULL, 75, 800, 600, 20202, 160, 16, 21, 01, 80, 3, | ||
50 | FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | ||
51 | FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, | ||
52 | /* 800x600-85 VESA */ | ||
53 | { NULL, 85, 800, 600, 17761, 152, 32, 27, 01, 64, 3, | ||
54 | FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | ||
55 | FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, | ||
56 | /* 1024x768-60 VESA */ | ||
57 | { NULL, 60, 1024, 768, 15384, 160, 24, 29, 3, 136, 6, | ||
58 | 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, | ||
59 | /* 1024x768-75 VESA */ | ||
60 | { NULL, 75, 1024, 768, 12690, 176, 16, 28, 1, 96, 3, | ||
61 | FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | ||
62 | FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, | ||
63 | /* 1024x768-85 VESA */ | ||
64 | { NULL, 85, 1024, 768, 10582, 208, 48, 36, 1, 96, 3, | ||
65 | FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | ||
66 | FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, | ||
67 | /* 1280x960-60 VESA */ | ||
68 | { NULL, 60, 1280, 960, 9259, 312, 96, 36, 1, 112, 3, | ||
69 | FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | ||
70 | FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, | ||
71 | /* 1280x960-85 VESA */ | ||
72 | { NULL, 85, 1280, 960, 6734, 224, 64, 47, 1, 160, 3, | ||
73 | FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | ||
74 | FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, | ||
75 | /* 1280x1024-60 VESA */ | ||
76 | { NULL, 60, 1280, 1024, 9259, 248, 48, 38, 1, 112, 3, | ||
77 | FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | ||
78 | FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, | ||
79 | /* 1280x1024-75 VESA */ | ||
80 | { NULL, 75, 1280, 1024, 7407, 248, 16, 38, 1, 144, 3, | ||
81 | FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | ||
82 | FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, | ||
83 | /* 1280x1024-85 VESA */ | ||
84 | { NULL, 85, 1280, 1024, 6349, 224, 64, 44, 1, 160, 3, | ||
85 | FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | ||
86 | FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, | ||
87 | }; | ||
88 | |||
33 | static int gx1_line_delta(int xres, int bpp) | 89 | static int gx1_line_delta(int xres, int bpp) |
34 | { | 90 | { |
35 | int line_delta = xres * (bpp >> 3); | 91 | int line_delta = xres * (bpp >> 3); |
@@ -47,8 +103,6 @@ static int gx1fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | |||
47 | { | 103 | { |
48 | struct geodefb_par *par = info->par; | 104 | struct geodefb_par *par = info->par; |
49 | 105 | ||
50 | printk(KERN_DEBUG "%s()\n", __FUNCTION__); | ||
51 | |||
52 | /* Maximum resolution is 1280x1024. */ | 106 | /* Maximum resolution is 1280x1024. */ |
53 | if (var->xres > 1280 || var->yres > 1024) | 107 | if (var->xres > 1280 || var->yres > 1024) |
54 | return -EINVAL; | 108 | return -EINVAL; |
@@ -146,40 +200,48 @@ static int gx1fb_blank(int blank_mode, struct fb_info *info) | |||
146 | return par->vid_ops->blank_display(info, blank_mode); | 200 | return par->vid_ops->blank_display(info, blank_mode); |
147 | } | 201 | } |
148 | 202 | ||
149 | static int __init gx1fb_map_video_memory(struct fb_info *info) | 203 | static int __init gx1fb_map_video_memory(struct fb_info *info, struct pci_dev *dev) |
150 | { | 204 | { |
151 | struct geodefb_par *par = info->par; | 205 | struct geodefb_par *par = info->par; |
152 | unsigned gx_base; | 206 | unsigned gx_base; |
153 | int fb_len; | 207 | int fb_len; |
208 | int ret; | ||
154 | 209 | ||
155 | gx_base = gx1_gx_base(); | 210 | gx_base = gx1_gx_base(); |
156 | if (!gx_base) | 211 | if (!gx_base) |
157 | return -ENODEV; | 212 | return -ENODEV; |
158 | 213 | ||
159 | par->vid_dev = pci_get_device(PCI_VENDOR_ID_CYRIX, | 214 | ret = pci_enable_device(dev); |
160 | PCI_DEVICE_ID_CYRIX_5530_VIDEO, NULL); | 215 | if (ret < 0) |
161 | if (!par->vid_dev) | 216 | return ret; |
162 | return -ENODEV; | ||
163 | 217 | ||
164 | par->vid_regs = ioremap(pci_resource_start(par->vid_dev, 1), | 218 | ret = pci_request_region(dev, 1, "gx1fb (video)"); |
165 | pci_resource_len(par->vid_dev, 1)); | 219 | if (ret < 0) |
220 | return ret; | ||
221 | par->vid_regs = ioremap(pci_resource_start(dev, 1), | ||
222 | pci_resource_len(dev, 1)); | ||
166 | if (!par->vid_regs) | 223 | if (!par->vid_regs) |
167 | return -ENOMEM; | 224 | return -ENOMEM; |
168 | 225 | ||
226 | if (!request_mem_region(gx_base + 0x8300, 0x100, "gx1fb (display controller)")) | ||
227 | return -EBUSY; | ||
169 | par->dc_regs = ioremap(gx_base + 0x8300, 0x100); | 228 | par->dc_regs = ioremap(gx_base + 0x8300, 0x100); |
170 | if (!par->dc_regs) | 229 | if (!par->dc_regs) |
171 | return -ENOMEM; | 230 | return -ENOMEM; |
172 | 231 | ||
173 | info->fix.smem_start = gx_base + 0x800000; | 232 | ret = pci_request_region(dev, 0, "gx1fb (frame buffer)"); |
233 | if (ret < 0 ) | ||
234 | return -EBUSY; | ||
174 | if ((fb_len = gx1_frame_buffer_size()) < 0) | 235 | if ((fb_len = gx1_frame_buffer_size()) < 0) |
175 | return -ENOMEM; | 236 | return -ENOMEM; |
237 | info->fix.smem_start = pci_resource_start(dev, 0); | ||
176 | info->fix.smem_len = fb_len; | 238 | info->fix.smem_len = fb_len; |
177 | info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len); | 239 | info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len); |
178 | if (!info->screen_base) | 240 | if (!info->screen_base) |
179 | return -ENOMEM; | 241 | return -ENOMEM; |
180 | 242 | ||
181 | printk(KERN_INFO "%s: %d Kibyte of video memory at 0x%lx\n", | 243 | dev_info(&dev->dev, "%d Kibyte of video memory at 0x%lx\n", |
182 | info->fix.id, info->fix.smem_len / 1024, info->fix.smem_start); | 244 | info->fix.smem_len / 1024, info->fix.smem_start); |
183 | 245 | ||
184 | return 0; | 246 | return 0; |
185 | } | 247 | } |
@@ -216,13 +278,13 @@ static struct fb_ops gx1fb_ops = { | |||
216 | .fb_cursor = soft_cursor, | 278 | .fb_cursor = soft_cursor, |
217 | }; | 279 | }; |
218 | 280 | ||
219 | static struct fb_info * __init gx1fb_init_fbinfo(void) | 281 | static struct fb_info * __init gx1fb_init_fbinfo(struct device *dev) |
220 | { | 282 | { |
221 | struct fb_info *info; | ||
222 | struct geodefb_par *par; | 283 | struct geodefb_par *par; |
284 | struct fb_info *info; | ||
223 | 285 | ||
224 | /* Alloc enough space for the pseudo palette. */ | 286 | /* Alloc enough space for the pseudo palette. */ |
225 | info = framebuffer_alloc(sizeof(struct geodefb_par) + sizeof(u32) * 16, NULL); | 287 | info = framebuffer_alloc(sizeof(struct geodefb_par) + sizeof(u32) * 16, dev); |
226 | if (!info) | 288 | if (!info) |
227 | return NULL; | 289 | return NULL; |
228 | 290 | ||
@@ -255,47 +317,37 @@ static struct fb_info * __init gx1fb_init_fbinfo(void) | |||
255 | /* CRT and panel options */ | 317 | /* CRT and panel options */ |
256 | par->enable_crt = crt_option; | 318 | par->enable_crt = crt_option; |
257 | if (parse_panel_option(info) < 0) | 319 | if (parse_panel_option(info) < 0) |
258 | printk(KERN_WARNING "%s: invalid 'panel' option -- disabling flat panel\n", | 320 | printk(KERN_WARNING "gx1fb: invalid 'panel' option -- disabling flat panel\n"); |
259 | info->fix.id); | ||
260 | if (!par->panel_x) | 321 | if (!par->panel_x) |
261 | par->enable_crt = 1; /* fall back to CRT if no panel is specified */ | 322 | par->enable_crt = 1; /* fall back to CRT if no panel is specified */ |
262 | 323 | ||
263 | return info; | 324 | return info; |
264 | } | 325 | } |
265 | 326 | ||
266 | 327 | static int __init gx1fb_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |
267 | static struct fb_info *gx1fb_info; | ||
268 | |||
269 | static int __init gx1fb_init(void) | ||
270 | { | 328 | { |
329 | struct geodefb_par *par; | ||
271 | struct fb_info *info; | 330 | struct fb_info *info; |
272 | struct geodefb_par *par; | ||
273 | int ret; | 331 | int ret; |
274 | 332 | ||
275 | #ifndef MODULE | 333 | info = gx1fb_init_fbinfo(&pdev->dev); |
276 | if (fb_get_options("gx1fb", NULL)) | ||
277 | return -ENODEV; | ||
278 | #endif | ||
279 | |||
280 | info = gx1fb_init_fbinfo(); | ||
281 | if (!info) | 334 | if (!info) |
282 | return -ENOMEM; | 335 | return -ENOMEM; |
283 | gx1fb_info = info; | ||
284 | |||
285 | par = info->par; | 336 | par = info->par; |
286 | 337 | ||
287 | /* GX1 display controller and CS5530 video device */ | 338 | /* GX1 display controller and CS5530 video device */ |
288 | par->dc_ops = &gx1_dc_ops; | 339 | par->dc_ops = &gx1_dc_ops; |
289 | par->vid_ops = &cs5530_vid_ops; | 340 | par->vid_ops = &cs5530_vid_ops; |
290 | 341 | ||
291 | if ((ret = gx1fb_map_video_memory(info)) < 0) { | 342 | if ((ret = gx1fb_map_video_memory(info, pdev)) < 0) { |
292 | printk(KERN_ERR "%s: gx1fb_map_video_memory() failed\n", info->fix.id); | 343 | dev_err(&pdev->dev, "failed to map frame buffer or controller registers\n"); |
293 | goto err; | 344 | goto err; |
294 | } | 345 | } |
295 | 346 | ||
296 | ret = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 16); | 347 | ret = fb_find_mode(&info->var, info, mode_option, |
348 | gx1_modedb, ARRAY_SIZE(gx1_modedb), NULL, 16); | ||
297 | if (ret == 0 || ret == 4) { | 349 | if (ret == 0 || ret == 4) { |
298 | printk(KERN_ERR "%s: could not find valid video mode\n", info->fix.id); | 350 | dev_err(&pdev->dev, "could not find valid video mode\n"); |
299 | ret = -EINVAL; | 351 | ret = -EINVAL; |
300 | goto err; | 352 | goto err; |
301 | } | 353 | } |
@@ -310,39 +362,83 @@ static int __init gx1fb_init(void) | |||
310 | ret = -EINVAL; | 362 | ret = -EINVAL; |
311 | goto err; | 363 | goto err; |
312 | } | 364 | } |
365 | pci_set_drvdata(pdev, info); | ||
313 | printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, info->fix.id); | 366 | printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, info->fix.id); |
314 | return 0; | 367 | return 0; |
315 | 368 | ||
316 | err: | 369 | err: |
317 | if (info->screen_base) | 370 | if (info->screen_base) { |
318 | iounmap(info->screen_base); | 371 | iounmap(info->screen_base); |
319 | if (par->vid_regs) | 372 | pci_release_region(pdev, 0); |
373 | } | ||
374 | if (par->vid_regs) { | ||
320 | iounmap(par->vid_regs); | 375 | iounmap(par->vid_regs); |
321 | if (par->dc_regs) | 376 | pci_release_region(pdev, 1); |
377 | } | ||
378 | if (par->dc_regs) { | ||
322 | iounmap(par->dc_regs); | 379 | iounmap(par->dc_regs); |
323 | if (par->vid_dev) | 380 | release_mem_region(gx1_gx_base() + 0x8300, 0x100); |
324 | pci_dev_put(par->vid_dev); | 381 | } |
382 | |||
383 | pci_disable_device(pdev); | ||
384 | |||
325 | if (info) | 385 | if (info) |
326 | framebuffer_release(info); | 386 | framebuffer_release(info); |
327 | return ret; | 387 | return ret; |
328 | } | 388 | } |
329 | 389 | ||
330 | static void __exit gx1fb_cleanup(void) | 390 | static void gx1fb_remove(struct pci_dev *pdev) |
331 | { | 391 | { |
332 | struct fb_info *info = gx1fb_info; | 392 | struct fb_info *info = pci_get_drvdata(pdev); |
333 | struct geodefb_par *par = gx1fb_info->par; | 393 | struct geodefb_par *par = info->par; |
334 | 394 | ||
335 | unregister_framebuffer(info); | 395 | unregister_framebuffer(info); |
336 | 396 | ||
337 | iounmap((void __iomem *)info->screen_base); | 397 | iounmap((void __iomem *)info->screen_base); |
398 | pci_release_region(pdev, 0); | ||
399 | |||
338 | iounmap(par->vid_regs); | 400 | iounmap(par->vid_regs); |
401 | pci_release_region(pdev, 1); | ||
402 | |||
339 | iounmap(par->dc_regs); | 403 | iounmap(par->dc_regs); |
404 | release_mem_region(gx1_gx_base() + 0x8300, 0x100); | ||
340 | 405 | ||
341 | pci_dev_put(par->vid_dev); | 406 | pci_disable_device(pdev); |
407 | pci_set_drvdata(pdev, NULL); | ||
342 | 408 | ||
343 | framebuffer_release(info); | 409 | framebuffer_release(info); |
344 | } | 410 | } |
345 | 411 | ||
412 | static struct pci_device_id gx1fb_id_table[] = { | ||
413 | { PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_VIDEO, | ||
414 | PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16, | ||
415 | 0xff0000, 0 }, | ||
416 | { 0, } | ||
417 | }; | ||
418 | |||
419 | MODULE_DEVICE_TABLE(pci, gx1fb_id_table); | ||
420 | |||
421 | static struct pci_driver gx1fb_driver = { | ||
422 | .name = "gx1fb", | ||
423 | .id_table = gx1fb_id_table, | ||
424 | .probe = gx1fb_probe, | ||
425 | .remove = gx1fb_remove, | ||
426 | }; | ||
427 | |||
428 | static int __init gx1fb_init(void) | ||
429 | { | ||
430 | #ifndef MODULE | ||
431 | if (fb_get_options("gx1fb", NULL)) | ||
432 | return -ENODEV; | ||
433 | #endif | ||
434 | return pci_register_driver(&gx1fb_driver); | ||
435 | } | ||
436 | |||
437 | static void __exit gx1fb_cleanup(void) | ||
438 | { | ||
439 | pci_unregister_driver(&gx1fb_driver); | ||
440 | } | ||
441 | |||
346 | module_init(gx1fb_init); | 442 | module_init(gx1fb_init); |
347 | module_exit(gx1fb_cleanup); | 443 | module_exit(gx1fb_cleanup); |
348 | 444 | ||