Commit 0e0d1336 authored by Geert Uytterhoeven's avatar Geert Uytterhoeven Committed by Florian Tobias Schandinat

fbdev/cirrusfb: Rewrite Zorro graphics card probing

As indicated by commit a7f4d00a ("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: default avatarGeert Uytterhoeven <geert@linux-m68k.org>
Acked-by: default avatarJeff Garzik <jgarzik@redhat.com>
Signed-off-by: default avatarFlorian Tobias Schandinat <FlorianSchandinat@gmx.de>
parent 38eb6863
...@@ -280,52 +280,63 @@ MODULE_DEVICE_TABLE(pci, cirrusfb_pci_table); ...@@ -280,52 +280,63 @@ MODULE_DEVICE_TABLE(pci, cirrusfb_pci_table);
#endif /* CONFIG_PCI */ #endif /* CONFIG_PCI */
#ifdef CONFIG_ZORRO #ifdef CONFIG_ZORRO
static const struct zorro_device_id cirrusfb_zorro_table[] = { struct zorrocl {
enum cirrus_board type; /* Board type */
u32 regoffset; /* Offset of registers in first Zorro device */
u32 ramsize; /* Size of video RAM in first Zorro device */
/* If zero, use autoprobe on RAM device */
u32 ramoffset; /* Offset of video RAM in first Zorro device */
zorro_id ramid; /* Zorro ID of RAM device */
};
static const struct zorrocl zcl_sd64 __devinitconst = {
.type = BT_SD64,
.ramid = ZORRO_PROD_HELFRICH_SD64_RAM,
};
static const struct zorrocl zcl_piccolo __devinitconst = {
.type = BT_PICCOLO,
.ramid = ZORRO_PROD_HELFRICH_PICCOLO_RAM,
};
static const struct zorrocl zcl_picasso __devinitconst = {
.type = BT_PICASSO,
.ramid = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM,
};
static const struct zorrocl zcl_spectrum __devinitconst = {
.type = BT_SPECTRUM,
.ramid = ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_RAM,
};
static const struct zorrocl zcl_picasso4_z3 __devinitconst = {
.type = BT_PICASSO4,
.regoffset = 0x00600000,
.ramsize = 4 * MB_,
.ramoffset = 0x01000000,
};
static const struct zorro_device_id cirrusfb_zorro_table[] __devinitconst = {
{ {
.id = ZORRO_PROD_HELFRICH_SD64_RAM, .id = ZORRO_PROD_HELFRICH_SD64_REG,
.driver_data = BT_SD64, .driver_data = (unsigned long)&zcl_sd64,
}, { }, {
.id = ZORRO_PROD_HELFRICH_PICCOLO_RAM, .id = ZORRO_PROD_HELFRICH_PICCOLO_REG,
.driver_data = BT_PICCOLO, .driver_data = (unsigned long)&zcl_piccolo,
}, { }, {
.id = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM, .id = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_REG,
.driver_data = BT_PICASSO, .driver_data = (unsigned long)&zcl_picasso,
}, { }, {
.id = ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_RAM, .id = ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_REG,
.driver_data = BT_SPECTRUM, .driver_data = (unsigned long)&zcl_spectrum,
}, { }, {
.id = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z3, .id = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z3,
.driver_data = BT_PICASSO4, .driver_data = (unsigned long)&zcl_picasso4_z3,
}, },
{ 0 } { 0 }
}; };
MODULE_DEVICE_TABLE(zorro, cirrusfb_zorro_table); MODULE_DEVICE_TABLE(zorro, cirrusfb_zorro_table);
static const struct {
zorro_id id2;
unsigned long size;
} cirrusfb_zorro_table2[] = {
[BT_SD64] = {
.id2 = ZORRO_PROD_HELFRICH_SD64_REG,
.size = 0x400000
},
[BT_PICCOLO] = {
.id2 = ZORRO_PROD_HELFRICH_PICCOLO_REG,
.size = 0x200000
},
[BT_PICASSO] = {
.id2 = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_REG,
.size = 0x200000
},
[BT_SPECTRUM] = {
.id2 = ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_REG,
.size = 0x200000
},
[BT_PICASSO4] = {
.id2 = 0,
.size = 0x400000
}
};
#endif /* CONFIG_ZORRO */ #endif /* CONFIG_ZORRO */
#ifdef CIRRUSFB_DEBUG #ifdef CIRRUSFB_DEBUG
...@@ -1956,16 +1967,12 @@ static void cirrusfb_zorro_unmap(struct fb_info *info) ...@@ -1956,16 +1967,12 @@ static void cirrusfb_zorro_unmap(struct fb_info *info)
struct cirrusfb_info *cinfo = info->par; struct cirrusfb_info *cinfo = info->par;
struct zorro_dev *zdev = to_zorro_dev(info->device); struct zorro_dev *zdev = to_zorro_dev(info->device);
zorro_release_device(zdev); if (info->fix.smem_start > 16 * MB_)
if (cinfo->btype == BT_PICASSO4) {
cinfo->regbase -= 0x600000;
iounmap((void *)cinfo->regbase);
iounmap(info->screen_base); iounmap(info->screen_base);
} else { if (info->fix.mmio_start > 16 * MB_)
if (zorro_resource_start(zdev) > 0x01000000) iounmap(cinfo->regbase);
iounmap(info->screen_base);
} zorro_release_device(zdev);
} }
#endif /* CONFIG_ZORRO */ #endif /* CONFIG_ZORRO */
...@@ -2222,115 +2229,102 @@ static struct pci_driver cirrusfb_pci_driver = { ...@@ -2222,115 +2229,102 @@ static struct pci_driver cirrusfb_pci_driver = {
static int __devinit cirrusfb_zorro_register(struct zorro_dev *z, static int __devinit cirrusfb_zorro_register(struct zorro_dev *z,
const struct zorro_device_id *ent) const struct zorro_device_id *ent)
{ {
struct cirrusfb_info *cinfo;
struct fb_info *info; struct fb_info *info;
int error;
const struct zorrocl *zcl;
enum cirrus_board btype; enum cirrus_board btype;
struct zorro_dev *z2 = NULL; unsigned long regbase, ramsize, rambase;
unsigned long board_addr, board_size, size; struct cirrusfb_info *cinfo;
int ret;
btype = ent->driver_data;
if (cirrusfb_zorro_table2[btype].id2)
z2 = zorro_find_device(cirrusfb_zorro_table2[btype].id2, NULL);
size = cirrusfb_zorro_table2[btype].size;
info = framebuffer_alloc(sizeof(struct cirrusfb_info), &z->dev); info = framebuffer_alloc(sizeof(struct cirrusfb_info), &z->dev);
if (!info) { if (!info) {
printk(KERN_ERR "cirrusfb: could not allocate memory\n"); printk(KERN_ERR "cirrusfb: could not allocate memory\n");
ret = -ENOMEM; return -ENOMEM;
goto err_out;
} }
dev_info(info->device, "%s board detected\n", zcl = (const struct zorrocl *)ent->driver_data;
cirrusfb_board_info[btype].name); btype = zcl->type;
regbase = zorro_resource_start(z) + zcl->regoffset;
cinfo = info->par; ramsize = zcl->ramsize;
cinfo->btype = btype; if (ramsize) {
rambase = zorro_resource_start(z) + zcl->ramoffset;
assert(z); } else {
assert(btype != BT_NONE); struct zorro_dev *ram = zorro_find_device(zcl->ramid, NULL);
if (!ram || !zorro_resource_len(ram)) {
dev_err(info->device, "No video RAM found\n");
error = -ENODEV;
goto err_release_fb;
}
rambase = zorro_resource_start(ram);
ramsize = zorro_resource_len(ram);
}
board_addr = zorro_resource_start(z); dev_info(info->device,
board_size = zorro_resource_len(z); "%s board detected, REG at 0x%lx, %lu MiB RAM at 0x%lx\n",
info->screen_size = size; cirrusfb_board_info[btype].name, regbase, ramsize / MB_,
rambase);
if (!zorro_request_device(z, "cirrusfb")) { if (!zorro_request_device(z, "cirrusfb")) {
dev_err(info->device, "cannot reserve region 0x%lx, abort\n", dev_err(info->device, "Cannot reserve %pR\n", &z->resource);
board_addr); error = -EBUSY;
ret = -EBUSY;
goto err_release_fb; goto err_release_fb;
} }
ret = -EIO; cinfo = info->par;
cinfo->btype = btype;
if (btype == BT_PICASSO4) {
dev_info(info->device, " REG at $%lx\n", board_addr + 0x600000);
/* To be precise, for the P4 this is not the */
/* begin of the board, but the begin of RAM. */
/* for P4, map in its address space in 2 chunks (### TEST! ) */
/* (note the ugly hardcoded 16M number) */
cinfo->regbase = ioremap(board_addr, 16777216);
if (!cinfo->regbase)
goto err_release_region;
dev_dbg(info->device, "Virtual address for board set to: $%p\n",
cinfo->regbase);
cinfo->regbase += 0x600000;
info->fix.mmio_start = board_addr + 0x600000;
info->fix.smem_start = board_addr + 16777216;
info->screen_base = ioremap(info->fix.smem_start, 16777216);
if (!info->screen_base)
goto err_unmap_regbase;
} else {
dev_info(info->device, " REG at $%lx\n",
(unsigned long) z2->resource.start);
info->fix.smem_start = board_addr;
if (board_addr > 0x01000000)
info->screen_base = ioremap(board_addr, board_size);
else
info->screen_base = (caddr_t) ZTWO_VADDR(board_addr);
if (!info->screen_base)
goto err_release_region;
/* set address for REG area of board */ info->fix.mmio_start = regbase;
cinfo->regbase = (caddr_t) ZTWO_VADDR(z2->resource.start); cinfo->regbase = regbase > 16 * MB_ ? ioremap(regbase, 64 * 1024)
info->fix.mmio_start = z2->resource.start; : (caddr_t)ZTWO_VADDR(regbase);
if (!cinfo->regbase) {
dev_err(info->device, "Cannot map registers\n");
error = -EIO;
goto err_release_dev;
}
dev_dbg(info->device, "Virtual address for board set to: $%p\n", info->fix.smem_start = rambase;
cinfo->regbase); info->screen_size = ramsize;
info->screen_base = rambase > 16 * MB_ ? ioremap(rambase, ramsize)
: (caddr_t)ZTWO_VADDR(rambase);
if (!info->screen_base) {
dev_err(info->device, "Cannot map video RAM\n");
error = -EIO;
goto err_unmap_reg;
} }
cinfo->unmap = cirrusfb_zorro_unmap; cinfo->unmap = cirrusfb_zorro_unmap;
dev_info(info->device, dev_info(info->device,
"Cirrus Logic chipset on Zorro bus, RAM (%lu MB) at $%lx\n", "Cirrus Logic chipset on Zorro bus, RAM (%lu MiB) at 0x%lx\n",
board_size / MB_, board_addr); ramsize / MB_, rambase);
zorro_set_drvdata(z, info);
/* MCLK select etc. */ /* MCLK select etc. */
if (cirrusfb_board_info[btype].init_sr1f) if (cirrusfb_board_info[btype].init_sr1f)
vga_wseq(cinfo->regbase, CL_SEQR1F, vga_wseq(cinfo->regbase, CL_SEQR1F,
cirrusfb_board_info[btype].sr1f); cirrusfb_board_info[btype].sr1f);
ret = cirrusfb_register(info); error = cirrusfb_register(info);
if (!ret) if (error) {
dev_err(info->device, "Failed to register device, error %d\n",
error);
goto err_unmap_ram;
}
zorro_set_drvdata(z, info);
return 0; return 0;
if (btype == BT_PICASSO4 || board_addr > 0x01000000) err_unmap_ram:
if (rambase > 16 * MB_)
iounmap(info->screen_base); iounmap(info->screen_base);
err_unmap_regbase: err_unmap_reg:
if (btype == BT_PICASSO4) if (regbase > 16 * MB_)
iounmap(cinfo->regbase - 0x600000); iounmap(cinfo->regbase);
err_release_region: err_release_dev:
release_region(board_addr, board_size); zorro_release_device(z);
err_release_fb: err_release_fb:
framebuffer_release(info); framebuffer_release(info);
err_out: return error;
return ret;
} }
void __devexit cirrusfb_zorro_unregister(struct zorro_dev *z) void __devexit cirrusfb_zorro_unregister(struct zorro_dev *z)
...@@ -2338,6 +2332,7 @@ void __devexit cirrusfb_zorro_unregister(struct zorro_dev *z) ...@@ -2338,6 +2332,7 @@ void __devexit cirrusfb_zorro_unregister(struct zorro_dev *z)
struct fb_info *info = zorro_get_drvdata(z); struct fb_info *info = zorro_get_drvdata(z);
cirrusfb_cleanup(info); cirrusfb_cleanup(info);
zorro_set_drvdata(z, NULL);
} }
static struct zorro_driver cirrusfb_zorro_driver = { static struct zorro_driver cirrusfb_zorro_driver = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment