pmc551.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:29k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * $Id: pmc551.c,v 1.20 2002/03/05 13:47:08 dwmw2 Exp $
  3.  *
  4.  * PMC551 PCI Mezzanine Ram Device
  5.  *
  6.  * Author:
  7.  *       Mark Ferrell <mferrell@mvista.com>
  8.  *       Copyright 1999,2000 Nortel Networks
  9.  *
  10.  * License:
  11.  *  As part of this driver was derived from the slram.c driver it
  12.  *  falls under the same license, which is GNU General Public
  13.  *  License v2
  14.  *
  15.  * Description:
  16.  *  This driver is intended to support the PMC551 PCI Ram device
  17.  *  from Ramix Inc.  The PMC551 is a PMC Mezzanine module for
  18.  *  cPCI embedded systems.  The device contains a single SROM
  19.  *  that initially programs the V370PDC chipset onboard the
  20.  *  device, and various banks of DRAM/SDRAM onboard.  This driver
  21.  *  implements this PCI Ram device as an MTD (Memory Technology
  22.  *  Device) so that it can be used to hold a file system, or for
  23.  *  added swap space in embedded systems.  Since the memory on
  24.  *  this board isn't as fast as main memory we do not try to hook
  25.  *  it into main memory as that would simply reduce performance
  26.  *  on the system.  Using it as a block device allows us to use
  27.  *  it as high speed swap or for a high speed disk device of some
  28.  *  sort.  Which becomes very useful on diskless systems in the
  29.  *  embedded market I might add.
  30.  *  
  31.  * Notes:
  32.  *  Due to what I assume is more buggy SROM, the 64M PMC551 I
  33.  *  have available claims that all 4 of it's DRAM banks have 64M
  34.  *  of ram configured (making a grand total of 256M onboard).
  35.  *  This is slightly annoying since the BAR0 size reflects the
  36.  *  aperture size, not the dram size, and the V370PDC supplies no
  37.  *  other method for memory size discovery.  This problem is
  38.  *  mostly only relevant when compiled as a module, as the
  39.  *  unloading of the module with an aperture size smaller then
  40.  *  the ram will cause the driver to detect the onboard memory
  41.  *  size to be equal to the aperture size when the module is
  42.  *  reloaded.  Soooo, to help, the module supports an msize
  43.  *  option to allow the specification of the onboard memory, and
  44.  *  an asize option, to allow the specification of the aperture
  45.  *  size.  The aperture must be equal to or less then the memory
  46.  *  size, the driver will correct this if you screw it up.  This
  47.  *  problem is not relevant for compiled in drivers as compiled
  48.  *  in drivers only init once.
  49.  *
  50.  * Credits:
  51.  *       Saeed Karamooz <saeed@ramix.com> of Ramix INC. for the
  52.  *       initial example code of how to initialize this device and for
  53.  *       help with questions I had concerning operation of the device.
  54.  *
  55.  *       Most of the MTD code for this driver was originally written
  56.  *       for the slram.o module in the MTD drivers package which
  57.  *       allows the mapping of system memory into an MTD device.
  58.  *       Since the PMC551 memory module is accessed in the same
  59.  *       fashion as system memory, the slram.c code became a very nice
  60.  *       fit to the needs of this driver.  All we added was PCI
  61.  *       detection/initialization to the driver and automatically figure
  62.  *       out the size via the PCI detection.o, later changes by Corey
  63.  *       Minyard set up the card to utilize a 1M sliding apature.
  64.  *
  65.  *  Corey Minyard <minyard@nortelnetworks.com>
  66.  *       * Modified driver to utilize a sliding aperture instead of 
  67.  *         mapping all memory into kernel space which turned out to
  68.  *         be very wasteful.
  69.  *       * Located a bug in the SROM's initialization sequence that 
  70.  *         made the memory unusable, added a fix to code to touch up
  71.  *         the DRAM some.
  72.  *
  73.  * Bugs/FIXME's:
  74.  *       * MUST fix the init function to not spin on a register
  75.  *       waiting for it to set .. this does not safely handle busted
  76.  *       devices that never reset the register correctly which will
  77.  *       cause the system to hang w/ a reboot being the only chance at
  78.  *       recover. [sort of fixed, could be better]
  79.  *       * Add I2C handling of the SROM so we can read the SROM's information
  80.  *       about the aperture size.  This should always accurately reflect the
  81.  *       onboard memory size.
  82.  *       * Comb the init routine.  It's still a bit cludgy on a few things.
  83.  */
  84. #include <linux/config.h>
  85. #include <linux/kernel.h>
  86. #include <linux/module.h>
  87. #include <asm/uaccess.h>
  88. #include <linux/types.h>
  89. #include <linux/sched.h>
  90. #include <linux/init.h>
  91. #include <linux/ptrace.h>
  92. #include <linux/slab.h>
  93. #include <linux/string.h>
  94. #include <linux/timer.h>
  95. #include <linux/major.h>
  96. #include <linux/fs.h>
  97. #include <linux/ioctl.h>
  98. #include <asm/io.h>
  99. #include <asm/system.h>
  100. #include <asm/segment.h>
  101. #include <stdarg.h>
  102. #include <linux/pci.h>
  103. #ifndef CONFIG_PCI
  104. #error Enable PCI in your kernel config
  105. #endif
  106. #include <linux/mtd/mtd.h>
  107. #include <linux/mtd/pmc551.h>
  108. #include <linux/mtd/compatmac.h>
  109. #if LINUX_VERSION_CODE > 0x20300
  110. #define PCI_BASE_ADDRESS(dev) (dev->resource[0].start)
  111. #else
  112. #define PCI_BASE_ADDRESS(dev) (dev->base_address[0])
  113. #endif
  114. static struct mtd_info *pmc551list;
  115. static int pmc551_erase (struct mtd_info *mtd, struct erase_info *instr)
  116. {
  117.         struct mypriv *priv = (struct mypriv *)mtd->priv;
  118.         u32 soff_hi, soff_lo; /* start address offset hi/lo */
  119.         u32 eoff_hi, eoff_lo; /* end address offset hi/lo */
  120.         unsigned long end;
  121. u_char *ptr;
  122. size_t retlen;
  123. #ifdef CONFIG_MTD_PMC551_DEBUG
  124. printk(KERN_DEBUG "pmc551_erase(pos:%ld, len:%ld)n", (long)instr->addr, (long)instr->len);
  125. #endif
  126.         end = instr->addr + instr->len - 1;
  127.         /* Is it past the end? */
  128.         if ( end > mtd->size ) {
  129. #ifdef CONFIG_MTD_PMC551_DEBUG
  130. printk(KERN_DEBUG "pmc551_erase() out of bounds (%ld > %ld)n", (long)end, (long)mtd->size);
  131. #endif
  132.                 return -EINVAL;
  133.         }
  134.         eoff_hi = end & ~(priv->asize - 1);
  135.         soff_hi = instr->addr & ~(priv->asize - 1);
  136.         eoff_lo = end & (priv->asize - 1);
  137.         soff_lo = instr->addr & (priv->asize - 1);
  138. pmc551_point (mtd, instr->addr, instr->len, &retlen, &ptr);
  139.         if ( soff_hi == eoff_hi || mtd->size == priv->asize) {
  140.                 /* The whole thing fits within one access, so just one shot
  141.                    will do it. */
  142.                 memset(ptr, 0xff, instr->len);
  143.         } else {
  144.                 /* We have to do multiple writes to get all the data
  145.                    written. */
  146.                 while (soff_hi != eoff_hi) {
  147. #ifdef CONFIG_MTD_PMC551_DEBUG
  148. printk( KERN_DEBUG "pmc551_erase() soff_hi: %ld, eoff_hi: %ldn", (long)soff_hi, (long)eoff_hi);
  149. #endif
  150.                         memset(ptr, 0xff, priv->asize);
  151.                         if (soff_hi + priv->asize >= mtd->size) {
  152.                                 goto out;
  153.                         }
  154.                         soff_hi += priv->asize;
  155. pmc551_point (mtd,(priv->base_map0|soff_hi),
  156.       priv->asize, &retlen, &ptr);
  157.                 }
  158.                 memset (ptr, 0xff, eoff_lo);
  159.         }
  160. out:
  161. instr->state = MTD_ERASE_DONE;
  162. #ifdef CONFIG_MTD_PMC551_DEBUG
  163. printk(KERN_DEBUG "pmc551_erase() donen");
  164. #endif
  165.         if (instr->callback) {
  166.                 (*(instr->callback))(instr);
  167. }
  168.         return 0;
  169. }
  170. static int pmc551_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf)
  171. {
  172.         struct mypriv *priv = (struct mypriv *)mtd->priv;
  173.         u32 soff_hi;
  174.         u32 soff_lo;
  175. #ifdef CONFIG_MTD_PMC551_DEBUG
  176. printk(KERN_DEBUG "pmc551_point(%ld, %ld)n", (long)from, (long)len);
  177. #endif
  178. if (from + len > mtd->size) {
  179. #ifdef CONFIG_MTD_PMC551_DEBUG
  180. printk(KERN_DEBUG "pmc551_point() out of bounds (%ld > %ld)n", (long)from+len, (long)mtd->size);
  181. #endif
  182. return -EINVAL;
  183. }
  184.         soff_hi = from & ~(priv->asize - 1);
  185.         soff_lo = from & (priv->asize - 1);
  186. /* Cheap hack optimization */
  187. if( priv->curr_map0 != from ) {
  188.          pci_write_config_dword ( priv->dev, PMC551_PCI_MEM_MAP0,
  189.                                   (priv->base_map0 | soff_hi) );
  190. priv->curr_map0 = soff_hi;
  191. }
  192. *mtdbuf = priv->start + soff_lo;
  193. *retlen = len;
  194. return 0;
  195. }
  196. static void pmc551_unpoint (struct mtd_info *mtd, u_char *addr)
  197. {
  198. #ifdef CONFIG_MTD_PMC551_DEBUG
  199. printk(KERN_DEBUG "pmc551_unpoint()n");
  200. #endif
  201. }
  202. static int pmc551_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
  203. {
  204.         struct mypriv *priv = (struct mypriv *)mtd->priv;
  205.         u32 soff_hi, soff_lo; /* start address offset hi/lo */
  206.         u32 eoff_hi, eoff_lo; /* end address offset hi/lo */
  207.         unsigned long end;
  208. u_char *ptr;
  209.         u_char *copyto = buf;
  210. #ifdef CONFIG_MTD_PMC551_DEBUG
  211. printk(KERN_DEBUG "pmc551_read(pos:%ld, len:%ld) asize: %ldn", (long)from, (long)len, (long)priv->asize);
  212. #endif
  213.         end = from + len - 1;
  214.         /* Is it past the end? */
  215.         if (end > mtd->size) {
  216. #ifdef CONFIG_MTD_PMC551_DEBUG
  217. printk(KERN_DEBUG "pmc551_read() out of bounds (%ld > %ld)n", (long) end, (long)mtd->size);
  218. #endif
  219.                 return -EINVAL;
  220.         }
  221.         soff_hi = from & ~(priv->asize - 1);
  222.         eoff_hi = end & ~(priv->asize - 1);
  223.         soff_lo = from & (priv->asize - 1);
  224.         eoff_lo = end & (priv->asize - 1);
  225. pmc551_point (mtd, from, len, retlen, &ptr);
  226.         if (soff_hi == eoff_hi) {
  227.                 /* The whole thing fits within one access, so just one shot
  228.                    will do it. */
  229.                 memcpy(copyto, ptr, len);
  230.                 copyto += len;
  231.         } else {
  232.                 /* We have to do multiple writes to get all the data
  233.                    written. */
  234.                 while (soff_hi != eoff_hi) {
  235. #ifdef CONFIG_MTD_PMC551_DEBUG
  236. printk( KERN_DEBUG "pmc551_read() soff_hi: %ld, eoff_hi: %ldn", (long)soff_hi, (long)eoff_hi);
  237. #endif
  238.                         memcpy(copyto, ptr, priv->asize);
  239.                         copyto += priv->asize;
  240.                         if (soff_hi + priv->asize >= mtd->size) {
  241.                                 goto out;
  242.                         }
  243.                         soff_hi += priv->asize;
  244. pmc551_point (mtd, soff_hi, priv->asize, retlen, &ptr);
  245.                 }
  246.                 memcpy(copyto, ptr, eoff_lo);
  247.                 copyto += eoff_lo;
  248.         }
  249. out:
  250. #ifdef CONFIG_MTD_PMC551_DEBUG
  251. printk(KERN_DEBUG "pmc551_read() donen");
  252. #endif
  253.         *retlen = copyto - buf;
  254.         return 0;
  255. }
  256. static int pmc551_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
  257. {
  258.         struct mypriv *priv = (struct mypriv *)mtd->priv;
  259.         u32 soff_hi, soff_lo; /* start address offset hi/lo */
  260.         u32 eoff_hi, eoff_lo; /* end address offset hi/lo */
  261.         unsigned long end;
  262. u_char *ptr;
  263.         const u_char *copyfrom = buf;
  264. #ifdef CONFIG_MTD_PMC551_DEBUG
  265. printk(KERN_DEBUG "pmc551_write(pos:%ld, len:%ld) asize:%ldn", (long)to, (long)len, (long)priv->asize);
  266. #endif
  267.         end = to + len - 1;
  268.         /* Is it past the end?  or did the u32 wrap? */
  269.         if (end > mtd->size ) {
  270. #ifdef CONFIG_MTD_PMC551_DEBUG
  271. printk(KERN_DEBUG "pmc551_write() out of bounds (end: %ld, size: %ld, to: %ld)n", (long) end, (long)mtd->size, (long)to);
  272. #endif
  273.                 return -EINVAL;
  274.         }
  275.         soff_hi = to & ~(priv->asize - 1);
  276.         eoff_hi = end & ~(priv->asize - 1);
  277.         soff_lo = to & (priv->asize - 1);
  278.         eoff_lo = end & (priv->asize - 1);
  279. pmc551_point (mtd, to, len, retlen, &ptr);
  280.         if (soff_hi == eoff_hi) {
  281.                 /* The whole thing fits within one access, so just one shot
  282.                    will do it. */
  283.                 memcpy(ptr, copyfrom, len);
  284.                 copyfrom += len;
  285.         } else {
  286.                 /* We have to do multiple writes to get all the data
  287.                    written. */
  288.                 while (soff_hi != eoff_hi) {
  289. #ifdef CONFIG_MTD_PMC551_DEBUG
  290. printk( KERN_DEBUG "pmc551_write() soff_hi: %ld, eoff_hi: %ldn", (long)soff_hi, (long)eoff_hi);
  291. #endif
  292.                  memcpy(ptr, copyfrom, priv->asize);
  293.                  copyfrom += priv->asize;
  294.                         if (soff_hi >= mtd->size) {
  295.                                 goto out;
  296.                         }
  297.                         soff_hi += priv->asize;
  298. pmc551_point (mtd, soff_hi, priv->asize, retlen, &ptr);
  299.                 }
  300.                 memcpy(ptr, copyfrom, eoff_lo);
  301.                 copyfrom += eoff_lo;
  302.         }
  303. out:
  304. #ifdef CONFIG_MTD_PMC551_DEBUG
  305. printk(KERN_DEBUG "pmc551_write() donen");
  306. #endif
  307.         *retlen = copyfrom - buf;
  308.         return 0;
  309. }
  310. /*
  311.  * Fixup routines for the V370PDC
  312.  * PCI device ID 0x020011b0
  313.  *
  314.  * This function basicly kick starts the DRAM oboard the card and gets it
  315.  * ready to be used.  Before this is done the device reads VERY erratic, so
  316.  * much that it can crash the Linux 2.2.x series kernels when a user cat's
  317.  * /proc/pci .. though that is mainly a kernel bug in handling the PCI DEVSEL
  318.  * register.  FIXME: stop spinning on registers .. must implement a timeout
  319.  * mechanism
  320.  * returns the size of the memory region found.
  321.  */
  322. static u32 fixup_pmc551 (struct pci_dev *dev)
  323. {
  324. #ifdef CONFIG_MTD_PMC551_BUGFIX
  325.         u32 dram_data;
  326. #endif
  327.         u32 size, dcmd, cfg, dtmp;
  328.         u16 cmd, tmp, i;
  329. u8 bcmd, counter;
  330.         /* Sanity Check */
  331.         if(!dev) {
  332.                 return -ENODEV;
  333.         }
  334. /*
  335.  * Attempt to reset the card
  336.  * FIXME: Stop Spinning registers
  337.  */
  338. counter=0;
  339. /* unlock registers */
  340. pci_write_config_byte(dev, PMC551_SYS_CTRL_REG, 0xA5 );
  341. /* read in old data */
  342. pci_read_config_byte(dev, PMC551_SYS_CTRL_REG, &bcmd );
  343. /* bang the reset line up and down for a few */
  344. for(i=0;i<10;i++) {
  345. counter=0;
  346. bcmd &= ~0x80;
  347. while(counter++ < 100) {
  348. pci_write_config_byte(dev, PMC551_SYS_CTRL_REG, bcmd);
  349. }
  350. counter=0;
  351. bcmd |= 0x80;
  352. while(counter++ < 100) {
  353. pci_write_config_byte(dev, PMC551_SYS_CTRL_REG, bcmd);
  354. }
  355. }
  356. bcmd |= (0x40|0x20);
  357. pci_write_config_byte(dev, PMC551_SYS_CTRL_REG, bcmd);
  358.         /* 
  359.  * Take care and turn off the memory on the device while we
  360.  * tweak the configurations
  361.  */
  362.         pci_read_config_word(dev, PCI_COMMAND, &cmd);
  363.         tmp = cmd & ~(PCI_COMMAND_IO|PCI_COMMAND_MEMORY);
  364.         pci_write_config_word(dev, PCI_COMMAND, tmp);
  365. /*
  366.  * Disable existing aperture before probing memory size
  367.  */
  368. pci_read_config_dword(dev, PMC551_PCI_MEM_MAP0, &dcmd);
  369.         dtmp=(dcmd|PMC551_PCI_MEM_MAP_ENABLE|PMC551_PCI_MEM_MAP_REG_EN);
  370. pci_write_config_dword(dev, PMC551_PCI_MEM_MAP0, dtmp);
  371. /*
  372.  * Grab old BAR0 config so that we can figure out memory size
  373.  * This is another bit of kludge going on.  The reason for the
  374.  * redundancy is I am hoping to retain the original configuration
  375.  * previously assigned to the card by the BIOS or some previous 
  376.  * fixup routine in the kernel.  So we read the old config into cfg,
  377.  * then write all 1's to the memory space, read back the result into
  378.  * "size", and then write back all the old config.
  379.  */
  380. pci_read_config_dword( dev, PCI_BASE_ADDRESS_0, &cfg );
  381. #ifndef CONFIG_MTD_PMC551_BUGFIX
  382. pci_write_config_dword( dev, PCI_BASE_ADDRESS_0, ~0 );
  383. pci_read_config_dword( dev, PCI_BASE_ADDRESS_0, &size );
  384. size = (size&PCI_BASE_ADDRESS_MEM_MASK);
  385. size &= ~(size-1);
  386. pci_write_config_dword( dev, PCI_BASE_ADDRESS_0, cfg );
  387. #else
  388.         /*
  389.          * Get the size of the memory by reading all the DRAM size values
  390.          * and adding them up.
  391.          *
  392.          * KLUDGE ALERT: the boards we are using have invalid column and
  393.          * row mux values.  We fix them here, but this will break other
  394.          * memory configurations.
  395.          */
  396.         pci_read_config_dword(dev, PMC551_DRAM_BLK0, &dram_data);
  397.         size = PMC551_DRAM_BLK_GET_SIZE(dram_data);
  398.         dram_data = PMC551_DRAM_BLK_SET_COL_MUX(dram_data, 0x5);
  399.         dram_data = PMC551_DRAM_BLK_SET_ROW_MUX(dram_data, 0x9);
  400.         pci_write_config_dword(dev, PMC551_DRAM_BLK0, dram_data);
  401.         pci_read_config_dword(dev, PMC551_DRAM_BLK1, &dram_data);
  402.         size += PMC551_DRAM_BLK_GET_SIZE(dram_data);
  403.         dram_data = PMC551_DRAM_BLK_SET_COL_MUX(dram_data, 0x5);
  404.         dram_data = PMC551_DRAM_BLK_SET_ROW_MUX(dram_data, 0x9);
  405.         pci_write_config_dword(dev, PMC551_DRAM_BLK1, dram_data);
  406.         pci_read_config_dword(dev, PMC551_DRAM_BLK2, &dram_data);
  407.         size += PMC551_DRAM_BLK_GET_SIZE(dram_data);
  408.         dram_data = PMC551_DRAM_BLK_SET_COL_MUX(dram_data, 0x5);
  409.         dram_data = PMC551_DRAM_BLK_SET_ROW_MUX(dram_data, 0x9);
  410.         pci_write_config_dword(dev, PMC551_DRAM_BLK2, dram_data);
  411.         pci_read_config_dword(dev, PMC551_DRAM_BLK3, &dram_data);
  412.         size += PMC551_DRAM_BLK_GET_SIZE(dram_data);
  413.         dram_data = PMC551_DRAM_BLK_SET_COL_MUX(dram_data, 0x5);
  414.         dram_data = PMC551_DRAM_BLK_SET_ROW_MUX(dram_data, 0x9);
  415.         pci_write_config_dword(dev, PMC551_DRAM_BLK3, dram_data);
  416.         /*
  417.          * Oops .. something went wrong
  418.          */
  419.         if( (size &= PCI_BASE_ADDRESS_MEM_MASK) == 0) {
  420.                 return -ENODEV;
  421.         }
  422. #endif /* CONFIG_MTD_PMC551_BUGFIX */
  423. if ((cfg&PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_MEMORY) {
  424.                 return -ENODEV;
  425. }
  426.         /*
  427.          * Precharge Dram
  428.          */
  429.         pci_write_config_word( dev, PMC551_SDRAM_MA, 0x0400 );
  430.         pci_write_config_word( dev, PMC551_SDRAM_CMD, 0x00bf );
  431.         /*
  432.          * Wait until command has gone through
  433.          * FIXME: register spinning issue
  434.          */
  435.         do { pci_read_config_word( dev, PMC551_SDRAM_CMD, &cmd );
  436. if(counter++ > 100)break;
  437.         } while ( (PCI_COMMAND_IO) & cmd );
  438.         /*
  439.  * Turn on auto refresh 
  440.  * The loop is taken directly from Ramix's example code.  I assume that
  441.  * this must be held high for some duration of time, but I can find no
  442.  * documentation refrencing the reasons why.
  443.          */
  444.         for ( i = 1; i<=8 ; i++) {
  445.                 pci_write_config_word (dev, PMC551_SDRAM_CMD, 0x0df);
  446.                 /*
  447.                  * Make certain command has gone through
  448.                  * FIXME: register spinning issue
  449.                  */
  450. counter=0;
  451.                 do { pci_read_config_word(dev, PMC551_SDRAM_CMD, &cmd);
  452. if(counter++ > 100)break;
  453.                 } while ( (PCI_COMMAND_IO) & cmd );
  454.         }
  455.         pci_write_config_word ( dev, PMC551_SDRAM_MA, 0x0020);
  456.         pci_write_config_word ( dev, PMC551_SDRAM_CMD, 0x0ff);
  457.         /*
  458.          * Wait until command completes
  459.          * FIXME: register spinning issue
  460.          */
  461. counter=0;
  462.         do { pci_read_config_word ( dev, PMC551_SDRAM_CMD, &cmd);
  463. if(counter++ > 100)break;
  464.         } while ( (PCI_COMMAND_IO) & cmd );
  465.         pci_read_config_dword ( dev, PMC551_DRAM_CFG, &dcmd);
  466.         dcmd |= 0x02000000;
  467.         pci_write_config_dword ( dev, PMC551_DRAM_CFG, dcmd);
  468.         /*
  469.          * Check to make certain fast back-to-back, if not
  470.          * then set it so
  471.          */
  472.         pci_read_config_word( dev, PCI_STATUS, &cmd);
  473.         if((cmd&PCI_COMMAND_FAST_BACK) == 0) {
  474.                 cmd |= PCI_COMMAND_FAST_BACK;
  475.                 pci_write_config_word( dev, PCI_STATUS, cmd);
  476.         }
  477.         /*
  478.          * Check to make certain the DEVSEL is set correctly, this device
  479.          * has a tendancy to assert DEVSEL and TRDY when a write is performed
  480.          * to the memory when memory is read-only
  481.          */
  482.         if((cmd&PCI_STATUS_DEVSEL_MASK) != 0x0) {
  483.                 cmd &= ~PCI_STATUS_DEVSEL_MASK;
  484.                 pci_write_config_word( dev, PCI_STATUS, cmd );
  485.         }
  486.         /*
  487.          * Set to be prefetchable and put everything back based on old cfg.
  488.  * it's possible that the reset of the V370PDC nuked the original
  489.  * setup
  490.          */
  491. /*
  492.         cfg |= PCI_BASE_ADDRESS_MEM_PREFETCH;
  493. pci_write_config_dword( dev, PCI_BASE_ADDRESS_0, cfg );
  494. */
  495.         /*
  496.          * Turn PCI memory and I/O bus access back on
  497.          */
  498.         pci_write_config_word( dev, PCI_COMMAND,
  499.                                PCI_COMMAND_MEMORY | PCI_COMMAND_IO );
  500. #ifdef CONFIG_MTD_PMC551_DEBUG
  501.         /*
  502.          * Some screen fun
  503.          */
  504.         printk(KERN_DEBUG "pmc551: %d%c (0x%x) of %sprefetchable memory at 0x%lxn",
  505.        (size<1024)?size:(size<1048576)?size>>10:size>>20,
  506.                (size<1024)?'B':(size<1048576)?'K':'M',
  507.        size, ((dcmd&(0x1<<3)) == 0)?"non-":"",
  508.                PCI_BASE_ADDRESS(dev)&PCI_BASE_ADDRESS_MEM_MASK );
  509.         /*
  510.          * Check to see the state of the memory
  511.          */
  512.         pci_read_config_dword( dev, PMC551_DRAM_BLK0, &dcmd );
  513.         printk(KERN_DEBUG "pmc551: DRAM_BLK0 Flags: %s,%sn"
  514.   "pmc551: DRAM_BLK0 Size: %d at %dn"
  515.   "pmc551: DRAM_BLK0 Row MUX: %d, Col MUX: %dn",
  516.                (((0x1<<1)&dcmd) == 0)?"RW":"RO",
  517.                (((0x1<<0)&dcmd) == 0)?"Off":"On",
  518.        PMC551_DRAM_BLK_GET_SIZE(dcmd),
  519.        ((dcmd>>20)&0x7FF), ((dcmd>>13)&0x7), ((dcmd>>9)&0xF) );
  520.         pci_read_config_dword( dev, PMC551_DRAM_BLK1, &dcmd );
  521.         printk(KERN_DEBUG "pmc551: DRAM_BLK1 Flags: %s,%sn"
  522.   "pmc551: DRAM_BLK1 Size: %d at %dn"
  523.   "pmc551: DRAM_BLK1 Row MUX: %d, Col MUX: %dn",
  524.                (((0x1<<1)&dcmd) == 0)?"RW":"RO",
  525.                (((0x1<<0)&dcmd) == 0)?"Off":"On",
  526.        PMC551_DRAM_BLK_GET_SIZE(dcmd),
  527.        ((dcmd>>20)&0x7FF), ((dcmd>>13)&0x7), ((dcmd>>9)&0xF) );
  528.         pci_read_config_dword( dev, PMC551_DRAM_BLK2, &dcmd );
  529.         printk(KERN_DEBUG "pmc551: DRAM_BLK2 Flags: %s,%sn"
  530.   "pmc551: DRAM_BLK2 Size: %d at %dn"
  531.   "pmc551: DRAM_BLK2 Row MUX: %d, Col MUX: %dn",
  532.                (((0x1<<1)&dcmd) == 0)?"RW":"RO",
  533.                (((0x1<<0)&dcmd) == 0)?"Off":"On",
  534.        PMC551_DRAM_BLK_GET_SIZE(dcmd),
  535.        ((dcmd>>20)&0x7FF), ((dcmd>>13)&0x7), ((dcmd>>9)&0xF) );
  536.         pci_read_config_dword( dev, PMC551_DRAM_BLK3, &dcmd );
  537.         printk(KERN_DEBUG "pmc551: DRAM_BLK3 Flags: %s,%sn"
  538.   "pmc551: DRAM_BLK3 Size: %d at %dn"
  539.   "pmc551: DRAM_BLK3 Row MUX: %d, Col MUX: %dn",
  540.                (((0x1<<1)&dcmd) == 0)?"RW":"RO",
  541.                (((0x1<<0)&dcmd) == 0)?"Off":"On",
  542.        PMC551_DRAM_BLK_GET_SIZE(dcmd),
  543.        ((dcmd>>20)&0x7FF), ((dcmd>>13)&0x7), ((dcmd>>9)&0xF) );
  544.         pci_read_config_word( dev, PCI_COMMAND, &cmd );
  545.         printk( KERN_DEBUG "pmc551: Memory Access %sn",
  546.                 (((0x1<<1)&cmd) == 0)?"off":"on" );
  547.         printk( KERN_DEBUG "pmc551: I/O Access %sn",
  548.                 (((0x1<<0)&cmd) == 0)?"off":"on" );
  549.         pci_read_config_word( dev, PCI_STATUS, &cmd );
  550.         printk( KERN_DEBUG "pmc551: Devsel %sn",
  551.                 ((PCI_STATUS_DEVSEL_MASK&cmd)==0x000)?"Fast":
  552.                 ((PCI_STATUS_DEVSEL_MASK&cmd)==0x200)?"Medium":
  553.                 ((PCI_STATUS_DEVSEL_MASK&cmd)==0x400)?"Slow":"Invalid" );
  554.         printk( KERN_DEBUG "pmc551: %sFast Back-to-Backn",
  555.                 ((PCI_COMMAND_FAST_BACK&cmd) == 0)?"Not ":"" );
  556. pci_read_config_byte(dev, PMC551_SYS_CTRL_REG, &bcmd );
  557. printk( KERN_DEBUG "pmc551: EEPROM is under %s controln"
  558.    "pmc551: System Control Register is %slocked to PCI accessn"
  559.    "pmc551: System Control Register is %slocked to EEPROM accessn", 
  560. (bcmd&0x1)?"software":"hardware",
  561. (bcmd&0x20)?"":"un", (bcmd&0x40)?"":"un");
  562. #endif
  563.         return size;
  564. }
  565. /*
  566.  * Kernel version specific module stuffages
  567.  */
  568. MODULE_LICENSE("GPL");
  569. MODULE_AUTHOR("Mark Ferrell <mferrell@mvista.com>");
  570. MODULE_DESCRIPTION(PMC551_VERSION);
  571. MODULE_PARM(msize, "i");
  572. MODULE_PARM_DESC(msize, "memory size in Megabytes [1 - 1024]");
  573. MODULE_PARM(asize, "i");
  574. MODULE_PARM_DESC(asize, "aperture size, must be <= memsize [1-1024]");
  575. /*
  576.  * Stuff these outside the ifdef so as to not bust compiled in driver support
  577.  */
  578. static int msize=0;
  579. #if defined(CONFIG_MTD_PMC551_APERTURE_SIZE)
  580. static int asize=CONFIG_MTD_PMC551_APERTURE_SIZE
  581. #else
  582. static int asize=0;
  583. #endif
  584. /*
  585.  * PMC551 Card Initialization
  586.  */
  587. int __init init_pmc551(void)
  588. {
  589.         struct pci_dev *PCI_Device = NULL;
  590.         struct mypriv *priv;
  591.         int count, found=0;
  592.         struct mtd_info *mtd;
  593.         u32 length = 0;
  594. if(msize) {
  595. msize = (1 << (ffs(msize) - 1))<<20;
  596. if (msize > (1<<30)) {
  597. printk(KERN_NOTICE "pmc551: Invalid memory size [%d]n", msize);
  598. return -EINVAL;
  599. }
  600. }
  601. if(asize) {
  602. asize = (1 << (ffs(asize) - 1))<<20;
  603. if (asize > (1<<30) ) {
  604. printk(KERN_NOTICE "pmc551: Invalid aperture size [%d]n", asize);
  605. return -EINVAL;
  606. }
  607. }
  608.         printk(KERN_INFO PMC551_VERSION);
  609.         if(!pci_present()) {
  610.                 printk(KERN_NOTICE "pmc551: PCI not enabled.n");
  611.                 return -ENODEV;
  612.         }
  613.         /*
  614.          * PCU-bus chipset probe.
  615.          */
  616.         for( count = 0; count < MAX_MTD_DEVICES; count++ ) {
  617.                 if ((PCI_Device = pci_find_device(PCI_VENDOR_ID_V3_SEMI,
  618.                                                   PCI_DEVICE_ID_V3_SEMI_V370PDC,
  619.   PCI_Device ) ) == NULL) {
  620.                         break;
  621.                 }
  622.                 printk(KERN_NOTICE "pmc551: Found PCI V370PDC at 0x%lXn",
  623.     PCI_BASE_ADDRESS(PCI_Device));
  624.                 /*
  625.                  * The PMC551 device acts VERY weird if you don't init it
  626.                  * first.  i.e. it will not correctly report devsel.  If for
  627.                  * some reason the sdram is in a wrote-protected state the
  628.                  * device will DEVSEL when it is written to causing problems
  629.                  * with the oldproc.c driver in
  630.                  * some kernels (2.2.*)
  631.                  */
  632.                 if((length = fixup_pmc551(PCI_Device)) <= 0) {
  633.                         printk(KERN_NOTICE "pmc551: Cannot init SDRAMn");
  634.                         break;
  635.                 }
  636. /*
  637.  * This is needed until the driver is capable of reading the
  638.  * onboard I2C SROM to discover the "real" memory size.
  639.  */
  640. if(msize) {
  641. length = msize;
  642. printk(KERN_NOTICE "pmc551: Using specified memory size 0x%xn", length);
  643. } else {
  644. msize = length;
  645. }
  646.                 mtd = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
  647.                 if (!mtd) {
  648.                         printk(KERN_NOTICE "pmc551: Cannot allocate new MTD device.n");
  649.                         break;
  650.                 }
  651.                 memset(mtd, 0, sizeof(struct mtd_info));
  652.                 priv = kmalloc (sizeof(struct mypriv), GFP_KERNEL);
  653.                 if (!priv) {
  654.                         printk(KERN_NOTICE "pmc551: Cannot allocate new MTD device.n");
  655.                         kfree(mtd);
  656.                         break;
  657.                 }
  658.                 memset(priv, 0, sizeof(*priv));
  659.                 mtd->priv = priv;
  660.                 priv->dev = PCI_Device;
  661. if(asize > length) {
  662. printk(KERN_NOTICE "pmc551: reducing aperture size to fit %dMn",length>>20);
  663. priv->asize = asize = length;
  664. } else if (asize == 0 || asize == length) {
  665. printk(KERN_NOTICE "pmc551: Using existing aperture size %dMn", length>>20);
  666. priv->asize = asize = length;
  667. } else {
  668. printk(KERN_NOTICE "pmc551: Using specified aperture size %dMn", asize>>20);
  669. priv->asize = asize;
  670. }
  671.                 priv->start = ioremap((PCI_BASE_ADDRESS(PCI_Device)
  672.                                        & PCI_BASE_ADDRESS_MEM_MASK),
  673.                                       priv->asize);
  674. if (!priv->start) {
  675. printk(KERN_NOTICE "pmc551: Unable to map IO spacen");
  676.                         kfree(mtd->priv);
  677.                         kfree(mtd);
  678. break;
  679. }
  680. #ifdef CONFIG_MTD_PMC551_DEBUG
  681. printk( KERN_DEBUG "pmc551: setting aperture to %dn",
  682. ffs(priv->asize>>20)-1);
  683. #endif
  684.                 priv->base_map0 = ( PMC551_PCI_MEM_MAP_REG_EN
  685.   | PMC551_PCI_MEM_MAP_ENABLE
  686.   | (ffs(priv->asize>>20)-1)<<4 );
  687.                 priv->curr_map0 = priv->base_map0;
  688.                 pci_write_config_dword ( priv->dev, PMC551_PCI_MEM_MAP0,
  689.                                          priv->curr_map0 );
  690. #ifdef CONFIG_MTD_PMC551_DEBUG
  691. printk( KERN_DEBUG "pmc551: aperture set to %dn", 
  692. (priv->base_map0 & 0xF0)>>4 );
  693. #endif
  694.                 mtd->size  = msize;
  695.                 mtd->flags  = MTD_CAP_RAM;
  696.                 mtd->erase  = pmc551_erase;
  697.                 mtd->read  = pmc551_read;
  698.                 mtd->write  = pmc551_write;
  699.                 mtd->point  = pmc551_point;
  700.                 mtd->unpoint  = pmc551_unpoint;
  701.                 mtd->module  = THIS_MODULE;
  702.                 mtd->type  = MTD_RAM;
  703.                 mtd->name  = "PMC551 RAM board";
  704.                 mtd->erasesize  = 0x10000;
  705.                 if (add_mtd_device(mtd)) {
  706.                         printk(KERN_NOTICE "pmc551: Failed to register new devicen");
  707. iounmap(priv->start);
  708.                         kfree(mtd->priv);
  709.                         kfree(mtd);
  710.                         break;
  711.                 }
  712.                 printk(KERN_NOTICE "Registered pmc551 memory device.n");
  713.                 printk(KERN_NOTICE "Mapped %dM of memory from 0x%p to 0x%pn",
  714.                        priv->asize>>20,
  715.                        priv->start,
  716.                        priv->start + priv->asize);
  717.                 printk(KERN_NOTICE "Total memory is %d%cn",
  718.         (length<1024)?length:
  719. (length<1048576)?length>>10:length>>20,
  720.                 (length<1024)?'B':(length<1048576)?'K':'M');
  721. priv->nextpmc551 = pmc551list;
  722. pmc551list = mtd;
  723. found++;
  724.         }
  725.         if( !pmc551list ) {
  726.                 printk(KERN_NOTICE "pmc551: not detectedn");
  727.                 return -ENODEV;
  728.         } else {
  729. printk(KERN_NOTICE "pmc551: %d pmc551 devices loadedn", found);
  730.                 return 0;
  731. }
  732. }
  733. /*
  734.  * PMC551 Card Cleanup
  735.  */
  736. static void __exit cleanup_pmc551(void)
  737. {
  738.         int found=0;
  739.         struct mtd_info *mtd;
  740. struct mypriv *priv;
  741. while((mtd=pmc551list)) {
  742. priv = (struct mypriv *)mtd->priv;
  743. pmc551list = priv->nextpmc551;
  744. if(priv->start) {
  745. printk (KERN_DEBUG "pmc551: unmapping %dM starting at 0x%pn",
  746. priv->asize>>20, priv->start);
  747. iounmap (priv->start);
  748. }
  749. kfree (mtd->priv);
  750. del_mtd_device (mtd);
  751. kfree (mtd);
  752. found++;
  753. }
  754. printk(KERN_NOTICE "pmc551: %d pmc551 devices unloadedn", found);
  755. }
  756. module_init(init_pmc551);
  757. module_exit(cleanup_pmc551);