aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/video/geode/Kconfig10
-rw-r--r--drivers/video/geode/geodefb.h1
-rw-r--r--drivers/video/geode/gx1fb_core.c182
-rw-r--r--drivers/video/geode/video_cs5530.c4
4 files changed, 143 insertions, 54 deletions
diff --git a/drivers/video/geode/Kconfig b/drivers/video/geode/Kconfig
index b075fd02de31..5a9b89c3831b 100644
--- a/drivers/video/geode/Kconfig
+++ b/drivers/video/geode/Kconfig
@@ -3,15 +3,13 @@
3# 3#
4config FB_GEODE 4config FB_GEODE
5 bool "AMD Geode family framebuffer support (EXPERIMENTAL)" 5 bool "AMD Geode family framebuffer support (EXPERIMENTAL)"
6 default n 6 depends on FB && PCI && EXPERIMENTAL && X86
7 depends on FB && EXPERIMENTAL && X86
8 ---help--- 7 ---help---
9 Say 'Y' here to allow you to select framebuffer drivers for 8 Say 'Y' here to allow you to select framebuffer drivers for
10 the AMD Geode family of processors. 9 the AMD Geode family of processors.
11 10
12config FB_GEODE_GX1 11config FB_GEODE_GX1
13 tristate "AMD Geode GX1 framebuffer support (EXPERIMENTAL)" 12 tristate "AMD Geode GX1 framebuffer support (EXPERIMENTAL)"
14 default n
15 depends on FB_GEODE && EXPERIMENTAL 13 depends on FB_GEODE && EXPERIMENTAL
16 select FB_CFB_FILLRECT 14 select FB_CFB_FILLRECT
17 select FB_CFB_COPYAREA 15 select FB_CFB_COPYAREA
@@ -21,9 +19,7 @@ config FB_GEODE_GX1
21 Framebuffer driver for the display controller integrated into the 19 Framebuffer driver for the display controller integrated into the
22 AMD Geode GX1 processor. 20 AMD Geode GX1 processor.
23 21
24 This driver is also available as a module ( = code which can be 22 To compile this driver as a module, choose M here: the module will be
25 inserted and removed from the running kernel whenever you want). The 23 called gx1fb.
26 module will be called gx1fb. If you want to compile it as a module,
27 say M here and read <file:Documentation/modules.txt>.
28 24
29 If unsure, say N. 25 If unsure, say N.
diff --git a/drivers/video/geode/geodefb.h b/drivers/video/geode/geodefb.h
index b7bac0a526b3..ae04820e0c57 100644
--- a/drivers/video/geode/geodefb.h
+++ b/drivers/video/geode/geodefb.h
@@ -29,7 +29,6 @@ struct geodefb_par {
29 int enable_crt; 29 int enable_crt;
30 int panel_x; /* dimensions of an attached flat panel, non-zero => enable panel */ 30 int panel_x; /* dimensions of an attached flat panel, non-zero => enable panel */
31 int panel_y; 31 int panel_y;
32 struct pci_dev *vid_dev;
33 void __iomem *dc_regs; 32 void __iomem *dc_regs;
34 void __iomem *vid_regs; 33 void __iomem *vid_regs;
35 struct geode_dc_ops *dc_ops; 34 struct geode_dc_ops *dc_ops;
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";
30static int crt_option = 1; 30static int crt_option = 1;
31static char panel_option[32] = ""; 31static char panel_option[32] = "";
32 32
33/* Modes relevant to the GX1 (taken from modedb.c) */
34static 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
33static int gx1_line_delta(int xres, int bpp) 89static 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
149static int __init gx1fb_map_video_memory(struct fb_info *info) 203static 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
219static struct fb_info * __init gx1fb_init_fbinfo(void) 281static 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 327static int __init gx1fb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
267static struct fb_info *gx1fb_info;
268
269static 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
330static void __exit gx1fb_cleanup(void) 390static 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
412static 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
419MODULE_DEVICE_TABLE(pci, gx1fb_id_table);
420
421static struct pci_driver gx1fb_driver = {
422 .name = "gx1fb",
423 .id_table = gx1fb_id_table,
424 .probe = gx1fb_probe,
425 .remove = gx1fb_remove,
426};
427
428static 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
437static void __exit gx1fb_cleanup(void)
438{
439 pci_unregister_driver(&gx1fb_driver);
440}
441
346module_init(gx1fb_init); 442module_init(gx1fb_init);
347module_exit(gx1fb_cleanup); 443module_exit(gx1fb_cleanup);
348 444
diff --git a/drivers/video/geode/video_cs5530.c b/drivers/video/geode/video_cs5530.c
index d3764acf8443..649c3943d431 100644
--- a/drivers/video/geode/video_cs5530.c
+++ b/drivers/video/geode/video_cs5530.c
@@ -69,8 +69,6 @@ static const struct cs5530_pll_entry cs5530_pll_table[] = {
69 { 4310, 0x2FB1B802, }, /* 232.0000 */ 69 { 4310, 0x2FB1B802, }, /* 232.0000 */
70}; 70};
71 71
72#define NUM_CS5530_FREQUENCIES sizeof(cs5530_pll_table)/sizeof(struct cs5530_pll_entry)
73
74static void cs5530_set_dclk_frequency(struct fb_info *info) 72static void cs5530_set_dclk_frequency(struct fb_info *info)
75{ 73{
76 struct geodefb_par *par = info->par; 74 struct geodefb_par *par = info->par;
@@ -82,7 +80,7 @@ static void cs5530_set_dclk_frequency(struct fb_info *info)
82 value = cs5530_pll_table[0].pll_value; 80 value = cs5530_pll_table[0].pll_value;
83 min = cs5530_pll_table[0].pixclock - info->var.pixclock; 81 min = cs5530_pll_table[0].pixclock - info->var.pixclock;
84 if (min < 0) min = -min; 82 if (min < 0) min = -min;
85 for (i = 1; i < NUM_CS5530_FREQUENCIES; i++) { 83 for (i = 1; i < ARRAY_SIZE(cs5530_pll_table); i++) {
86 diff = cs5530_pll_table[i].pixclock - info->var.pixclock; 84 diff = cs5530_pll_table[i].pixclock - info->var.pixclock;
87 if (diff < 0L) diff = -diff; 85 if (diff < 0L) diff = -diff;
88 if (diff < min) { 86 if (diff < min) {