static int intelfb_pci_register()

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, &gtt_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;
}