📄 pmc551.c
字号:
start_addr_lowbits = to & PMC551_ADDR_LOW_MASK; end_addr_lowbits = end & PMC551_ADDR_LOW_MASK; /* Only rewrite the first value if it doesn't match our current values. Most operations are on the same page as the previous value, so this is a pretty good optimization. */ if (priv->curr_mem_map0_val != (priv->mem_map0_base_val | start_addr_highbits)) { priv->curr_mem_map0_val = (priv->mem_map0_base_val | start_addr_highbits); pci_write_config_dword ( priv->dev, PMC551_PCI_MEM_MAP0, priv->curr_mem_map0_val); } if (start_addr_highbits == end_addr_highbits) { /* The whole thing fits within one access, so just one shot will do it. */ memcpy(priv->start + start_addr_lowbits, copyfrom, len); copyfrom += len; } else { /* We have to do multiple writes to get all the data written. */ memcpy(priv->start + start_addr_lowbits, copyfrom, priv->aperture_size - start_addr_lowbits); copyfrom += priv->aperture_size - start_addr_lowbits; start_addr_highbits += priv->aperture_size; while (start_addr_highbits != end_addr_highbits) { pci_write_config_dword ( priv->dev, PMC551_PCI_MEM_MAP0, (priv->mem_map0_base_val | start_addr_highbits)); memcpy(priv->start, copyfrom, priv->aperture_size); copyfrom += priv->aperture_size; start_addr_highbits += priv->aperture_size; if (start_addr_highbits >= mtd->size) { /* Make sure we have the right value here. */ priv->curr_mem_map0_val = (priv->mem_map0_base_val | start_addr_highbits); goto out; } } priv->curr_mem_map0_val = (priv->mem_map0_base_val | start_addr_highbits); pci_write_config_dword ( priv->dev, PMC551_PCI_MEM_MAP0, priv->curr_mem_map0_val); memcpy(priv->start, copyfrom, end_addr_lowbits); copyfrom += end_addr_lowbits; }out: *retlen = copyfrom - buf; return 0;}/* * Fixup routines for the V370PDC * PCI device ID 0x020011b0 * * This function basicly kick starts the DRAM oboard the card and gets it * ready to be used. Before this is done the device reads VERY erratic, so * much that it can crash the Linux 2.2.x series kernels when a user cat's * /proc/pci .. though that is mainly a kernel bug in handling the PCI DEVSEL * register. FIXME: stop spinning on registers .. must implement a timeout * mechanism * returns the size of the memory region found. */static u32 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 ); pci_write_config_dword( dev, PCI_BASE_ADDRESS_0, cfg ); size=~(size&PCI_BASE_ADDRESS_MEM_MASK)+1;#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 untill 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 tendancy 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 * settup */ 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%c (0x%x) of %sprefetchable memory at 0x%lx\n", (size<1024)?size:(size<1048576)?size/1024:size/1024/1024, (size<1024)?'B':(size<1048576)?'K':'M', size, ((dcmd&(0x1<<3)) == 0)?"non-":"", PCI_BASE_ADDRESS(dev)&PCI_BASE_ADDRESS_MEM_MASK ); /* * 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"
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -