static int __init fixup_pmc551()

in devices/pmc551.c [347:627]


static int __init fixup_pmc551(struct pci_dev *dev)
{
#ifdef CONFIG_MTD_PMC551_BUGFIX
	u32 dram_data;
#endif
	u32 size, dcmd, cfg, dtmp;
	u16 cmd, tmp, i;
	u8 bcmd, counter;

	/* Sanity Check */
	if (!dev) {
		return -ENODEV;
	}

	/*
	 * Attempt to reset the card
	 * FIXME: Stop Spinning registers
	 */
	counter = 0;
	/* unlock registers */
	pci_write_config_byte(dev, PMC551_SYS_CTRL_REG, 0xA5);
	/* read in old data */
	pci_read_config_byte(dev, PMC551_SYS_CTRL_REG, &bcmd);
	/* bang the reset line up and down for a few */
	for (i = 0; i < 10; i++) {
		counter = 0;
		bcmd &= ~0x80;
		while (counter++ < 100) {
			pci_write_config_byte(dev, PMC551_SYS_CTRL_REG, bcmd);
		}
		counter = 0;
		bcmd |= 0x80;
		while (counter++ < 100) {
			pci_write_config_byte(dev, PMC551_SYS_CTRL_REG, bcmd);
		}
	}
	bcmd |= (0x40 | 0x20);
	pci_write_config_byte(dev, PMC551_SYS_CTRL_REG, bcmd);

	/*
	 * Take care and turn off the memory on the device while we
	 * tweak the configurations
	 */
	pci_read_config_word(dev, PCI_COMMAND, &cmd);
	tmp = cmd & ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
	pci_write_config_word(dev, PCI_COMMAND, tmp);

	/*
	 * Disable existing aperture before probing memory size
	 */
	pci_read_config_dword(dev, PMC551_PCI_MEM_MAP0, &dcmd);
	dtmp = (dcmd | PMC551_PCI_MEM_MAP_ENABLE | PMC551_PCI_MEM_MAP_REG_EN);
	pci_write_config_dword(dev, PMC551_PCI_MEM_MAP0, dtmp);
	/*
	 * Grab old BAR0 config so that we can figure out memory size
	 * This is another bit of kludge going on.  The reason for the
	 * redundancy is I am hoping to retain the original configuration
	 * previously assigned to the card by the BIOS or some previous
	 * fixup routine in the kernel.  So we read the old config into cfg,
	 * then write all 1's to the memory space, read back the result into
	 * "size", and then write back all the old config.
	 */
	pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &cfg);
#ifndef CONFIG_MTD_PMC551_BUGFIX
	pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, ~0);
	pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &size);
	size = (size & PCI_BASE_ADDRESS_MEM_MASK);
	size &= ~(size - 1);
	pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, cfg);
#else
	/*
	 * Get the size of the memory by reading all the DRAM size values
	 * and adding them up.
	 *
	 * KLUDGE ALERT: the boards we are using have invalid column and
	 * row mux values.  We fix them here, but this will break other
	 * memory configurations.
	 */
	pci_read_config_dword(dev, PMC551_DRAM_BLK0, &dram_data);
	size = PMC551_DRAM_BLK_GET_SIZE(dram_data);
	dram_data = PMC551_DRAM_BLK_SET_COL_MUX(dram_data, 0x5);
	dram_data = PMC551_DRAM_BLK_SET_ROW_MUX(dram_data, 0x9);
	pci_write_config_dword(dev, PMC551_DRAM_BLK0, dram_data);

	pci_read_config_dword(dev, PMC551_DRAM_BLK1, &dram_data);
	size += PMC551_DRAM_BLK_GET_SIZE(dram_data);
	dram_data = PMC551_DRAM_BLK_SET_COL_MUX(dram_data, 0x5);
	dram_data = PMC551_DRAM_BLK_SET_ROW_MUX(dram_data, 0x9);
	pci_write_config_dword(dev, PMC551_DRAM_BLK1, dram_data);

	pci_read_config_dword(dev, PMC551_DRAM_BLK2, &dram_data);
	size += PMC551_DRAM_BLK_GET_SIZE(dram_data);
	dram_data = PMC551_DRAM_BLK_SET_COL_MUX(dram_data, 0x5);
	dram_data = PMC551_DRAM_BLK_SET_ROW_MUX(dram_data, 0x9);
	pci_write_config_dword(dev, PMC551_DRAM_BLK2, dram_data);

	pci_read_config_dword(dev, PMC551_DRAM_BLK3, &dram_data);
	size += PMC551_DRAM_BLK_GET_SIZE(dram_data);
	dram_data = PMC551_DRAM_BLK_SET_COL_MUX(dram_data, 0x5);
	dram_data = PMC551_DRAM_BLK_SET_ROW_MUX(dram_data, 0x9);
	pci_write_config_dword(dev, PMC551_DRAM_BLK3, dram_data);

	/*
	 * Oops .. something went wrong
	 */
	if ((size &= PCI_BASE_ADDRESS_MEM_MASK) == 0) {
		return -ENODEV;
	}
#endif				/* CONFIG_MTD_PMC551_BUGFIX */

	if ((cfg & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_MEMORY) {
		return -ENODEV;
	}

	/*
	 * Precharge Dram
	 */
	pci_write_config_word(dev, PMC551_SDRAM_MA, 0x0400);
	pci_write_config_word(dev, PMC551_SDRAM_CMD, 0x00bf);

	/*
	 * Wait until command has gone through
	 * FIXME: register spinning issue
	 */
	do {
		pci_read_config_word(dev, PMC551_SDRAM_CMD, &cmd);
		if (counter++ > 100)
			break;
	} while ((PCI_COMMAND_IO) & cmd);

	/*
	 * Turn on auto refresh
	 * The loop is taken directly from Ramix's example code.  I assume that
	 * this must be held high for some duration of time, but I can find no
	 * documentation refrencing the reasons why.
	 */
	for (i = 1; i <= 8; i++) {
		pci_write_config_word(dev, PMC551_SDRAM_CMD, 0x0df);

		/*
		 * Make certain command has gone through
		 * FIXME: register spinning issue
		 */
		counter = 0;
		do {
			pci_read_config_word(dev, PMC551_SDRAM_CMD, &cmd);
			if (counter++ > 100)
				break;
		} while ((PCI_COMMAND_IO) & cmd);
	}

	pci_write_config_word(dev, PMC551_SDRAM_MA, 0x0020);
	pci_write_config_word(dev, PMC551_SDRAM_CMD, 0x0ff);

	/*
	 * Wait until command completes
	 * FIXME: register spinning issue
	 */
	counter = 0;
	do {
		pci_read_config_word(dev, PMC551_SDRAM_CMD, &cmd);
		if (counter++ > 100)
			break;
	} while ((PCI_COMMAND_IO) & cmd);

	pci_read_config_dword(dev, PMC551_DRAM_CFG, &dcmd);
	dcmd |= 0x02000000;
	pci_write_config_dword(dev, PMC551_DRAM_CFG, dcmd);

	/*
	 * Check to make certain fast back-to-back, if not
	 * then set it so
	 */
	pci_read_config_word(dev, PCI_STATUS, &cmd);
	if ((cmd & PCI_COMMAND_FAST_BACK) == 0) {
		cmd |= PCI_COMMAND_FAST_BACK;
		pci_write_config_word(dev, PCI_STATUS, cmd);
	}

	/*
	 * Check to make certain the DEVSEL is set correctly, this device
	 * has a tendency to assert DEVSEL and TRDY when a write is performed
	 * to the memory when memory is read-only
	 */
	if ((cmd & PCI_STATUS_DEVSEL_MASK) != 0x0) {
		cmd &= ~PCI_STATUS_DEVSEL_MASK;
		pci_write_config_word(dev, PCI_STATUS, cmd);
	}
	/*
	 * Set to be prefetchable and put everything back based on old cfg.
	 * it's possible that the reset of the V370PDC nuked the original
	 * setup
	 */
	/*
	   cfg |= PCI_BASE_ADDRESS_MEM_PREFETCH;
	   pci_write_config_dword( dev, PCI_BASE_ADDRESS_0, cfg );
	 */

	/*
	 * Turn PCI memory and I/O bus access back on
	 */
	pci_write_config_word(dev, PCI_COMMAND,
			      PCI_COMMAND_MEMORY | PCI_COMMAND_IO);
#ifdef CONFIG_MTD_PMC551_DEBUG
	/*
	 * Some screen fun
	 */
	printk(KERN_DEBUG "pmc551: %d%sB (0x%x) of %sprefetchable memory at "
		"0x%llx\n", (size < 1024) ? size : (size < 1048576) ?
		size >> 10 : size >> 20,
		(size < 1024) ? "" : (size < 1048576) ? "Ki" : "Mi", size,
		((dcmd & (0x1 << 3)) == 0) ? "non-" : "",
		(unsigned long long)pci_resource_start(dev, 0));

	/*
	 * Check to see the state of the memory
	 */
	pci_read_config_dword(dev, PMC551_DRAM_BLK0, &dcmd);
	printk(KERN_DEBUG "pmc551: DRAM_BLK0 Flags: %s,%s\n"
		"pmc551: DRAM_BLK0 Size: %d at %d\n"
		"pmc551: DRAM_BLK0 Row MUX: %d, Col MUX: %d\n",
		(((0x1 << 1) & dcmd) == 0) ? "RW" : "RO",
		(((0x1 << 0) & dcmd) == 0) ? "Off" : "On",
		PMC551_DRAM_BLK_GET_SIZE(dcmd),
		((dcmd >> 20) & 0x7FF), ((dcmd >> 13) & 0x7),
		((dcmd >> 9) & 0xF));

	pci_read_config_dword(dev, PMC551_DRAM_BLK1, &dcmd);
	printk(KERN_DEBUG "pmc551: DRAM_BLK1 Flags: %s,%s\n"
		"pmc551: DRAM_BLK1 Size: %d at %d\n"
		"pmc551: DRAM_BLK1 Row MUX: %d, Col MUX: %d\n",
		(((0x1 << 1) & dcmd) == 0) ? "RW" : "RO",
		(((0x1 << 0) & dcmd) == 0) ? "Off" : "On",
		PMC551_DRAM_BLK_GET_SIZE(dcmd),
		((dcmd >> 20) & 0x7FF), ((dcmd >> 13) & 0x7),
		((dcmd >> 9) & 0xF));

	pci_read_config_dword(dev, PMC551_DRAM_BLK2, &dcmd);
	printk(KERN_DEBUG "pmc551: DRAM_BLK2 Flags: %s,%s\n"
		"pmc551: DRAM_BLK2 Size: %d at %d\n"
		"pmc551: DRAM_BLK2 Row MUX: %d, Col MUX: %d\n",
		(((0x1 << 1) & dcmd) == 0) ? "RW" : "RO",
		(((0x1 << 0) & dcmd) == 0) ? "Off" : "On",
		PMC551_DRAM_BLK_GET_SIZE(dcmd),
		((dcmd >> 20) & 0x7FF), ((dcmd >> 13) & 0x7),
		((dcmd >> 9) & 0xF));

	pci_read_config_dword(dev, PMC551_DRAM_BLK3, &dcmd);
	printk(KERN_DEBUG "pmc551: DRAM_BLK3 Flags: %s,%s\n"
		"pmc551: DRAM_BLK3 Size: %d at %d\n"
		"pmc551: DRAM_BLK3 Row MUX: %d, Col MUX: %d\n",
		(((0x1 << 1) & dcmd) == 0) ? "RW" : "RO",
		(((0x1 << 0) & dcmd) == 0) ? "Off" : "On",
		PMC551_DRAM_BLK_GET_SIZE(dcmd),
		((dcmd >> 20) & 0x7FF), ((dcmd >> 13) & 0x7),
		((dcmd >> 9) & 0xF));

	pci_read_config_word(dev, PCI_COMMAND, &cmd);
	printk(KERN_DEBUG "pmc551: Memory Access %s\n",
		(((0x1 << 1) & cmd) == 0) ? "off" : "on");
	printk(KERN_DEBUG "pmc551: I/O Access %s\n",
		(((0x1 << 0) & cmd) == 0) ? "off" : "on");

	pci_read_config_word(dev, PCI_STATUS, &cmd);
	printk(KERN_DEBUG "pmc551: Devsel %s\n",
		((PCI_STATUS_DEVSEL_MASK & cmd) == 0x000) ? "Fast" :
		((PCI_STATUS_DEVSEL_MASK & cmd) == 0x200) ? "Medium" :
		((PCI_STATUS_DEVSEL_MASK & cmd) == 0x400) ? "Slow" : "Invalid");

	printk(KERN_DEBUG "pmc551: %sFast Back-to-Back\n",
		((PCI_COMMAND_FAST_BACK & cmd) == 0) ? "Not " : "");

	pci_read_config_byte(dev, PMC551_SYS_CTRL_REG, &bcmd);
	printk(KERN_DEBUG "pmc551: EEPROM is under %s control\n"
		"pmc551: System Control Register is %slocked to PCI access\n"
		"pmc551: System Control Register is %slocked to EEPROM access\n",
		(bcmd & 0x1) ? "software" : "hardware",
		(bcmd & 0x20) ? "" : "un", (bcmd & 0x40) ? "" : "un");
#endif
	return size;
}