diff options
author | Geert Uytterhoeven <geert@linux-m68k.org> | 2011-10-20 07:42:23 -0400 |
---|---|---|
committer | Florian Tobias Schandinat <FlorianSchandinat@gmx.de> | 2011-11-11 11:55:55 -0500 |
commit | 0e0d13364b417a40266999c61671db0ef8690ad3 (patch) | |
tree | 51924743f301a186b4ac9e46eb0bc99b42a7413e /drivers/video/cirrusfb.c | |
parent | 38eb6863ed21de9beab792f66cd282c21e0dc10b (diff) |
fbdev/cirrusfb: Rewrite Zorro graphics card probing
As indicated by commit a7f4d00a82feb5b311f765bf9522bc55bee0684f ("zorro:
Defer device_register() until all devices have been identified"), cirrusfb
crashes if zorro_find_device() cannot find an expected device.
Rewrite the Zorro device probe code to make it more robust, easier to
understand, and more extensible.
Other logical changes:
- For cards that show up as 2 Zorro devices, autoprobe graphics memory
sizes based on the size of the Zorro device containing the graphics
memory.
Acording to the NetBSD sources, this is safe.
Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
Acked-by: Jeff Garzik <jgarzik@redhat.com>
Signed-off-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
Diffstat (limited to 'drivers/video/cirrusfb.c')
-rw-r--r-- | drivers/video/cirrusfb.c | 241 |
1 files changed, 118 insertions, 123 deletions
diff --git a/drivers/video/cirrusfb.c b/drivers/video/cirrusfb.c index 6df7c54db0a3..357139ab7a0f 100644 --- a/drivers/video/cirrusfb.c +++ b/drivers/video/cirrusfb.c | |||
@@ -280,52 +280,63 @@ MODULE_DEVICE_TABLE(pci, cirrusfb_pci_table); | |||
280 | #endif /* CONFIG_PCI */ | 280 | #endif /* CONFIG_PCI */ |
281 | 281 | ||
282 | #ifdef CONFIG_ZORRO | 282 | #ifdef CONFIG_ZORRO |
283 | static const struct zorro_device_id cirrusfb_zorro_table[] = { | 283 | struct zorrocl { |
284 | enum cirrus_board type; /* Board type */ | ||
285 | u32 regoffset; /* Offset of registers in first Zorro device */ | ||
286 | u32 ramsize; /* Size of video RAM in first Zorro device */ | ||
287 | /* If zero, use autoprobe on RAM device */ | ||
288 | u32 ramoffset; /* Offset of video RAM in first Zorro device */ | ||
289 | zorro_id ramid; /* Zorro ID of RAM device */ | ||
290 | }; | ||
291 | |||
292 | static const struct zorrocl zcl_sd64 __devinitconst = { | ||
293 | .type = BT_SD64, | ||
294 | .ramid = ZORRO_PROD_HELFRICH_SD64_RAM, | ||
295 | }; | ||
296 | |||
297 | static const struct zorrocl zcl_piccolo __devinitconst = { | ||
298 | .type = BT_PICCOLO, | ||
299 | .ramid = ZORRO_PROD_HELFRICH_PICCOLO_RAM, | ||
300 | }; | ||
301 | |||
302 | static const struct zorrocl zcl_picasso __devinitconst = { | ||
303 | .type = BT_PICASSO, | ||
304 | .ramid = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM, | ||
305 | }; | ||
306 | |||
307 | static const struct zorrocl zcl_spectrum __devinitconst = { | ||
308 | .type = BT_SPECTRUM, | ||
309 | .ramid = ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_RAM, | ||
310 | }; | ||
311 | |||
312 | static const struct zorrocl zcl_picasso4_z3 __devinitconst = { | ||
313 | .type = BT_PICASSO4, | ||
314 | .regoffset = 0x00600000, | ||
315 | .ramsize = 4 * MB_, | ||
316 | .ramoffset = 0x01000000, | ||
317 | }; | ||
318 | |||
319 | |||
320 | static const struct zorro_device_id cirrusfb_zorro_table[] __devinitconst = { | ||
284 | { | 321 | { |
285 | .id = ZORRO_PROD_HELFRICH_SD64_RAM, | 322 | .id = ZORRO_PROD_HELFRICH_SD64_REG, |
286 | .driver_data = BT_SD64, | 323 | .driver_data = (unsigned long)&zcl_sd64, |
287 | }, { | 324 | }, { |
288 | .id = ZORRO_PROD_HELFRICH_PICCOLO_RAM, | 325 | .id = ZORRO_PROD_HELFRICH_PICCOLO_REG, |
289 | .driver_data = BT_PICCOLO, | 326 | .driver_data = (unsigned long)&zcl_piccolo, |
290 | }, { | 327 | }, { |
291 | .id = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM, | 328 | .id = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_REG, |
292 | .driver_data = BT_PICASSO, | 329 | .driver_data = (unsigned long)&zcl_picasso, |
293 | }, { | 330 | }, { |
294 | .id = ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_RAM, | 331 | .id = ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_REG, |
295 | .driver_data = BT_SPECTRUM, | 332 | .driver_data = (unsigned long)&zcl_spectrum, |
296 | }, { | 333 | }, { |
297 | .id = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z3, | 334 | .id = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z3, |
298 | .driver_data = BT_PICASSO4, | 335 | .driver_data = (unsigned long)&zcl_picasso4_z3, |
299 | }, | 336 | }, |
300 | { 0 } | 337 | { 0 } |
301 | }; | 338 | }; |
302 | MODULE_DEVICE_TABLE(zorro, cirrusfb_zorro_table); | 339 | MODULE_DEVICE_TABLE(zorro, cirrusfb_zorro_table); |
303 | |||
304 | static const struct { | ||
305 | zorro_id id2; | ||
306 | unsigned long size; | ||
307 | } cirrusfb_zorro_table2[] = { | ||
308 | [BT_SD64] = { | ||
309 | .id2 = ZORRO_PROD_HELFRICH_SD64_REG, | ||
310 | .size = 0x400000 | ||
311 | }, | ||
312 | [BT_PICCOLO] = { | ||
313 | .id2 = ZORRO_PROD_HELFRICH_PICCOLO_REG, | ||
314 | .size = 0x200000 | ||
315 | }, | ||
316 | [BT_PICASSO] = { | ||
317 | .id2 = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_REG, | ||
318 | .size = 0x200000 | ||
319 | }, | ||
320 | [BT_SPECTRUM] = { | ||
321 | .id2 = ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_REG, | ||
322 | .size = 0x200000 | ||
323 | }, | ||
324 | [BT_PICASSO4] = { | ||
325 | .id2 = 0, | ||
326 | .size = 0x400000 | ||
327 | } | ||
328 | }; | ||
329 | #endif /* CONFIG_ZORRO */ | 340 | #endif /* CONFIG_ZORRO */ |
330 | 341 | ||
331 | #ifdef CIRRUSFB_DEBUG | 342 | #ifdef CIRRUSFB_DEBUG |
@@ -1956,16 +1967,12 @@ static void cirrusfb_zorro_unmap(struct fb_info *info) | |||
1956 | struct cirrusfb_info *cinfo = info->par; | 1967 | struct cirrusfb_info *cinfo = info->par; |
1957 | struct zorro_dev *zdev = to_zorro_dev(info->device); | 1968 | struct zorro_dev *zdev = to_zorro_dev(info->device); |
1958 | 1969 | ||
1959 | zorro_release_device(zdev); | 1970 | if (info->fix.smem_start > 16 * MB_) |
1960 | |||
1961 | if (cinfo->btype == BT_PICASSO4) { | ||
1962 | cinfo->regbase -= 0x600000; | ||
1963 | iounmap((void *)cinfo->regbase); | ||
1964 | iounmap(info->screen_base); | 1971 | iounmap(info->screen_base); |
1965 | } else { | 1972 | if (info->fix.mmio_start > 16 * MB_) |
1966 | if (zorro_resource_start(zdev) > 0x01000000) | 1973 | iounmap(cinfo->regbase); |
1967 | iounmap(info->screen_base); | 1974 | |
1968 | } | 1975 | zorro_release_device(zdev); |
1969 | } | 1976 | } |
1970 | #endif /* CONFIG_ZORRO */ | 1977 | #endif /* CONFIG_ZORRO */ |
1971 | 1978 | ||
@@ -2222,115 +2229,102 @@ static struct pci_driver cirrusfb_pci_driver = { | |||
2222 | static int __devinit cirrusfb_zorro_register(struct zorro_dev *z, | 2229 | static int __devinit cirrusfb_zorro_register(struct zorro_dev *z, |
2223 | const struct zorro_device_id *ent) | 2230 | const struct zorro_device_id *ent) |
2224 | { | 2231 | { |
2225 | struct cirrusfb_info *cinfo; | ||
2226 | struct fb_info *info; | 2232 | struct fb_info *info; |
2233 | int error; | ||
2234 | const struct zorrocl *zcl; | ||
2227 | enum cirrus_board btype; | 2235 | enum cirrus_board btype; |
2228 | struct zorro_dev *z2 = NULL; | 2236 | unsigned long regbase, ramsize, rambase; |
2229 | unsigned long board_addr, board_size, size; | 2237 | struct cirrusfb_info *cinfo; |
2230 | int ret; | ||
2231 | |||
2232 | btype = ent->driver_data; | ||
2233 | if (cirrusfb_zorro_table2[btype].id2) | ||
2234 | z2 = zorro_find_device(cirrusfb_zorro_table2[btype].id2, NULL); | ||
2235 | size = cirrusfb_zorro_table2[btype].size; | ||
2236 | 2238 | ||
2237 | info = framebuffer_alloc(sizeof(struct cirrusfb_info), &z->dev); | 2239 | info = framebuffer_alloc(sizeof(struct cirrusfb_info), &z->dev); |
2238 | if (!info) { | 2240 | if (!info) { |
2239 | printk(KERN_ERR "cirrusfb: could not allocate memory\n"); | 2241 | printk(KERN_ERR "cirrusfb: could not allocate memory\n"); |
2240 | ret = -ENOMEM; | 2242 | return -ENOMEM; |
2241 | goto err_out; | ||
2242 | } | 2243 | } |
2243 | 2244 | ||
2244 | dev_info(info->device, "%s board detected\n", | 2245 | zcl = (const struct zorrocl *)ent->driver_data; |
2245 | cirrusfb_board_info[btype].name); | 2246 | btype = zcl->type; |
2246 | 2247 | regbase = zorro_resource_start(z) + zcl->regoffset; | |
2247 | cinfo = info->par; | 2248 | ramsize = zcl->ramsize; |
2248 | cinfo->btype = btype; | 2249 | if (ramsize) { |
2249 | 2250 | rambase = zorro_resource_start(z) + zcl->ramoffset; | |
2250 | assert(z); | 2251 | } else { |
2251 | assert(btype != BT_NONE); | 2252 | struct zorro_dev *ram = zorro_find_device(zcl->ramid, NULL); |
2253 | if (!ram || !zorro_resource_len(ram)) { | ||
2254 | dev_err(info->device, "No video RAM found\n"); | ||
2255 | error = -ENODEV; | ||
2256 | goto err_release_fb; | ||
2257 | } | ||
2258 | rambase = zorro_resource_start(ram); | ||
2259 | ramsize = zorro_resource_len(ram); | ||
2260 | } | ||
2252 | 2261 | ||
2253 | board_addr = zorro_resource_start(z); | 2262 | dev_info(info->device, |
2254 | board_size = zorro_resource_len(z); | 2263 | "%s board detected, REG at 0x%lx, %lu MiB RAM at 0x%lx\n", |
2255 | info->screen_size = size; | 2264 | cirrusfb_board_info[btype].name, regbase, ramsize / MB_, |
2265 | rambase); | ||
2256 | 2266 | ||
2257 | if (!zorro_request_device(z, "cirrusfb")) { | 2267 | if (!zorro_request_device(z, "cirrusfb")) { |
2258 | dev_err(info->device, "cannot reserve region 0x%lx, abort\n", | 2268 | dev_err(info->device, "Cannot reserve %pR\n", &z->resource); |
2259 | board_addr); | 2269 | error = -EBUSY; |
2260 | ret = -EBUSY; | ||
2261 | goto err_release_fb; | 2270 | goto err_release_fb; |
2262 | } | 2271 | } |
2263 | 2272 | ||
2264 | ret = -EIO; | 2273 | cinfo = info->par; |
2265 | 2274 | cinfo->btype = btype; | |
2266 | if (btype == BT_PICASSO4) { | ||
2267 | dev_info(info->device, " REG at $%lx\n", board_addr + 0x600000); | ||
2268 | |||
2269 | /* To be precise, for the P4 this is not the */ | ||
2270 | /* begin of the board, but the begin of RAM. */ | ||
2271 | /* for P4, map in its address space in 2 chunks (### TEST! ) */ | ||
2272 | /* (note the ugly hardcoded 16M number) */ | ||
2273 | cinfo->regbase = ioremap(board_addr, 16777216); | ||
2274 | if (!cinfo->regbase) | ||
2275 | goto err_release_region; | ||
2276 | |||
2277 | dev_dbg(info->device, "Virtual address for board set to: $%p\n", | ||
2278 | cinfo->regbase); | ||
2279 | cinfo->regbase += 0x600000; | ||
2280 | info->fix.mmio_start = board_addr + 0x600000; | ||
2281 | |||
2282 | info->fix.smem_start = board_addr + 16777216; | ||
2283 | info->screen_base = ioremap(info->fix.smem_start, 16777216); | ||
2284 | if (!info->screen_base) | ||
2285 | goto err_unmap_regbase; | ||
2286 | } else { | ||
2287 | dev_info(info->device, " REG at $%lx\n", | ||
2288 | (unsigned long) z2->resource.start); | ||
2289 | |||
2290 | info->fix.smem_start = board_addr; | ||
2291 | if (board_addr > 0x01000000) | ||
2292 | info->screen_base = ioremap(board_addr, board_size); | ||
2293 | else | ||
2294 | info->screen_base = (caddr_t) ZTWO_VADDR(board_addr); | ||
2295 | if (!info->screen_base) | ||
2296 | goto err_release_region; | ||
2297 | 2275 | ||
2298 | /* set address for REG area of board */ | 2276 | info->fix.mmio_start = regbase; |
2299 | cinfo->regbase = (caddr_t) ZTWO_VADDR(z2->resource.start); | 2277 | cinfo->regbase = regbase > 16 * MB_ ? ioremap(regbase, 64 * 1024) |
2300 | info->fix.mmio_start = z2->resource.start; | 2278 | : (caddr_t)ZTWO_VADDR(regbase); |
2279 | if (!cinfo->regbase) { | ||
2280 | dev_err(info->device, "Cannot map registers\n"); | ||
2281 | error = -EIO; | ||
2282 | goto err_release_dev; | ||
2283 | } | ||
2301 | 2284 | ||
2302 | dev_dbg(info->device, "Virtual address for board set to: $%p\n", | 2285 | info->fix.smem_start = rambase; |
2303 | cinfo->regbase); | 2286 | info->screen_size = ramsize; |
2287 | info->screen_base = rambase > 16 * MB_ ? ioremap(rambase, ramsize) | ||
2288 | : (caddr_t)ZTWO_VADDR(rambase); | ||
2289 | if (!info->screen_base) { | ||
2290 | dev_err(info->device, "Cannot map video RAM\n"); | ||
2291 | error = -EIO; | ||
2292 | goto err_unmap_reg; | ||
2304 | } | 2293 | } |
2294 | |||
2305 | cinfo->unmap = cirrusfb_zorro_unmap; | 2295 | cinfo->unmap = cirrusfb_zorro_unmap; |
2306 | 2296 | ||
2307 | dev_info(info->device, | 2297 | dev_info(info->device, |
2308 | "Cirrus Logic chipset on Zorro bus, RAM (%lu MB) at $%lx\n", | 2298 | "Cirrus Logic chipset on Zorro bus, RAM (%lu MiB) at 0x%lx\n", |
2309 | board_size / MB_, board_addr); | 2299 | ramsize / MB_, rambase); |
2310 | |||
2311 | zorro_set_drvdata(z, info); | ||
2312 | 2300 | ||
2313 | /* MCLK select etc. */ | 2301 | /* MCLK select etc. */ |
2314 | if (cirrusfb_board_info[btype].init_sr1f) | 2302 | if (cirrusfb_board_info[btype].init_sr1f) |
2315 | vga_wseq(cinfo->regbase, CL_SEQR1F, | 2303 | vga_wseq(cinfo->regbase, CL_SEQR1F, |
2316 | cirrusfb_board_info[btype].sr1f); | 2304 | cirrusfb_board_info[btype].sr1f); |
2317 | 2305 | ||
2318 | ret = cirrusfb_register(info); | 2306 | error = cirrusfb_register(info); |
2319 | if (!ret) | 2307 | if (error) { |
2320 | return 0; | 2308 | dev_err(info->device, "Failed to register device, error %d\n", |
2309 | error); | ||
2310 | goto err_unmap_ram; | ||
2311 | } | ||
2321 | 2312 | ||
2322 | if (btype == BT_PICASSO4 || board_addr > 0x01000000) | 2313 | zorro_set_drvdata(z, info); |
2314 | return 0; | ||
2315 | |||
2316 | err_unmap_ram: | ||
2317 | if (rambase > 16 * MB_) | ||
2323 | iounmap(info->screen_base); | 2318 | iounmap(info->screen_base); |
2324 | 2319 | ||
2325 | err_unmap_regbase: | 2320 | err_unmap_reg: |
2326 | if (btype == BT_PICASSO4) | 2321 | if (regbase > 16 * MB_) |
2327 | iounmap(cinfo->regbase - 0x600000); | 2322 | iounmap(cinfo->regbase); |
2328 | err_release_region: | 2323 | err_release_dev: |
2329 | release_region(board_addr, board_size); | 2324 | zorro_release_device(z); |
2330 | err_release_fb: | 2325 | err_release_fb: |
2331 | framebuffer_release(info); | 2326 | framebuffer_release(info); |
2332 | err_out: | 2327 | return error; |
2333 | return ret; | ||
2334 | } | 2328 | } |
2335 | 2329 | ||
2336 | void __devexit cirrusfb_zorro_unregister(struct zorro_dev *z) | 2330 | void __devexit cirrusfb_zorro_unregister(struct zorro_dev *z) |
@@ -2338,6 +2332,7 @@ void __devexit cirrusfb_zorro_unregister(struct zorro_dev *z) | |||
2338 | struct fb_info *info = zorro_get_drvdata(z); | 2332 | struct fb_info *info = zorro_get_drvdata(z); |
2339 | 2333 | ||
2340 | cirrusfb_cleanup(info); | 2334 | cirrusfb_cleanup(info); |
2335 | zorro_set_drvdata(z, NULL); | ||
2341 | } | 2336 | } |
2342 | 2337 | ||
2343 | static struct zorro_driver cirrusfb_zorro_driver = { | 2338 | static struct zorro_driver cirrusfb_zorro_driver = { |