in fbdev/intelfb/intelfbdrv.c [469:891]
static int intelfb_pci_register(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
struct fb_info *info;
struct intelfb_info *dinfo;
int i, err, dvo;
int aperture_size, stolen_size;
struct agp_kern_info gtt_info;
int agp_memtype;
const char *s;
struct agp_bridge_data *bridge;
int aperture_bar = 0;
int mmio_bar = 1;
int offset;
DBG_MSG("intelfb_pci_register\n");
num_registered++;
if (num_registered != 1) {
ERR_MSG("Attempted to register %d devices "
"(should be only 1).\n", num_registered);
return -ENODEV;
}
info = framebuffer_alloc(sizeof(struct intelfb_info), &pdev->dev);
if (!info)
return -ENOMEM;
if (fb_alloc_cmap(&info->cmap, 256, 1) < 0) {
ERR_MSG("Could not allocate cmap for intelfb_info.\n");
goto err_out_cmap;
}
dinfo = info->par;
dinfo->info = info;
dinfo->fbops = &intel_fb_ops;
dinfo->pdev = pdev;
/* Reserve pixmap space. */
info->pixmap.addr = kzalloc(64 * 1024, GFP_KERNEL);
if (info->pixmap.addr == NULL) {
ERR_MSG("Cannot reserve pixmap memory.\n");
goto err_out_pixmap;
}
/* set early this option because it could be changed by tv encoder
driver */
dinfo->fixed_mode = fixed;
/* Enable device. */
if ((err = pci_enable_device(pdev))) {
ERR_MSG("Cannot enable device.\n");
cleanup(dinfo);
return -ENODEV;
}
/* Set base addresses. */
if ((ent->device == PCI_DEVICE_ID_INTEL_915G) ||
(ent->device == PCI_DEVICE_ID_INTEL_915GM) ||
(ent->device == PCI_DEVICE_ID_INTEL_945G) ||
(ent->device == PCI_DEVICE_ID_INTEL_945GM) ||
(ent->device == PCI_DEVICE_ID_INTEL_945GME) ||
(ent->device == PCI_DEVICE_ID_INTEL_965G) ||
(ent->device == PCI_DEVICE_ID_INTEL_965GM)) {
aperture_bar = 2;
mmio_bar = 0;
}
dinfo->aperture.physical = pci_resource_start(pdev, aperture_bar);
dinfo->aperture.size = pci_resource_len(pdev, aperture_bar);
dinfo->mmio_base_phys = pci_resource_start(pdev, mmio_bar);
DBG_MSG("fb aperture: 0x%llx/0x%llx, MMIO region: 0x%llx/0x%llx\n",
(unsigned long long)pci_resource_start(pdev, aperture_bar),
(unsigned long long)pci_resource_len(pdev, aperture_bar),
(unsigned long long)pci_resource_start(pdev, mmio_bar),
(unsigned long long)pci_resource_len(pdev, mmio_bar));
/* Reserve the fb and MMIO regions */
if (!request_mem_region(dinfo->aperture.physical, dinfo->aperture.size,
INTELFB_MODULE_NAME)) {
ERR_MSG("Cannot reserve FB region.\n");
cleanup(dinfo);
return -ENODEV;
}
dinfo->flag |= INTELFB_FB_ACQUIRED;
if (!request_mem_region(dinfo->mmio_base_phys,
INTEL_REG_SIZE,
INTELFB_MODULE_NAME)) {
ERR_MSG("Cannot reserve MMIO region.\n");
cleanup(dinfo);
return -ENODEV;
}
dinfo->flag |= INTELFB_MMIO_ACQUIRED;
/* Get the chipset info. */
dinfo->pci_chipset = pdev->device;
if (intelfbhw_get_chipset(pdev, dinfo)) {
cleanup(dinfo);
return -ENODEV;
}
if (intelfbhw_get_memory(pdev, &aperture_size,&stolen_size)) {
cleanup(dinfo);
return -ENODEV;
}
INF_MSG("%02x:%02x.%d: %s, aperture size %dMB, "
"stolen memory %dkB\n",
pdev->bus->number, PCI_SLOT(pdev->devfn),
PCI_FUNC(pdev->devfn), dinfo->name,
BtoMB(aperture_size), BtoKB(stolen_size));
/* Set these from the options. */
dinfo->accel = accel;
dinfo->hwcursor = hwcursor;
if (NOACCEL_CHIPSET(dinfo) && dinfo->accel == 1) {
INF_MSG("Acceleration is not supported for the %s chipset.\n",
dinfo->name);
dinfo->accel = 0;
}
/* Framebuffer parameters - Use all the stolen memory if >= vram */
if (ROUND_UP_TO_PAGE(stolen_size) >= MB(vram)) {
dinfo->fb.size = ROUND_UP_TO_PAGE(stolen_size);
dinfo->fbmem_gart = 0;
} else {
dinfo->fb.size = MB(vram);
dinfo->fbmem_gart = 1;
}
/* Allocate space for the ring buffer and HW cursor if enabled. */
if (dinfo->accel) {
dinfo->ring.size = RINGBUFFER_SIZE;
dinfo->ring_tail_mask = dinfo->ring.size - 1;
}
if (dinfo->hwcursor)
dinfo->cursor.size = HW_CURSOR_SIZE;
/* Use agpgart to manage the GATT */
if (!(bridge = agp_backend_acquire(pdev))) {
ERR_MSG("cannot acquire agp\n");
cleanup(dinfo);
return -ENODEV;
}
/* get the current gatt info */
if (agp_copy_info(bridge, >t_info)) {
ERR_MSG("cannot get agp info\n");
agp_backend_release(bridge);
cleanup(dinfo);
return -ENODEV;
}
if (MB(voffset) < stolen_size)
offset = (stolen_size >> 12);
else
offset = ROUND_UP_TO_PAGE(MB(voffset))/GTT_PAGE_SIZE;
/* set the mem offsets - set them after the already used pages */
if (dinfo->accel)
dinfo->ring.offset = offset + gtt_info.current_memory;
if (dinfo->hwcursor)
dinfo->cursor.offset = offset +
+ gtt_info.current_memory + (dinfo->ring.size >> 12);
if (dinfo->fbmem_gart)
dinfo->fb.offset = offset +
+ gtt_info.current_memory + (dinfo->ring.size >> 12)
+ (dinfo->cursor.size >> 12);
/* Allocate memories (which aren't stolen) */
/* Map the fb and MMIO regions */
/* ioremap only up to the end of used aperture */
dinfo->aperture.virtual = (u8 __iomem *)ioremap_wc
(dinfo->aperture.physical, ((offset + dinfo->fb.offset) << 12)
+ dinfo->fb.size);
if (!dinfo->aperture.virtual) {
ERR_MSG("Cannot remap FB region.\n");
agp_backend_release(bridge);
cleanup(dinfo);
return -ENODEV;
}
dinfo->mmio_base =
(u8 __iomem *)ioremap(dinfo->mmio_base_phys,
INTEL_REG_SIZE);
if (!dinfo->mmio_base) {
ERR_MSG("Cannot remap MMIO region.\n");
agp_backend_release(bridge);
cleanup(dinfo);
return -ENODEV;
}
if (dinfo->accel) {
if (!(dinfo->gtt_ring_mem =
agp_allocate_memory(bridge, dinfo->ring.size >> 12,
AGP_NORMAL_MEMORY))) {
ERR_MSG("cannot allocate ring buffer memory\n");
agp_backend_release(bridge);
cleanup(dinfo);
return -ENOMEM;
}
if (agp_bind_memory(dinfo->gtt_ring_mem,
dinfo->ring.offset)) {
ERR_MSG("cannot bind ring buffer memory\n");
agp_backend_release(bridge);
cleanup(dinfo);
return -EBUSY;
}
dinfo->ring.physical = dinfo->aperture.physical
+ (dinfo->ring.offset << 12);
dinfo->ring.virtual = dinfo->aperture.virtual
+ (dinfo->ring.offset << 12);
dinfo->ring_head = 0;
}
if (dinfo->hwcursor) {
agp_memtype = dinfo->mobile ? AGP_PHYSICAL_MEMORY
: AGP_NORMAL_MEMORY;
if (!(dinfo->gtt_cursor_mem =
agp_allocate_memory(bridge, dinfo->cursor.size >> 12,
agp_memtype))) {
ERR_MSG("cannot allocate cursor memory\n");
agp_backend_release(bridge);
cleanup(dinfo);
return -ENOMEM;
}
if (agp_bind_memory(dinfo->gtt_cursor_mem,
dinfo->cursor.offset)) {
ERR_MSG("cannot bind cursor memory\n");
agp_backend_release(bridge);
cleanup(dinfo);
return -EBUSY;
}
if (dinfo->mobile)
dinfo->cursor.physical
= dinfo->gtt_cursor_mem->physical;
else
dinfo->cursor.physical = dinfo->aperture.physical
+ (dinfo->cursor.offset << 12);
dinfo->cursor.virtual = dinfo->aperture.virtual
+ (dinfo->cursor.offset << 12);
}
if (dinfo->fbmem_gart) {
if (!(dinfo->gtt_fb_mem =
agp_allocate_memory(bridge, dinfo->fb.size >> 12,
AGP_NORMAL_MEMORY))) {
WRN_MSG("cannot allocate framebuffer memory - use "
"the stolen one\n");
dinfo->fbmem_gart = 0;
}
if (agp_bind_memory(dinfo->gtt_fb_mem,
dinfo->fb.offset)) {
WRN_MSG("cannot bind framebuffer memory - use "
"the stolen one\n");
dinfo->fbmem_gart = 0;
}
}
/* update framebuffer memory parameters */
if (!dinfo->fbmem_gart)
dinfo->fb.offset = 0; /* starts at offset 0 */
dinfo->fb.physical = dinfo->aperture.physical
+ (dinfo->fb.offset << 12);
dinfo->fb.virtual = dinfo->aperture.virtual + (dinfo->fb.offset << 12);
dinfo->fb_start = dinfo->fb.offset << 12;
/* release agpgart */
agp_backend_release(bridge);
if (mtrr)
dinfo->wc_cookie = arch_phys_wc_add(dinfo->aperture.physical,
dinfo->aperture.size);
DBG_MSG("fb: 0x%x(+ 0x%x)/0x%x (0x%p)\n",
dinfo->fb.physical, dinfo->fb.offset, dinfo->fb.size,
dinfo->fb.virtual);
DBG_MSG("MMIO: 0x%x/0x%x (0x%p)\n",
dinfo->mmio_base_phys, INTEL_REG_SIZE,
dinfo->mmio_base);
DBG_MSG("ring buffer: 0x%x/0x%x (0x%p)\n",
dinfo->ring.physical, dinfo->ring.size,
dinfo->ring.virtual);
DBG_MSG("HW cursor: 0x%x/0x%x (0x%p) (offset 0x%x) (phys 0x%x)\n",
dinfo->cursor.physical, dinfo->cursor.size,
dinfo->cursor.virtual, dinfo->cursor.offset,
dinfo->cursor.physical);
DBG_MSG("options: vram = %d, accel = %d, hwcursor = %d, fixed = %d, "
"noinit = %d\n", vram, accel, hwcursor, fixed, noinit);
DBG_MSG("options: mode = \"%s\"\n", mode ? mode : "");
if (probeonly)
bailout(dinfo);
/*
* Check if the LVDS port or any DVO ports are enabled. If so,
* don't allow mode switching
*/
dvo = intelfbhw_check_non_crt(dinfo);
if (dvo) {
dinfo->fixed_mode = 1;
WRN_MSG("Non-CRT device is enabled ( ");
i = 0;
while (dvo) {
if (dvo & 1) {
s = intelfbhw_dvo_to_string(1 << i);
if (s)
printk("%s ", s);
}
dvo >>= 1;
++i;
}
printk("). Disabling mode switching.\n");
}
if (bailearly == 1)
bailout(dinfo);
if (FIXED_MODE(dinfo) &&
screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB) {
ERR_MSG("Video mode must be programmed at boot time.\n");
cleanup(dinfo);
return -ENODEV;
}
if (bailearly == 2)
bailout(dinfo);
/* Initialise dinfo and related data. */
/* If an initial mode was programmed at boot time, get its details. */
if (screen_info.orig_video_isVGA == VIDEO_TYPE_VLFB)
get_initial_mode(dinfo);
if (bailearly == 3)
bailout(dinfo);
if (FIXED_MODE(dinfo)) /* remap fb address */
update_dinfo(dinfo, &dinfo->initial_var);
if (bailearly == 4)
bailout(dinfo);
if (intelfb_set_fbinfo(dinfo)) {
cleanup(dinfo);
return -ENODEV;
}
if (bailearly == 5)
bailout(dinfo);
#ifdef CONFIG_FB_INTEL_I2C
/* register I2C bus */
intelfb_create_i2c_busses(dinfo);
#endif
if (bailearly == 6)
bailout(dinfo);
pci_set_drvdata(pdev, dinfo);
/* Save the initial register state. */
i = intelfbhw_read_hw_state(dinfo, &dinfo->save_state,
bailearly > 6 ? bailearly - 6 : 0);
if (i != 0) {
DBG_MSG("intelfbhw_read_hw_state returned %d\n", i);
bailout(dinfo);
}
intelfbhw_print_hw_state(dinfo, &dinfo->save_state);
if (bailearly == 18)
bailout(dinfo);
/* read active pipe */
dinfo->pipe = intelfbhw_active_pipe(&dinfo->save_state);
/* Cursor initialisation */
if (dinfo->hwcursor) {
intelfbhw_cursor_init(dinfo);
intelfbhw_cursor_reset(dinfo);
}
if (bailearly == 19)
bailout(dinfo);
/* 2d acceleration init */
if (dinfo->accel)
intelfbhw_2d_start(dinfo);
if (bailearly == 20)
bailout(dinfo);
if (noregister)
bailout(dinfo);
if (register_framebuffer(dinfo->info) < 0) {
ERR_MSG("Cannot register framebuffer.\n");
cleanup(dinfo);
return -ENODEV;
}
dinfo->registered = 1;
dinfo->open = 0;
init_waitqueue_head(&dinfo->vsync.wait);
spin_lock_init(&dinfo->int_lock);
dinfo->irq_flags = 0;
dinfo->vsync.pan_display = 0;
dinfo->vsync.pan_offset = 0;
return 0;
err_out_pixmap:
fb_dealloc_cmap(&info->cmap);
err_out_cmap:
framebuffer_release(info);
return -ENODEV;
}