static int initMatrox2()

in fbdev/matrox/matroxfb_base.c [1633:1962]


static int initMatrox2(struct matrox_fb_info *minfo, struct board *b)
{
	unsigned long ctrlptr_phys = 0;
	unsigned long video_base_phys = 0;
	unsigned int memsize;
	int err;

	static const struct pci_device_id intel_82437[] = {
		{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437) },
		{ },
	};

	DBG(__func__)

	/* set default values... */
	vesafb_defined.accel_flags = FB_ACCELF_TEXT;

	minfo->hw_switch = b->base->lowlevel;
	minfo->devflags.accelerator = b->base->accelID;
	minfo->max_pixel_clock = b->maxclk;

	printk(KERN_INFO "matroxfb: Matrox %s detected\n", b->name);
	minfo->capable.plnwt = 1;
	minfo->chip = b->chip;
	minfo->capable.srcorg = b->flags & DEVF_SRCORG;
	minfo->devflags.video64bits = b->flags & DEVF_VIDEO64BIT;
	if (b->flags & DEVF_TEXT4B) {
		minfo->devflags.vgastep = 4;
		minfo->devflags.textmode = 4;
		minfo->devflags.text_type_aux = FB_AUX_TEXT_MGA_STEP16;
	} else if (b->flags & DEVF_TEXT16B) {
		minfo->devflags.vgastep = 16;
		minfo->devflags.textmode = 1;
		minfo->devflags.text_type_aux = FB_AUX_TEXT_MGA_STEP16;
	} else {
		minfo->devflags.vgastep = 8;
		minfo->devflags.textmode = 1;
		minfo->devflags.text_type_aux = FB_AUX_TEXT_MGA_STEP8;
	}
	minfo->devflags.support32MB = (b->flags & DEVF_SUPPORT32MB) != 0;
	minfo->devflags.precise_width = !(b->flags & DEVF_ANY_VXRES);
	minfo->devflags.crtc2 = (b->flags & DEVF_CRTC2) != 0;
	minfo->devflags.maven_capable = (b->flags & DEVF_MAVEN_CAPABLE) != 0;
	minfo->devflags.dualhead = (b->flags & DEVF_DUALHEAD) != 0;
	minfo->devflags.dfp_type = dfp_type;
	minfo->devflags.g450dac = (b->flags & DEVF_G450DAC) != 0;
	minfo->devflags.textstep = minfo->devflags.vgastep * minfo->devflags.textmode;
	minfo->devflags.textvram = 65536 / minfo->devflags.textmode;
	setDefaultOutputs(minfo);
	if (b->flags & DEVF_PANELLINK_CAPABLE) {
		minfo->outputs[2].data = minfo;
		minfo->outputs[2].output = &panellink_output;
		minfo->outputs[2].src = minfo->outputs[2].default_src;
		minfo->outputs[2].mode = MATROXFB_OUTPUT_MODE_MONITOR;
		minfo->devflags.panellink = 1;
	}

	if (minfo->capable.cross4MB < 0)
		minfo->capable.cross4MB = b->flags & DEVF_CROSS4MB;
	if (b->flags & DEVF_SWAPS) {
		ctrlptr_phys = pci_resource_start(minfo->pcidev, 1);
		video_base_phys = pci_resource_start(minfo->pcidev, 0);
		minfo->devflags.fbResource = PCI_BASE_ADDRESS_0;
	} else {
		ctrlptr_phys = pci_resource_start(minfo->pcidev, 0);
		video_base_phys = pci_resource_start(minfo->pcidev, 1);
		minfo->devflags.fbResource = PCI_BASE_ADDRESS_1;
	}
	err = -EINVAL;
	if (!ctrlptr_phys) {
		printk(KERN_ERR "matroxfb: control registers are not available, matroxfb disabled\n");
		goto fail;
	}
	if (!video_base_phys) {
		printk(KERN_ERR "matroxfb: video RAM is not available in PCI address space, matroxfb disabled\n");
		goto fail;
	}
	memsize = b->base->maxvram;
	if (!request_mem_region(ctrlptr_phys, 16384, "matroxfb MMIO")) {
		goto fail;
	}
	if (!request_mem_region(video_base_phys, memsize, "matroxfb FB")) {
		goto failCtrlMR;
	}
	minfo->video.len_maximum = memsize;
	/* convert mem (autodetect k, M) */
	if (mem < 1024) mem *= 1024;
	if (mem < 0x00100000) mem *= 1024;

	if (mem && (mem < memsize))
		memsize = mem;
	err = -ENOMEM;

	minfo->mmio.vbase.vaddr = ioremap(ctrlptr_phys, 16384);
	if (!minfo->mmio.vbase.vaddr) {
		printk(KERN_ERR "matroxfb: cannot ioremap(%lX, 16384), matroxfb disabled\n", ctrlptr_phys);
		goto failVideoMR;
	}
	minfo->mmio.base = ctrlptr_phys;
	minfo->mmio.len = 16384;
	minfo->video.base = video_base_phys;
	minfo->video.vbase.vaddr = ioremap_wc(video_base_phys, memsize);
	if (!minfo->video.vbase.vaddr) {
		printk(KERN_ERR "matroxfb: cannot ioremap(%lX, %d), matroxfb disabled\n",
			video_base_phys, memsize);
		goto failCtrlIO;
	}
	{
		u_int32_t cmd;
		u_int32_t mga_option;

		pci_read_config_dword(minfo->pcidev, PCI_OPTION_REG, &mga_option);
		pci_read_config_dword(minfo->pcidev, PCI_COMMAND, &cmd);
		mga_option &= 0x7FFFFFFF; /* clear BIG_ENDIAN */
		mga_option |= MX_OPTION_BSWAP;
		/* disable palette snooping */
		cmd &= ~PCI_COMMAND_VGA_PALETTE;
		if (pci_dev_present(intel_82437)) {
			if (!(mga_option & 0x20000000) && !minfo->devflags.nopciretry) {
				printk(KERN_WARNING "matroxfb: Disabling PCI retries due to i82437 present\n");
			}
			mga_option |= 0x20000000;
			minfo->devflags.nopciretry = 1;
		}
		pci_write_config_dword(minfo->pcidev, PCI_COMMAND, cmd);
		pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, mga_option);
		minfo->hw.MXoptionReg = mga_option;

		/* select non-DMA memory for PCI_MGA_DATA, otherwise dump of PCI cfg space can lock PCI bus */
		/* maybe preinit() candidate, but it is same... for all devices... at this time... */
		pci_write_config_dword(minfo->pcidev, PCI_MGA_INDEX, 0x00003C00);
	}

	err = -ENXIO;
	matroxfb_read_pins(minfo);
	if (minfo->hw_switch->preinit(minfo)) {
		goto failVideoIO;
	}

	err = -ENOMEM;
	if (!matroxfb_getmemory(minfo, memsize, &minfo->video.len) || !minfo->video.len) {
		printk(KERN_ERR "matroxfb: cannot determine memory size\n");
		goto failVideoIO;
	}
	minfo->devflags.ydstorg = 0;

	minfo->video.base = video_base_phys;
	minfo->video.len_usable = minfo->video.len;
	if (minfo->video.len_usable > b->base->maxdisplayable)
		minfo->video.len_usable = b->base->maxdisplayable;
	if (mtrr)
		minfo->wc_cookie = arch_phys_wc_add(video_base_phys,
						    minfo->video.len);

	if (!minfo->devflags.novga)
		request_region(0x3C0, 32, "matrox");
	matroxfb_g450_connect(minfo);
	minfo->hw_switch->reset(minfo);

	minfo->fbcon.monspecs.hfmin = 0;
	minfo->fbcon.monspecs.hfmax = fh;
	minfo->fbcon.monspecs.vfmin = 0;
	minfo->fbcon.monspecs.vfmax = fv;
	minfo->fbcon.monspecs.dpms = 0;	/* TBD */

	/* static settings */
	vesafb_defined.red = colors[depth-1].red;
	vesafb_defined.green = colors[depth-1].green;
	vesafb_defined.blue = colors[depth-1].blue;
	vesafb_defined.bits_per_pixel = colors[depth-1].bits_per_pixel;
	vesafb_defined.grayscale = grayscale;
	vesafb_defined.vmode = 0;
	if (noaccel)
		vesafb_defined.accel_flags &= ~FB_ACCELF_TEXT;

	minfo->fbops = matroxfb_ops;
	minfo->fbcon.fbops = &minfo->fbops;
	minfo->fbcon.pseudo_palette = minfo->cmap;
	minfo->fbcon.flags = FBINFO_PARTIAL_PAN_OK | 	 /* Prefer panning for scroll under MC viewer/edit */
				      FBINFO_HWACCEL_COPYAREA |  /* We have hw-assisted bmove */
				      FBINFO_HWACCEL_FILLRECT |  /* And fillrect */
				      FBINFO_HWACCEL_IMAGEBLIT | /* And imageblit */
				      FBINFO_HWACCEL_XPAN |      /* And we support both horizontal */
				      FBINFO_HWACCEL_YPAN |      /* And vertical panning */
				      FBINFO_READS_FAST;
	minfo->video.len_usable &= PAGE_MASK;
	fb_alloc_cmap(&minfo->fbcon.cmap, 256, 1);

#ifndef MODULE
	/* mode database is marked __init!!! */
	if (!hotplug) {
		fb_find_mode(&vesafb_defined, &minfo->fbcon, videomode[0] ? videomode : NULL,
			NULL, 0, &defaultmode, vesafb_defined.bits_per_pixel);
	}
#endif /* !MODULE */

	/* mode modifiers */
	if (hslen)
		vesafb_defined.hsync_len = hslen;
	if (vslen)
		vesafb_defined.vsync_len = vslen;
	if (left != ~0)
		vesafb_defined.left_margin = left;
	if (right != ~0)
		vesafb_defined.right_margin = right;
	if (upper != ~0)
		vesafb_defined.upper_margin = upper;
	if (lower != ~0)
		vesafb_defined.lower_margin = lower;
	if (xres)
		vesafb_defined.xres = xres;
	if (yres)
		vesafb_defined.yres = yres;
	if (sync != -1)
		vesafb_defined.sync = sync;
	else if (vesafb_defined.sync == ~0) {
		vesafb_defined.sync = 0;
		if (yres < 400)
			vesafb_defined.sync |= FB_SYNC_HOR_HIGH_ACT;
		else if (yres < 480)
			vesafb_defined.sync |= FB_SYNC_VERT_HIGH_ACT;
	}

	/* fv, fh, maxclk limits was specified */
	{
		unsigned int tmp;

		if (fv) {
			tmp = fv * (vesafb_defined.upper_margin + vesafb_defined.yres
				  + vesafb_defined.lower_margin + vesafb_defined.vsync_len);
			if ((tmp < fh) || (fh == 0)) fh = tmp;
		}
		if (fh) {
			tmp = fh * (vesafb_defined.left_margin + vesafb_defined.xres
				  + vesafb_defined.right_margin + vesafb_defined.hsync_len);
			if ((tmp < maxclk) || (maxclk == 0)) maxclk = tmp;
		}
		tmp = (maxclk + 499) / 500;
		if (tmp) {
			tmp = (2000000000 + tmp) / tmp;
			if (tmp > pixclock) pixclock = tmp;
		}
	}
	if (pixclock) {
		if (pixclock < 2000)		/* > 500MHz */
			pixclock = 4000;	/* 250MHz */
		if (pixclock > 1000000)
			pixclock = 1000000;	/* 1MHz */
		vesafb_defined.pixclock = pixclock;
	}

	/* FIXME: Where to move this?! */
#if defined(CONFIG_PPC_PMAC)
#ifndef MODULE
	if (machine_is(powermac)) {
		struct fb_var_screeninfo var;

		if (default_vmode <= 0 || default_vmode > VMODE_MAX)
			default_vmode = VMODE_640_480_60;
#if defined(CONFIG_PPC32)
		if (IS_REACHABLE(CONFIG_NVRAM) && default_cmode == CMODE_NVRAM)
			default_cmode = nvram_read_byte(NV_CMODE);
#endif
		if (default_cmode < CMODE_8 || default_cmode > CMODE_32)
			default_cmode = CMODE_8;
		if (!mac_vmode_to_var(default_vmode, default_cmode, &var)) {
			var.accel_flags = vesafb_defined.accel_flags;
			var.xoffset = var.yoffset = 0;
			/* Note: mac_vmode_to_var() does not set all parameters */
			vesafb_defined = var;
		}
	}
#endif /* !MODULE */
#endif /* CONFIG_PPC_PMAC */
	vesafb_defined.xres_virtual = vesafb_defined.xres;
	if (nopan) {
		vesafb_defined.yres_virtual = vesafb_defined.yres;
	} else {
		vesafb_defined.yres_virtual = 65536; /* large enough to be INF, but small enough
							to yres_virtual * xres_virtual < 2^32 */
	}
	matroxfb_init_fix(minfo);
	minfo->fbcon.screen_base = vaddr_va(minfo->video.vbase);
	/* Normalize values (namely yres_virtual) */
	matroxfb_check_var(&vesafb_defined, &minfo->fbcon);
	/* And put it into "current" var. Do NOT program hardware yet, or we'll not take over
	 * vgacon correctly. fbcon_startup will call fb_set_par for us, WITHOUT check_var,
	 * and unfortunately it will do it BEFORE vgacon contents is saved, so it won't work
	 * anyway. But we at least tried... */
	minfo->fbcon.var = vesafb_defined;
	err = -EINVAL;

	printk(KERN_INFO "matroxfb: %dx%dx%dbpp (virtual: %dx%d)\n",
		vesafb_defined.xres, vesafb_defined.yres, vesafb_defined.bits_per_pixel,
		vesafb_defined.xres_virtual, vesafb_defined.yres_virtual);
	printk(KERN_INFO "matroxfb: framebuffer at 0x%lX, mapped to 0x%p, size %d\n",
		minfo->video.base, vaddr_va(minfo->video.vbase), minfo->video.len);

/* We do not have to set currcon to 0... register_framebuffer do it for us on first console
 * and we do not want currcon == 0 for subsequent framebuffers */

	minfo->fbcon.device = &minfo->pcidev->dev;
	if (register_framebuffer(&minfo->fbcon) < 0) {
		goto failVideoIO;
	}
	fb_info(&minfo->fbcon, "%s frame buffer device\n", minfo->fbcon.fix.id);

	/* there is no console on this fb... but we have to initialize hardware
	 * until someone tells me what is proper thing to do */
	if (!minfo->initialized) {
		fb_info(&minfo->fbcon, "initializing hardware\n");
		/* We have to use FB_ACTIVATE_FORCE, as we had to put vesafb_defined to the fbcon.var
		 * already before, so register_framebuffer works correctly. */
		vesafb_defined.activate |= FB_ACTIVATE_FORCE;
		fb_set_var(&minfo->fbcon, &vesafb_defined);
	}

	return 0;
failVideoIO:;
	matroxfb_g450_shutdown(minfo);
	iounmap(minfo->video.vbase.vaddr);
failCtrlIO:;
	iounmap(minfo->mmio.vbase.vaddr);
failVideoMR:;
	release_mem_region(video_base_phys, minfo->video.len_maximum);
failCtrlMR:;
	release_mem_region(ctrlptr_phys, 16384);
fail:;
	return err;
}